Tutorial: Makefile Projects with Eclipse

The benefit of an IDE like Eclipse is: it makes working with projects very easy, as generates make files and it takes and automatically manages the make file(s). But sometimes this might not be what I want because I need greater flexibility and control, or I want to use the same make files for my continues integration and automated testing system. In that case a hand crafted make file is the way to go.

One thing does not exclude the other: This article explains how to use make files with Eclipse with similar comfort as the managed build system in Eclipse, but with the unlimited power of make files:

Makefile Project with Eclipse

Makefile Project with Eclipse

Outline

Eclipse comes with a built-in build system (managed make): I can configure the compiler linker settings, and Eclipse takes care about the rest. In this tutorial I’ll explain how I can create and use hand crafted make files with Eclipse. The proposed make file and template makes it easy to control the build system with make. The proposed approach requires that every new source file added to the project requires a extension of the make file, but the make file with auto-generate dependency files for all the included header files.

The benefit of using make files are:

  • Easier to store and track in a version control system than the Eclipse .cproject files and settings
  • Complete control of the build and make process
  • Rather trivial to extend with other steps like working with a version control system or an automated test system as part of the build process
  • Can use the same build (make) both inside the IDE and outside (e.g. on an automated build system)
  • and writing make files is fun too 🙂

The make file approach requires understanding the build process, and for this it is helpful to understand what is used with the managed make, so I can use it as a base or inspiration.

Preconditions

To use make files in Eclipse, I need the following:

  • Eclipse IDE. I’m using the NXP MCUXpresso IDE v10.0.2 (Neon based), but any other Eclipse distribution would do it too.
  • Installed GNU toolchain with make utility. Usually this comes with a bundled Eclipse IDE or you can use a DIY toolchain.
  • Compiler and linker settings for your target device. Use the options from an existing example project.
  • Startup and linker files. Here again you can borrow from an existing example project.
  • Application source files. I recommend to start with an ’empty’ main first.

A good way to get the necessary files and options is to look at an existing example project which usually is using ‘manged make’.

💡 I have put the sources of this project on GitHub. Check the link to the GitHub project in the Links section at the end of this article.

Coming from Eclipse Managed Make

With the managed make system, Eclipse detects the files present in the project (e.g. *.c) and generates the make files automatically:

Builder Settings

Builder Settings

This generates make files:

Generated Make Files

Generated Make Files

With a build tool integration, I have a GUI where I can set the options for the tools:

managed build tool settings

managed build tool settings

All this information gets added to the make files, and if I do a build, it calls the make utility (or builder) to build it with all the necessary command lines. I can can see what it does with checking the console view output:

Console View Output

Console View Output

With this, I should have everything to make a make file project.

Creating Make File Project

I’m creating a new make file project in Eclipse with the menu File > New Project:

New Project

New Project

As with many things in Eclipse, there are multiple ways to do things.

If I have existing code I want to add, I can use the ‘Makefile Project with Existing Code’. Then I can give a name and an existing code location (folder). It will then create the project inside that code location folder and add all the source files to the project:

New Make File Project with Existing Code

New Make File Project with Existing Code

The generic way is to generate a C or C++ project:

New C or C++ project

New C or C++ project

Then give the project a name and select an empty make file project with the supported toolchain:

Creating Empty Makefile Project

Creating Empty Makefile Project

Then press ‘Next’ and go through the remaining dialogs depending on the selected toolchain. This creates an empty project like this:

Empty Makefile Project

Empty Makefile Project

Application File

To have something to compile, add a new source file:

Adding new Source File

Adding new Source File

Name it main.c or whatever you like:

New main.c file

New main.c file

Then add a main() routine with some code, e.g.

 
static int i;

void main(void) {
  for(;;) {
    i++;
  }
  /* do not leave main() */
}
Added main

Added main

Makefile

Next, use the context menu New > File on the project folder:

New File

New File

Create a file named ‘makefile’ in the project:

Creating Make File

Creating Make File

This adds an empty make file.

CMSIS, System Files and Startup

The next step heavily depends on the device used. I’m using in this example the NXP FRDM-KL25Z board. To structure things, I have created directories for the sources. The special ‘debug‘ folder will be used to place the object and executable files.

Extended project Structure

Extended project Structure

Make File Syntax

The next step is to implement the make file content. A generic make file looks like this:

all: hello.axf

clean:
 rm main.o hello.axf

hello.axf: main.o
 gcc -g -o hello main.o

main.o:
 gcc -c -g main.c

