Abstract
In this installment, we will dwell into make and more advanced features. In the first installment, a simple
overview was provided giving focus on rule formation, with target and dependencies thoroughly explained. Now,
I’ll explain how to form more sofisticated rules, based on wider (or stricter) matching patterns.
Implicit rules are rules well known by make. When make was written, C programming language was on its prime and
the compilation process was well defined. GNU therefore decided to implicitly include that knowledge in make. When a
rule states that a dependncy is a file with .o extension, this will cause the compilation of the same file with c extension.
Listing 1. hello.c
At this point, we have two files: hello.c and Makefile on the same directory. The execution of the command ”make” in
the directory where hello.c (and Makefile) resides gives rise to the creation of hello.
How does this work? Make knows that in order to create the binary file hello, it must have a hello.o file available. We
only created hello.c, and it is not even referenced in the Makefile, so what gives?
Make does know that when one compiles and does not link a source file, the file created is given the same basename
with .o extension. With that knowledge, make extrapolates that since hello depends on hello.o, and since %.o files are
compilations of respective %.c files (i.e. ”gcc -c hello.c” creates hello.o) there must be a hello.c file in the directory. If
there is, timestamps are compared and if hello.c is newer than hello.o or hello.o does not exist, then the command ”$(CC)
-c hello.c” command insues.
Note: $(CC) is a make variable standing for C compiler. You can do CC=gcc in the beginning of the Makefile.
GNU make provides several builtin extensions, like basename or addprefix. These can ben proven useful in some
situations. Continuing with our example, lets add two other C source files,
Listing 3. main.c
#include <stdio.h>
int hello();
int world();
int main(int argc, char *argv[]) {
hello();
world();
return 0;
}
Listing 4. world.c
int hello();
int world();
int main(int argc, char *argv[]) {
hello();
world();
return 0;
}
We have now three different C source files: hello.c, world.c and main.c. main.c contains the main function, and it is
considered the main module. It also declares the signatures of both hello and world functions, which are defined within
their respective modules.
Note: A function declaration is the simple statement of the function’s signature while a function definition contains
the body of the function.
Now we must also update Makefile content to make sure the compilation process will include the new
files,
Listing 6. Makefile
Now ”make” will create ”main” which, when executed, will print out ”Hello world”.
Note: addsuffix applies the first operand as a suffix to every element of the second operand.
Now, every time main is targeted, the list of names in DEP gets appended with a .o causing make to regenerate .o files
as needed. This depends on the implicit rule that generates .o from .c files. The rule now can also be revamped to use the
target and first dependency operators, $@ and $¡ respectively. See the first installment for more informations on these
operators, rule syntax and variables.
As anyone who’ve ever delt with a large enough project can tell, this rules help with maintining the Makefile and the
project itself; you online add (or remove terms) from the first line and the compilation process adapts to the newly added
(or removed) items.
Wildcards are syntatic sugar to help the Makefile programmer to write smaller, more concise rules. Lets explore the
running example,
Listing 8. Makefile
Note: wildcard expands the pattern given to a list of existing filenames that correspond to the pattern.
Note: patsubst substitutes the explicit part of the name for another. % stands for whatever is not matched.
In this form, we automatically add all the C source files to the compilation process and create the main from
these.
There is yet another flavor for wildcards in make, that are used for pattern matching. These will be covered on the next
installment.