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:
CFLAGS=-g3 LDFLAGS=-pthread .PHONY: clean all all: myapp functions.o: functions.c functions.h $(CC) $(CFLAGS) -c functions.c main.o: main.c main.h functions.h $(CC) $(CFLAGS) -c main.c myapp: main.o functions.o $(CC) $(LDFLAGS) main.o functions.o -o myapp clean: rm -f *.o *~ myapp
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
$ make clean rm -f *.o *~ myapp
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
- compare timestamp of myapp and main.o/functions.o and if one is newer run the linker command
- main.o depends on main.c, main.h, functions.h
- myapp depends on main.o and functions.o
.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:
TARGETS = app1 app2 app3 RM = /bin/rm -f CC = gcc -g3 all: $(TARGETS) clean: $(RM) $(TARGETS)
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:
CC = gcc CFLAGS = -g3 LDFLAGS = -static all: app1 app2 app3 app1: app1.o common.o app2: app2.o common.o app3: app3.o common.o tools.o install: app1 app2 app3 cp -v app1 app2 app3 ./install clean: rm -v app1 app2 app3 *.o
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:
$ make gcc -g3 -c -o app1.o app1.c gcc -g3 -c -o common.o common.c gcc -static app1.o common.o -o app1 gcc -g3 -c -o app2.o app2.c gcc -static app2.o common.o -o app2 gcc -g3 -c -o app3.o app3.c gcc -g3 -c -o tools.o tools.c gcc -static app3.o common.o tools.o -o app3 $ make install cp -v app1 app2 app3 ./install 'app1' -> './install/app1' 'app2' -> './install/app2' 'app3' -> './install/app3'
Macros
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:
CC=gcc ARMCC=arm-none-linux-gnueabi-$(CC)
Shell environment variables are available in a makefile as macros, for example:
FILE = ${HOME}\app.c
They can also usefully be set at the command line, which enables control of the make at runtime without having to edit the makefile.
# make ARMCC=arm-linux-gcc
There arm many built in macros like CC, LD, LDFLAGS and more to see the full list run:
# make -p -f/dev/null | more
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:
${Macro-name:string1=string2}
for example if we have one macro:
ARMFLAGS = -m32 -arm -opt
we can make a new macro based on it with mips instead of arm:
MIPSFLAGS=${ARMFLAGS:arm=mips}
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
Subscribe to our list
1 thought on “Makefiles Tutorial”
Comments are closed.
[…] are seeing this because your blog was recently used as part of a DDOS attack against […]