make
The program make
and Makefiles are a simple way to organize code compilation. This tutorial offers a very basic idea of what is possible using make
.
Prerequisites
For this tutorial, please run
1 2 |
|
This will create a directory makefile_example2
with a main program hello.c
,
a function hellofunc.c
, and an include file hello.h
.
Compiling by hand
To compile this code, you would use the following command:
1 |
|
This command compiles the two C files, and names the executable hello. With the
-I.
flag, gcc
will look in the current directory for the include file
hello.h
. For future steps, please remove the executable with rm hello
.
With only two C files, it is easy to compile with the above approach, but with more files, it is harder to keep track of everything. In addition, if you are only making changes to one C file, the above approach recompiles all of C files every time which is time-consuming and inefficient.
Transferring to a Makefile
A Makefile will be helpful for such cases. A simple Makefile is included in
the getexample
, so before we start, please move it to makefile.bak
with mv
makefile makefile.bak
.
Now, in the makefile_example2
directory, create a file called makefile
which has the following two lines:
makefile | |
---|---|
1 2 |
|
Here, the tab must actually be a tab character, not spaces.
Now, type make
on the terminal and check if the executable is created. The
make
command will execute the compile command as you have written it in the
Makefile.
Note that invoking make
with no arguments executes the first rule in the
file. Furthermore, by putting the list of files on which the command depends on
the first line after the ':', make
knows that the rule hello
needs to be
executed if any of those files change.
Useful Makefile variables
Can we make it a little bit more efficient? Let's modify makefile
like so:
makefile | |
---|---|
1 2 3 4 |
|
In this Makefile, we define the variables CC
and CFLAGS
, which are special macros communicating to make
how we want to compile the files hello.c
and hellofunc.c
.
In particular, CC
is for the C compiler, and CFLAGS
is the list of flags to pass to C compiler.
By putting the object files (hello.o
and hellofunc.o
) in the dependency
list and in the rule, make
will automatically compile the .c
files
individually into object files, and then build the executable hello
. If your
project is small (just a few files), this form of Makefile is enough.
Setting up dependencies
However, there is a problem. This Makefile misses the include files. For
example, if you made a change to hello.h
, make
would not recompile the .c
files, even though the change in hello.h
may affect them. In order to fix
this problem, we need to tell make
that all .c
files depend on certain .h
files. This can be done by writing a simple rule and adding it to the Makefile.
makefile | |
---|---|
1 2 3 4 5 6 7 8 9 |
|
This addition first creates the macro DEPS
(the macro name can be anything),
which is the set of .h
files on which the .c
files depend.
Then we define a rule for all .o
files. The rule says that each .o
file
depends on
- the
.c
file with the same name, and - the
.h
files which are included inDEPS
.
Next, the rule says that to generate the .o
file, make
needs to compile the .c
file using the compiler defined in CC
. The components are described as follows:
- the
-c
flag says to generate the object file, - the
-o $@
says to put the output of the compilation in the file named on the left side of the:
(in this case, the.o
file), - the
$<
is the first item in the dependencies list (in this case, the.c
file), - and the
CFLAGS
macro is defined on the second line.
Generalizing
To simplify the final rule, you can use special macros $@
and $^
, which are
the left and right sides of the :
, respectively. This also generalizes the
rule to work for multiple files at once.
In the example below, all of the include files should be listed as part of the
macro DEPS
, and all of the object files should be listed as part of the macro
OBJ
.
makefile | |
---|---|
1 2 3 4 5 6 7 8 9 10 |
|
Further resources
Now you have a good sense of the Makefile. For more information on Makefiles and the make
function, check out the GNU Make Manual.
You can download some other Makefile examples on the HPCC using getexample.