Each entry in the make file has the following syntax:

<target>: <list of dependencies>
<tab>Commands to execute

💡 Note that there needs to be a <TAB> character in front of each command!

There are two special targets named all an clean. ‘clean’ is used to delete all temporary files, and ‘all’ is used to build the application.

Makefile Content

In the makefile I define variables for deleting files, the compiler and the linker:

############################
# Command for removing files
RM := rm -rf

############################
# Compiler
CC := arm-none-eabi-gcc

############################
# Linker
LL := arm-none-eabi-gcc

Then I define a macro for the final executable I want to make:

############################
# Binary/exectable to build
EXE := \
 ./debug/MyMakeProject.axf

Next a list of all object files. Because the object files will be placed in the ‘debug’ folder, this is part of the name:

############################
# List of object files
OBJS := \
 ./debug/main.o \
 ./debug/startup_MKL25Z4.o \
 ./debug/system_MKL25Z4.o

The next thing is something really cool. If main.c includes the header file main.h, I would have to write a rule like

main.o: main.c main.h
  $(CC) -c main.c -o main.o

But this is very painful: I have to write the rule for each file and need to keep track of the header files. Instead, I let the compiler create dependency files later below with extension .d (for dependency). The dependency file main.d looks like this:

debug/main.o debug/main.d: source/main.c source/main.h

source/main.h:

I’m including the files as additional rule files if it is not the ‘clean’ target:

############################
# Include generated dependcy files (only if not clean target)
ifneq ($(MAKECMDGOALS),clean)
ifneq ($(strip $(C_DEPS)),)
-include $(C_DEPS)
endif
endif

The following is the set of compiler options which I can use later:

############################
# Compiler options
CC_OPTIONS := -c -std=gnu99 -O0 -g -ffunction-sections -fdata-sections -fno-builtin -mcpu=cortex-m0plus -mthumb -DCPU_MKL25Z128VLK4 -D__USE_CMSIS -I"CMSIS" -I"source"

Similar, the options for the linker:

############################
# Linker Options
LL_OPTIONS := -nostdlib -Xlinker -Map="debug/MyMakeProject.map" -Xlinker --gc-sections -Xlinker -print-memory-usage -mcpu=cortex-m0plus -mthumb -T linkerfile.ld -o $(EXE)

Next the target to build the application:

############################
# Main (all) target
all: $(EXE)
 @echo "*** finished building ***"

Followed by the target to do a ‘clean’:

