(Use this version, it looks prettier.)
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).
makeis 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).
makeenables 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.
makefigures 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.
makeis 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.
makeis not limited to building a package. You can also use
maketo 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
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.
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
baz.l. You also have header files called
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 to update the first target listed in the makefile.
make notices that none of
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
make first updates the target
lexer.c, which runs
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.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.:
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:
.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.