📄Makefiles
Since makefiles are some kind of mystic shit, I'll try my best to explain some basics.
Introduction
I will mainly use the term executable in the following examples, note that Makefiles can also be used to create a library. The steps to create a Makefile for a library are described later in this page.
Note that if you copy paste a Makefile example from this gitbook, you'll have to change every 4 spaces tabs, to single tabs as gitbook automatically converts a tab to a 4 spaces tab.
What is a Makefile / make ?
Makefiles are basically sophisticated shell scripts that automate the repetitive tasks of compiling/recompiling many files.
Make Is a Unix utility that is designed to start execution of a makefile. A Makefile is a special file that you create name Makefile, it contains shell commands. While in the directory containing this Makefile, you will run the make command and the commands written in the Makefile will be executed.
Make keeps track of the last time files (normally object files) were updated and only updates those files which are required to keep the sourcefile up-to-date. If you have a program with a lot of source and/or header files, when you change a file on which others depend, you must recompile all the dependent files. This is an extremely time-consuming task.
A Makefile contains a list of rules. These rules tell the system what commands you want to execute. Most of the time, these rules are commands to compile, or recompile, a series of files.
The rules are in two parts. The first line is called a dependency line and the following line(s) are called actions or commands. The action line(s) must be indented with a tab.
Rule syntax:
RULE: DEPENDENCY LINE
[tab]ACTION LINE(S)
The dependency line is also made of two parts. The first part, before the colon, is the target file and the second part, after the colon, are the prerequisites. It is called a dependency line because the first part depends on the second part. Multiple prerequisites files must be separated by a space.
After the Makefile has been created, a program can be (re)compiled by typing make. Make then reads the Makefile, creates a dependency tree and take whatever action is necessary. It will not necessarily do all the rules in the Makefile as all dependencies may not need to be updated. It will rebuild target files if they are missing or older than the dependency file(s).
Unless directed otherwise, make will stop when it encounters an error during the build process.
Simple Makefile example
Let's start of with the following three files, hello.c, hellofunc.c and hello.h.
Normally, you would compile these files by executing the following command :
gcc -Wextra -Wall -Werror hello.c hellofunc.c -I. -o hello
This command compiles the two .c files and creates an executable named hello.
The simplest Makefile you could create for these file would look something like :
hello: hello.c hellofunc.c
gcc -Wextra -Wall -Werror hello.c hellofunc.c -I. -o hello
Next, I will describe what rules are present in every Makefiles, these are conventions rules, and are required by the 42 Norm.
More complex Makefile will be described later.
Rules conventions
As said above, there are some rules conventions, these are rules that are not mandatory but present in almost all Makefiles, this makes compiling and building, as well as cleaning easier. Plus, these rules are required in the 42 Norm.
all
Since the first rule encountered in the Makefile is executed when using the make
command without any specific rule, the all rule has to be placed first in the Makefile, it usually calls the $(NAME) rule as a dependency (see example below).
$(NAME)
This is the main rule, it has for target the name of the executable we want to create and it will link all object files in an executable.
%.o: %.c
This rule is not required in the 42 Norm but makes reading the Makefile much easier. This rule has for target any .o file, and for dependency the .c file with the same name.
clean
This rule is a simple cleaning rule that will delete all object files created during the build process, but leave the created executable untouched.
fclean
This rule is also a cleaning rule, it is dependent on the clean rule to delete all object files. Once all object files are deleted, this rule will delete the created executable.
re
This rule will rebuild everything, it is dependent on the fclean rule, which deletes every object file and the executable. Once all the object files and the executable are deleted, the re rule calls the all rule to rebuild everything.
Variables naming convention
There's a rule convention, for which rules are expected in every Makefile, and there's also a naming convention for variable. I'll describe here the variables that are expected in a Makefile, and explain why it's named this way for the ones that are not very clear.
NAME
The buid target name (executable / library / other)
CC
This variable contains the compiler gcc for C g++ for C++
CCFLAGS
This variable contains the compiler flags. i.e. for 42 we have to use -Wall -Werror -Wextra
CPPFLAGS
This variable contains the compiler preprocessor flags. i.e. : -I to specify the include directory (see complete examples below) -D MACRO=value to define a macro at compiling time (used in Get Next Line)
Automatic variables
There's a lot of so-called automatic variables that you can use in your Makefiles, I'll describe and explain (with examples) only the most used ones (=> the ones that will be the most useful for you in the 42 Cursus).
$@
The file name of the target of the rule.
$<
The name of the first prerequisite.
$?
The names of all the prerequisites that are newer than the target, with spaces between them. If the target does not exist, all prerequisites will be included.
$^
The names of all the prerequisites, with spaces between them.
Complete Makefile example (EXECUTABLE)
Here under I will write a complete Makefile to compile an executable as well as describing each steps (as I for the simple Makefile).
This Makefile contains some Filename functions, that is another thing you can do in Makefiles to make them easier to maintain.
Complete Makefile example (LIBRARY)
Here under I will write a complete Makefile to compile a library as well as describing each steps (as I did for the simple Makefile).
This Makefile contains some Filename functions, that is another thing you can do in Makefiles to make them easier to maintain.
.PHONY targets
A phony target is a target that is not really the name of a file. It's just a name for a recipe to be executed when you make an explicit reuquest (i.e make clean
).
There are two reasons to use a phony target :
To avoid a conflict with a file of the same name.
To improve performance.
If you write a rule whose recipe will not create the target file, the recipe will be executed every time the target comes up for remaking. Here is example :
clean:
rm -f *.o
Because the rm command does not create a file named clean, probably no such file will ever exist.
Therefore, the rm command will be executed every time you say make clean
.
In this example, the clean target will not work as expected if a file named clean is ever created in this directory. Since it has no prerequisites, clean would always be considered up to date and its recipe would not be executed.
To avoid this problem, you can explicitly declare the target to be phony by making it a prerequisite of the special .PHONY target as follows :
.PHONY: clean
clean:
rm -f *.o
Once this is done, make clean
will run the recipe regardless of whether there is a file named clean.
Sources
Everything I wrote there is available in greater details somewhere on this link.
Last updated
Was this helpful?