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

 

Advertisements

8 thoughts on “Tutorial: Makefile Projects with Eclipse

  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

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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s