Makefiles Tutorial

GNU Make is key utility in building applications.It is available on any operating systems. Its main purpose is to determine automatically which pieces of a program need to be recompiled, and issue the commands to build them

While working with open source project, Make is the common tool because almost any IDE can work with it. Make is a very powerful tool – in one command you can issue a series of tasks and working with it can make developers life easier.

To work with Make, we need to understand the basics , the file format and some rules

Simple example:

We have 2 C files and 2 header files:

  • functions.c (some functions)
  • functions.h (functions prototypes)
  • main.c (main function)
  • main.h (main constants)

The Makefile:

The makefile is built from target names. Each target name perform one task. In the above example the targets are: all, functions.o , main.o, myapp, clean

to run a task we use the target name , for example

running make clean removes all generated and backup files

The default for make is ‘all’ so running make without a target name build the required components. It start from all and continue recursively:

The process if we run make :

  • make starts with target all
  • all depends on myapp
    • myapp depends on main.o and functions.o
      • main.o depends on main.c, main.h, functions.h
        • there is no target name for main.c, main.h and functions.h
        • check if the timestamp of main.o is older then one of the files (main.c,main.h,functions.h) and run the command:
          • gcc -g3 -c main.c
      • functions.o depends on functions.c and functions.h
        • there is no target name for functions.c, functions.h
        • check timestamp and run command if required
      • after returning from targets main.o and functions.o
        • compare timestamp of myapp and main.o/functions.o and if one is newer run the linker command
          • gcc -pthread main.o functions.o myapp

.PHONY – tells the make utility that all and clean are not files

Note : The command line to run in the target must begin with [TAB] – not spaces!!!! 

Generating Multiple Executables

It is very easy to build more than one executable with make.

Single source file 

If we have for example 3 source files: app1.c , app2.c, app3.c and each one has its own main so we want to build 3 executables. Its it very simple Makefile:

Running make will build app1 from app1.c, app2 from app2.c and so on


Multiple Executables and Multiple Source files

if we want to build 3 executables but it based on more than one source we write it like this:

In this example

  • app1 is built from app1.c, common.c
  • app2 is built from app2.c, common.c
  • app3 is built from app3.c, common.c, tools.c

You can also run make install to copy the generated outputs:

The output:



Macros are similar to shell environment variables, but have their differences as well. They are useful when maintaining a text which is repeated through the makefile.

Macros may be used within others for example:

Shell environment variables are available in a makefile as macros, for example:

They can also usefully be set at the command line, which enables control of the make at runtime without having to edit the makefile.

There arm many built in macros like CC, LD, LDFLAGS and more to see the full list run:

String substitution

Macro string substitution is a powerful feature which enables us to create a new text string from an old one, substituting sub-strings. The syntax is:


for example if we have one macro:

we can make a new macro based on it with mips instead of arm:

There are more options and tricks but if we want to build complex apps using make we probably choose cmake or other tool that generate the makefiles for us

you can find the files i used in this post here