############################
# Clean target
clean:
 -$(RM) $(EXECUTABLES) $(OBJS) $(EXE)
 -$(RM) ./debug/*.map
 -@echo ' '

Below is the rule to link the application with all the object files:

############################
# Rule to link the executable
$(EXE): $(OBJS) $(USER_OBJS) linkerfile.ld
 @echo 'Building target: $@'
 @echo 'Invoking: Linker'
 arm-none-eabi-gcc $(LL_OPTIONS) $(OBJS) $(LIBS)
 @echo 'Finished building target: $@'
 @echo ' '

Next, I specify rules to build the object files. I have to specify a rule for each subfolder I’m going to use:

############################
# Rule to build the files in the source folder
./debug/%.o: ./source/%.c
 @echo 'Building file: $<'
 $(CC) $(CC_OPTIONS) -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.o)" -MT"$(@:%.o=%.d)" -o "$@" "$<"
 @echo 'Finished building: $<'
 @echo ' '

############################
# Rule to build the files in the CMSIS folder
./debug/%.o: ./CMSIS/%.c
 @echo 'Building file: $<'
 $(CC) $(CC_OPTIONS) -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.o)" -MT"$(@:%.o=%.d)" -o "$@" "$<"
 @echo 'Finished building: $<'
 @echo ' '

💡 The option -MMD -MP -MF”$(@:%.o=%.d)” -MT”$(@:%.o=%.o)” is generating the dependency .d file for each source file compiled.

Make Build Targets

To build the project, the usual ‘make/build’ and ‘clean’ menu/commands in Eclipse can be used. But there is another cool way: Build targets!

For this, open the Build Targets view (menu Windows > Show Views > Other):

Make Build Targets

Make Build Targets

In that view, select the project and click the ‘New Build Target’ button:

New Build Target

New Build Target

Create a target for ‘clean’:

Clean Target

Clean Target

This adds a ‘Build Targets’ group to the project. Use the context menu to add a new target for ‘all’:

Create new Target

Create new Target

With this, I can double-click or use the context menu to execute a target in the makefile :-).

Make Build Targets ini Eclipse Project Explorer

Make Build Targets in Eclipse Project Explorer

Summary

Managed make and build in Eclipse is a great feature: it is simple and easy to use, and probably the right thing for 98% of the use cases with an IDE like Eclipse. But if I want to use normal make files with Eclipse, this is not hard. With the proposed make file template I have to extend the list of files if new sources get added to the project. Otherwise everything is taken care of. Writing make files requires a learning phase, but this can be a well invested effort.

Happy Making 🙂

Links

 

35 thoughts on “Tutorial: Makefile Projects with Eclipse

      • Hi Erich: I have followed this tutorial as closely as I could, but I cannot generate the MK files that are shown in your third diagram. I have the “makefile” to start with, but I need to generate an MK tree to be useable in Wiced Studio. Can you help? How do I convert Unix Makefile system into Wiced-Eclipse MK build system? I have been searching for a solution for a couple of weeks now, and your example is the first one that has given me hope that it may be possible. Thanks, Garry.

        Like

  1. Nice tutorial. I love using makefiles for build automation, I don’t know if its the same in Windows, but I usually do the build based on the project directories, just fetch all .c files in there and .s files and automatically build all of them. make provides some useful features for this sort of thing. You can also specify the source directories directly as variables, and fetch all the files inside those directories with something like C_SRCS := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.c)) where SRC_DIRS is a list of directories with source files. That way you could even automate populating the SRC_DIRS list based on the project root directory if need be. For the list of object files: C_OBJS := $(patsubst %.c,$(OBJ_FOLDER)%.o,$(notdir $(C_SRCS))) where OBJ_FOLDER is some sort of build directory if you don’t want to make your source folder dirty. Cleaning the project is usually reduced down to deleting that build directory. You can have a look at my makefile here: https://github.com/Muriukidavid/twr-k60n512_2017/blob/master/Makefile .
    It might a little too much for a beginner, but I have learned that a great makefile is generic enough to be reused across projects with minimal changes. And yes, when it comes to version control, and of course sharing your code to the world on the Internet, makefiles are much better than IDE files like, .cproject files. Anything parametric rocks!! Thats why I love me some OpenSCAD for 3D modeling as well. Git and share the .scad files, let everyone change the code and render the models on their computers. How I wish every model on thingiverse.com was a .scad file…

    Like

    • Great input! I have tried OpenSCAD and I love it, but simply had not enough time to deal with it, that’s why I’m still doing my 3D models with Autodesk 123Design :-(.

      Like

  2. Pingback: Building Eclipse and MCUXpresso IDE Projects from the Command Line | MCU on Eclipse

  3. Pingback: Tutorial: Porting BLE+NRF Kinetis Design Studio Project to MCUXpresso IDE | MCU on Eclipse

  4. Pingback: Managing Project and Library Dependencies with Eclipse CDT | MCU on Eclipse

  5. Hi Eric,

    Do you know if it’s possible to have the makefile in another folder than where the project is saved/created and the makefile to use relative paths?
    The folder structure looks something like this (it’s a bit more complex, actually):

    root/
    /sources
    /projects/my_project_1/.cproject
    /lvl1/lvl2/lvl3/makefile

    So technically, what I would like to achieve is to be able to both do a “make” in the shell and compile the Eclipse project.

    So far I’ve found out that the Build command (in the Builder Settings) does not manage well the relative paths used by the makefile, and I couldn’t pass this point.

    Best regards!

    Like

    • I have not used such a structure. But I think you face a problem with the ‘current directory’ if using relative paths. Using Eclipse with the GNU MCU Eclipse plugins, the current directory for the compiler/make/etc is the ‘output’ folder which is usually named ‘Debug’ or ‘Release’, so this is the base for your relative path settings. If using make outside of Eclipse, you need to make sure that the current path is the same, otherwise your relative paths won’t point to the correct location?

      Like

  6. Great tutorial(s)! However, one thing that has been bothering me on several occasions, is integrating Eclipse with embedded makefile projects and version control. If you have any pointers on this that would be very much appreciated. For example:
    – I want to clone a project from git (or other vcs, or simply unzip a project tree), and -quickly- start working on it from Eclipse, with -all- settings (external build, launchers, indexer settings, etc.) readily available.
    – Similar when cloning the project a second time to a different directory (e.g. working on a different branch in parallel) -> new Eclipse instance to work on that, in different virtual desktop for example.

    I have never been able to figure this out properly; which files to check in to version control (.project, .cproject, but this doesn’t seem to be enough) to have -all- project settings shared and available.
    Setting it up once works fine (long list of indexer include paths), but I don’t like doing this multiple times. It’s still not clear to me if Eclipse properly supports this or not. Project settings should (all) be part of the checked-in project in my opinion.

    Like

  7. Hello Erich,

    what if i have more than 100 .cpp files in my project? should i add every .cpp to the Makefile and build .o files?

    Best regards,
    Hani

    Like

  8. Pingback: Building and Flashing ESP32 Applications with Eclipse | MCU on Eclipse

  9. Since an Eclipse-Managed Make generates the make files automatically, is it possible to call “make” from a command line to build a project with a managed make? If not, why not?

    Like

  10. Hi Erich: I have followed this tutorial as closely as I could, but I cannot generate the MK files that are shown in your third diagram. Thus, I am stuck. I have the Unix “makefile” tree to start with, but I need to generate an MK tree to be usable in Wiced Studio (Eclipse shell that uses MK tree). Can you help? How do I convert Unix Makefile system into Wiced-Eclipse MK build system? I have been searching for a solution for a couple of weeks now, and your example is the first one that has given me hope that it may be possible. Thanks, Garry.
    Your article: https://mcuoneclipse.com/2017/07/22/tutorial-makefile-projects-with-eclipse/comment-page-1/?unapproved=213016&moderation-hash=34ff6b30aeab7937e5e030049af887f4#comment-213016

    Like

    • Hi Garry,
      the makes files in the third image (https://mcuoneclipse.files.wordpress.com/2017/07/generated-make-files.jpg) are generated by Eclipse for an ‘automake’ project.
      So this should be generated by default for new projects in WICED if you create a new project. Converting a Unix make file system works as long as you stay on the same host system (switching between Windows and Unix is a challenge because of the paths and drive letters on Windows).
      If you have an existing and working make file system, you should be able to just build it from the command line.
      Then basically point to the make file from the eclipse project as in this article here. So make sure you can build things from the command line first to find any issues (e.g. path or tool settings).

      I hope this helps,
      Erich

      Like

      • Hi Erich:
        Thank you for your reply.
        I will try this again, but I think something is not right.
        I start with a cmake project that works fine with VS2017 driven by CMakeFiles.txt
        Then, I generate Unix Makefiles with -G “Eclipse CDT4 – Unix Makefiles”, and I get “makefile” in correct locations where the CMakeFiles.txt are located.
        Then, I create New “Makefile Project from Existing Code” and I get the new project created.
        Then, I select project properties, but the makefile generation box is grey (disabled).
        So, I cannot generate MK file system from new project that has makefiles.
        What am I missing?
        Thanks, Garry.

        Like

        • If you create in Eclipse a project with “Makefile Project from Existing Code”, then it means that you have to supply the make file, it will not be an automake project (make files generated).
          So you have either a ‘automakefile project’ where Eclipse is doing all the work for you, or if you create a makefile project then you are responsible for the make files.
          In any case it is a make file project, but the difference is who is maintaining it (you or Eclipse).
          I hope this makes it clear?

          Like

        • Hi Erich:
          Thank you for that explanation.

          What is the difference between a generated Unix Makefile, and an “MK” file as used by Wiced?

          Can I simply rename all the “makefile” to “makefile.MK” and expect it to work?

          There are dozens of these makefiles in many sub-directories, so renaming is a lot of work, but I will do it if you think it might work.

          For example, in file “scan.mk” (from a Wiced project) there are two effective lines:
          NAME := App_Scan
          $(NAME)_SOURCES := scan.c

          I understand these two lines in MK, but nowhere in the Unix Makefile can I find any direct reference to the C source files to be compiled. The conditionals with .o and .s are there, but no .c

          To me it looks like two different systems. Also, I cannot find the := assignment in the Unix Makefiles.

          What I think I need is some way to have the cmake -G “Eclipse CDT4 – Unix Makefiles” generator create MK format directly, so I tried the different generators for MinGW, Ninja, NMake, but none of them creates the same style as the Wiced-Eclipse MK file format. Is there such a thing?

          Any comments would be much appreciated.
          Thanks, Garry.

          Like

        • Hi Garry,
          I admit I have not used WICED recently (would need to re-install it, my notebook disk was running out of space).
          Simply renaming make files is not a guarantee that it will work. It might work, but it all depends.
          First there are different versions of make files (depending on the version of make utility), but the general basic syntax should always work.
          Not sure what you mean with ‘Unix make files’: the difference would be how files are used/referenced (drive letters, forward vs. backward slashes, etc).
          I doubt about an approach to ‘create Wiced-Ecliopse MK file format’: simply use ‘normal’ make files and treat it as such: you won’t be able to mimik the auto-generated make files in an easy way, unless you write your own generator?

          Like

        • Hi Erich:
          Thanks for your reply. I am okay working with Wiced so you don’t need to install that program. I just need to get Eclipse to create an MK file.
          I am now starting from scratch, creating a new project with only two files “main.c” and “stub.c”
          I have used the following steps in Eclipse:
          File – New – Project – C Project
          Next
          Makefile project – Empty Project – MinGW GCC – Project Name – Location (not default)
          Next
          create two new C files in “src” folder
          Of course I could not compile these files because there is no makefile or MK file.
          Now, please suggest how to create MK file as shown in your sample.
          I think I made a “wrong turn” somewhere in this new project creation.
          Thank you for your help.
          Garry.

          Like

        • Hi Erich:
          Thank you for the link to the makefile tutorial. I am working through that now.
          BUT, in the third image that we are discussing, who created the “sources.mk”, “objects.mk”, and “subdir.mk” files. Also, who created the “makefile”?
          Did you create all of these “MK” files by yourself, did Eclipse generate some of them? Was the “makefile” used by Eclipse to generate the “MK” files?
          I presume you started with the “makefile” then Eclipse created the three MK files, which I what I am trying to do, but I am getting very confused at the moment.
          Thanks for you help.
          Garry.

          Like

        • Hi Garry,
          the extension of the files (.mk, .mak, .MK) really does not matter. You are free to name the files the way you like, but usually the top make file is named ‘makefile’.
          The make files in https://mcuoneclipse.files.wordpress.com/2017/07/generated-make-files.jpg are all generated by Eclipse.
          The make file in https://mcuoneclipse.files.wordpress.com/2017/07/extended-project-structure.png is one generated by hand.
          You are free to organize the make files and the names as you want, but as a starter just have one file and name it makefile.

          Like

      • Hi Erich:

        Can you help me find these so-called “global variables”, as created by cmake Generator to get from CMakeLists.txt to Unix makefile. Here is my situation:

        I have reached an impasse with the cmake Generator related to the manner in which the cmake Generator handles a couple of include directories from the original CMakeLists.txt. There are two lines involved that are not directly created in the generated makefile:

        From the source file CMakeLists.txt we have:

        259 include_directories(${MACRO_UTILS_INC_FOLDER})

        260 include_directories(${UMOCK_C_INC_FOLDER})

        It seems like the cmake Generator does not directly create corresponding include directory statements in the generated makefile, but instead, puts a statement in a generated readme.md file as follows:

        The project will export a *global variable* MACRO_UTILS_INC_FOLDER that points to the folder needed to be included so that `#include “azure_macro_utils/macro_utils.h”` resolves properly.

        The same applies to the UMOCK_C_INC_FOLDER, and thus is creating build errors.

        Unfortunately, there are no clues given as to where these exported *global variables* are hidden. They are not in Windows Environment Variables, which I thought would make sense for command-line operation, so the mystery is to find these hidden global variables then include them (somehow) during the *make* makefile command-line operation.

        At this point, I am stuck in my work.

        I would appreciate any suggestions Thank you, Garry Anderson.

        Attached files for your reference: CMakeLists.txt (source), readme.md (generated), makefile (generated)

        Like

        • Hi Garry,
          I have mixed feelings about such generators. I believe you have to devfine these variables on the command line passed to cmake.
          Another thought is: maybe it would be easier for you if you write the make file instead using a generator/converter?
          Erich
          PS: there were no files attached

          Like

        • Hi Erich: I previously attached two files, but they did not get through. Perhaps we could continue with regular email that delivers attachments correctly. Please let me know your email address. I do not use Twitter, Facebook, or any other social media. I only use regular email. Thank you, Garry.

          Like

        • Hi Erich: I think I have reduced my question to one simple question: “What statement/syntax/command do I put in a makefile to make it include a folder, which is searched for finding other H files during make?” There must be some way to tell “make” which folders to search during the build process. “Cmake” has it, so “make” should also have it. Download attachments from here: https://files.secureserver.net/0sARqmkldheM4B
          Thanks, Garry Anderson.

          Like

What do you think?

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.