Makefiles
CSE 2421
make is a utility for building and maintaining groups of
programs (and other types of files) from source code
The purpose of the make utility is to determine automatically
which pieces of a large program need to be re-compiled and
issue the commands necessary to recompile them.
To use make, you must create a file call Makefile (or makefile)
that describes the relationships among files in your program
Make decides whether a target needs to be regenerated by
comparing file modification times
make is a Unix/Linux utility, which is used to manage building (compilation) of
programs.
It is very commonly used in industry in Unix/Linux environments.
For a large program, it is more efficient for the developer and the machine if the
program is written as a number of smaller files; recompiling each of these various files
that make up the program is only done when something changes which requires
recompilation.
This also promotes reusability of code, because source code for functions can be kept
in separate files, and the file can be called and compiled in any program for which it is
useful.
Makefiles contain file dependency lists and UNIX commands and will run them in a
specified sequence.
Anything that can be entered at the UNIX/LINUX command prompt can be in the
makefile.
The name of your makefile has to be: makefile or Makefile
The directory you put the makefile in matters!
You can only have one makefile per directory.
Each command must be preceded by a TAB and is immediately followed by hitting the
enter key.
MAKEFILES ARE UNFORGIVING WHEN IT COMES TO WHITESPACE!
To run make… you must be in the directory where the makefile is.
make is a Unix/Linux utility program.
Command to run make on the makefile in the directory:
$make tag-name
Note: tag-name is also called section name
Let’s look at a program with multiple source files that could be built with make. Let’s
suppose we want the executable to be called mkprog
/* mkfunc.h */
/* The header file contains function
prototypes for all functions in the
program, except main() and library
functions
*/
void print_hello();
int fact(int n);
/* mkfact.c */
#include “mkfunc.h”
/* note ” ”, not < > */
int fact(int n) {
if (n != 1) {
return (n * fact(n – 1));
}
else return 1;
}
/* mkhello.c */
#include “mkfunc.h”
#include
void print_hello() {
printf(“Hello World!\n”);
}
/* mkmain.c */
#include “mkfunc.h”
#include
int main() {
print_hello();
printf(“5 factorial is %d”, fact(5));
return 0;
}
Compiling our example would look like:
gcc -ansi -pedantic -o mkprog mkmain.c mkhello.c mkfact.c
The basic makefile is composed of lines:
target: dependencies
[tab] system command [These are known as rules]
“all” is the typical default target for makefiles
$make all
This executes:
gcc –ansi –pedantic -o mkprog mkmain.c mkhello.c mkfact.c
The make utility will execute the first target in the makefile by default, if no other one is
specified, so the following command has the same effect with the makefile given in the
next slide:
$make /* target “all” is implied if “all” is first */
all: mkprog
mkprog: mkmain.o mkfact.o mkhello.o
gcc mkmain.o mkfact.o mkhello.o -o mkprog
mkmain.o: mkmain.c mkfunc.h
gcc –ansi –pedantic –c mkmain.c
mkfact.o: mkfact.c mkfunc.h
gcc –ansi –pedantic –c mkfact.c
mkhello.o: mkhello.c mkfunc.h
gcc –ansi –pedantic –c mkhello.c
clean:
rm –rf *.o mkprog
all: mkprog
mkprog: mkmain.o mkfact.o mkhello.o mk mk_newfunc.o
gcc mkmain.o mkfact.o mkhello.o mk_newfunc.o -o mkprog
mkmain.o: mkmain.c mkfunc.h
gcc –ansi –pedantic –c mkmain.c
mkfact.o: mkfact.c mkfunc.h
gcc –ansi –pedantic –c mkfact.c
mkhello.o: mkhello.c mkfunc.h
gcc –ansi –pedantic –c mkhello.c
mk_newfunc.o: mk_newfunc.c mkfunc.h
gcc –ansi –pedantic –c mk_newfunc.c
clean:
rm –rf *.o mkprog
Based on the makefile above, make will create a
dependency table:
mkprog
mkmain.o mkfact.o mkhello.o
mkmain.c mkfunc.h mkfact.c mkfunc.h mkhello.c mkfunc.h
*Using this table, make can determine what to recompile based on changes in any of the files.
/home/4/jones.5684/cse2421
$make clean
rm –rf *.o mkprog
/home/4/jones.5684/cse2421
$make
gcc -ansi -pedantic -c mkmain.c
gcc -ansi -pedantic -c mkfact.c
gcc -ansi -pedantic -c mkhello.c
gcc mkmain.o mkfact.o mkhello.o -o mkprog
/home/4/jones.5684/cse2421
$mkprog
Hello World!
5 factorial is 120
/home/4/jones.5684/cse2421
$make
make: Nothing to be done for ‘all’.
To see what files have been modified recently, use ls –lt
◦ -l means long form (give details like times)
◦ -t means time sorted order (give the newest first)
This will help you predict what will be compiled by make
This will show you when make has nothing to do
Make can be used to issue any command in linux
Make follows the rules to build the target specified on the
command line
It will run those commands if the target is older than any of
the things it depends on
In this class, any compilation that turns a .c file into a .o file
or into an executable file must have ALL of the following 4
warnings:
◦ -ansi
◦ -pedantic
◦ -Wreturn-type
◦ -Wimplicitfunction-declaration
Forgetting any of these can cause a zero on your lab
With automatic variables…
◦ $@ the target of the current rule
◦ $^ the dependencies of the current rule
◦ $< the first dependency of the current rule
◦ $* the stem with which the pattern of the current rule matched
And patterns…
◦ % the Make wildcard % specifies a pattern
We can create the following rule :
%.o : %.c
gcc –ansi –pedantic -Wreturn-type -Wimplicitfunction-declaration –g –c $< -o $@
%.o : %.c
gcc –ansi –pedantic -Wreturn-type -Wimplicitfunction-declaration –g –c $< -o $@
Make will default to using cc (and not gcc) to build .o files and
cc won’t give warnings the way gcc with the flags we use gives
warnings
This doesn’t deal with header file dependencies
%.o : %.c *.h
gcc –ansi –pedantic -Wreturn-type -Wimplicitfunction-declaration –g –c $< -o $@
This rebuilds all .o when you touch any .h file
◦ This is almost perfect behavior and it let’s us use a single, very useful
rule
◦ There has to be at least one .h file in the directory for this to work right
or it defaults to cc again.
If you change one .c file it only rebuilds the one matching .o
file
# all you have to do is change the target name and the dependency list
# (assuming that it only depends on .o files)
# the previous slides handle turning .c into .o
lab3: lab3.o table.o memory.o
gcc –g –o $@ $^
# if you have libraries, put them at the end of the rule
lab3: lab3.o table.o memory.o
gcc –g –o $@ $^ -lm –lncurses –L. -lcustom
You can suppress the implicit rules that make has by using
the –r flag:
make –r lab3
Always use –r when you use make in order to force it to only
build things exactly as you direct
The graders will always build with make –r
If your code fails to build with make –r you get a zero on the
lab