(Use this version, it looks prettier.)
make
make
is a phenomenally handy tool for organising the build process of your program. It makes it trivially easy to recompile parts of your program after changing it. It is especially handy if your program consists of many source files, or some of the code is generated automatically (e.g. by lex).
make
is used by writing a file which tells it how to do whatever it is you want it to do (such as compiling a program). This file is called a makefile, and is usually called "Makefile" (this is the name make
will look for if you don't tell it otherwise).
make
do?make
enables the end user to build and install your package without knowing the details of how that is done -- because these details are recorded in the makefile that you supply.make
figures out automatically which files it needs to update, based on which source files have changed. It also automatically determines the proper order for updating files, in case one non-source file depends on another non-source file. As a result, if you change a few source files and then run make
, it does not need to recompile all of your program. It updates only those non-source files that depend directly or indirectly on the source files that you changed.make
is not limited to any particular language. For each non-source file in the program, the makefile specifies the shell commands to compute it. These shell commands can run a compiler to produce an object file, the linker to produce an executable, ar to update a library, or TEX or Makeinfo to format documentation.make
is not limited to building a package. You can also use make
to control installing or deinstalling a package, generate tags tables for it, or anything else you want to do often enough to make it worth while writing down how to do it.(This list is taken from the home page of the GNU version of make.)
In general, a makefile contains two things:
A rule consists of:
These are written like so:
target: prereq1 prereq2 action1 action2
When make
follows one of these rules and executes the actions, we say that make
updates the target.
When you run make
, you give it the name of zero or more targets to update, and it brings up for renewal those targets and all the ones they depend on (but each target only gets updated once each time). If you don't give it any targets, it assumes you want to update the first target listed in the makefile.
The target name is usually the name of a file, though it does not have to be. Now, suppose a particular target comes up for renewal. If the following are all true, then make
decides the target is already up to date and does not bother updating it.
On large projects especially, this can save a huge amount of time waiting for compilation of parts of the program that haven't changed.
A target with a name that is not the name of an existing file is called a phony target. These get updated regardless whenever you tell make
to update them, e.g. on the command line or as a prerequisite. This is based partly on the assumption that the target names a file which it creates (which is quite commonly the case). So if a target has phony prerequisites, make
will never think it is up to date.
Constants are not strictly necessary, but using them makes it easier to make major changes to the way your program is built.
For example, suppose you are writing a C program, and you want all of your files to be compiled with gcc
using the flags -Wall -pedantic -O
(turning on lots of warnings and simple optimisations). Then you can specify:
CC = gcc CFLAGS = -Wall -pedantic -O # this comment does not get included
Then, to compile a file, you would create a target for it, such as this:
foo.o: foo.c foo.h $(CC) $(CFLAGS) -c foo.c -o foo.o
Notice that to refer to the constant's value you write $(CFLAGS)
. That string gets replaced with whatever you put on the right hand side of the = sign (up until a # if there is one, which indicates a comment).
In this example we have specified the C compiler to use in the variable CC
. This is good practice if you are trying to produce portable code, as it makes it easy to compile your program with a different compiler - all you need is to change the definition of CC
, and all the actions referring to $(CC)
will use the new definition automatically.
make
To get the best out of make
, you should specify a rule for each of your source files so that they get compiled separately, with the final stage being a simple linkage operation.
Here is a fairly typical example. Suppose you are writing a program called fred
, and the source code for this program is in three source files, called foo.c
, bar.c
, and baz.l
. You also have header files called fred.h
, bar.h
and lexer.h
. baz.l
is a lex
file, which lex
uses to generate a lexical analyser, also written in C, in the file lexer.c
. You also use readline
and the standard maths functions. A good makefile would look something like this:
CC = gcc LEX = flex CFLAGS = -Wall -pedantic -O LDFLAGS = -ltermcap -lreadline -lm -lfl .PHONY: proper clean fred: foo.o bar.o lexer.o $(CC) $(CFLAGS) foo.o bar.o lexer.o $(LDFLAGS) -o fred foo.o: fred.h bar.h foo.c $(CC) $(CFLAGS) -c foo.c -o foo.o bar.o: fred.h bar.h bar.c $(CC) $(CFLAGS) -c bar.c -o bar.o lexer.o: fred.h lexer.h lexer.c $(CC) $(CFLAGS) -c lexer.c -o lexer.o lexer.c: baz.l $(LEX) -olexer.c baz.l proper: rm -vf *.o lexer.c clean: proper rm -vf fred
To make the whole project, given just those source files, just type
make
This tells make
to update the first target listed in the makefile. make
notices that none of foo.o
, bar.o
and lexer.o
actually exist yet, so it goes and updates those targets.
In the case of lexer.o
, the file lexer.c
also does not exist, because first it must be generated by lex
. So before updating lexer.o
, make
first updates the target lexer.c
, which runs lex
on baz.l
. Now make
compiles lexer.c
into lexer.o
, using the -c switch to tell gcc not to do any linking yet. Once all the other prerequisites are updated, make
looks at fred
again and runs its action, which is linking together of the three object files along with some libraries.
Now suppose that, having compiled the whole program once, you change one of the source files, say, bar.h
. foo.o
and bar.o
both depend on this file, so when you compile the program again, make
will see that those object files have older timestamps than the header file they are dependent on, and so they need to be updated. However, lexer.o
does not depend on bar.h
, so it is still newer than all of its prerequisites. So make
decides it is up to date and does not rebuild it.
If you want to compile only part of a program - for example, you're ironing out all the syntax errors from the lexer - you give make
the name of the target(s) you want it to update, viz.:
make lexer.o
You won't want to distribute your program, when it is finally ready, with all of the .o
and executable files, and all the other intermediate files such as lexer.c
. These are created during the build process, from the other source files. It's useful to have a convenient way to get rid of these before packaging. The usual way, when using make
, is to have one or more phony targets which delete these files. The target which removes all files created in the build process is usually called clean
, as above. Another common target is proper
, which removes only the intermediate files, and not the final executable. Obviously one can be implemented using the other as a prerequisite. As before, to tell make
to update these targets, type:
make clean
or
make proper
The .PHONY
target at the top tells make
which targets are always phony. If any files with those names ever actually appear in the directory, make
pretends they don't exist and always updates those targets when they come up for renewal.