Make is VERY POWERFUL. See the source document for the full features.
NOTE: Make can be used to avoid retyping a single long command,too. For example, if you are debugging and get tired
of typing
cxx -o myprog main.cxx func.cxx -lm
you could write a makefile as follows:
# lazy file
#
myprog:
cxx -o myprog main.cxx func.cxx -lm
mynext:
cxx -o mynext next.cxx
#
# end lazy file
There are two independent targets here. Since there are no dependencies listed for the targets, Make assume every
time that it must execute the appropriate command link (depending on whether you enter "make myprog"
or "make mynext").
Simple Example of `make'
Suppose we have a text editor consisting of eight C source files and three header files. We need a makefile to
tell `make' how to compile and link the editor. Assume that all the C files include `defs.h', but only those defining
editing commands include `commands.h' and only low level files that change the editor buffer include `buffer.h'.
To recompile the editor, each changed C source file must be recompiled. If a header file has changed, to be safe
each C source file that includes the header file must be recompiled. Each compilation produces an
object file corresponding to the source file. Finally, if any source file has been recompiled, all the object files,
whether newly made or saved from previous compilations, must be linked together to produce the new
executable editor.
Here is a straightforward makefile that describes these criteria and says how to compile and link when the time
comes:
edit : main.o kbd.o commands.o display.o \
insert.o search.o files.o utils.o
cc -o edit main.o kbd.o commands.o display.o \
insert.o search.o files.o utils.o
main.o : main.c defs.h
cc -c main.c
kbd.o : kbd.c defs.h command.h
cc -c kbd.c
commands.o : command.c defs.h command.h
cc -c commands.c
display.o : display.c defs.h buffer.h
cc -c display.c
insert.o : insert.c defs.h buffer.h
cc -c insert.c
search.o : search.c defs.h buffer.h
cc -c search.c
files.o : files.c defs.h buffer.h command.h
cc -c files.c
utils.o : utils.c defs.h
cc -c utils.c
We split each long line into two lines using a backslash-newline; this is like using one long line, but is easier
to read.
Each file that is generated by a program---that is to say, each file except for source files---is the "target"
of a "rule" (Note: Rules). (In this example, these are the object files such as `main.o', `kbd.o', etc.,
and the executable file `edit'.) The target appears at the beginning of a line, followed by a colon.
After the colon come the target's "dependencies": all the files that are used as input when the target
file is updated. A target file needs to be recompiled or relinked if any of its dependencies changes. In addition,
any dependencies that are themselves automatically generated should be updated first. In this example, `edit' depends
on each of the eight object files; the object file `main.o' depends on the source file `main.c' and on the header
file `defs.h'.
By default, `make' starts with the first rule (not counting rules whose target names start with `.'). This is called
the "default goal". Therefore, we put the rule for the executable program `edit' first. The other rules
are processed because their targets appear as dependencies of the goal.
After each line containing a target and dependencies come one or more lines of shell commands that say how to update
the target file. These lines start with a tab to tell `make' that they are command lines. But
`make' does not know anything about how the commands work. It is up to you to supply commands that will update
the target file properly. All `make' does is execute the commands you have specified when the
target file needs to be updated.
How `make' Processes This Makefile
After reading the makefile, `make' begins its real work by processing the first rule, the one for relinking `edit';
but before it can fully process this rule, it must process the rules for the files `edit' depends on: all the object
files. Each of these files is processed according to its own rule. These rules say to update the `.o' file by
compiling its source file. The recompilation must be done if the source file, or any of the header files named
as dependencies, is more recent than the object file, or if the object file does not exist.
Before recompiling an object file, `make' considers updating its dependencies, the source file and header files.
This makefile does not specify anything to be done for them---the `.c' and `.h' files are not the targets of any
rules---so nothing needs to be done. But automatically generated C programs, such as made by Bison or Yacc, would
be updated by their own rules at this time.
After recompiling whichever object files need it, `make' can now decide whether to relink `edit'. This must be
done if the file `edit' does not exist, or if any of the object files are newer than it. If an object file was
just recompiled, it is now newer than `edit', so `edit' will be relinked.
Thus, if we change the file `insert.c' and run `make', `make' will compile that file to update `insert.o', and
then
link `edit'. If we change the file `command.h' and run `make', `make' will recompile the object files `kbd.o',
`commands.o' and `files.o' and then link file `edit'.
Variables Make Makefiles Simpler
In our example, we had to list all the object files twice in the rule for `edit' (repeated here):
edit : main.o kbd.o commands.o display.o \
insert.o search.o files.o utils.o
cc -o edit main.o kbd.o commands.o display.o \
insert.o search.o files.o utils.o
Such duplication is error-prone; if a new object file is added to the system, we might add it to one list and forget
the other. We can eliminate the risk and simplify the makefile by using a "variable". Variables
allow a text string to be defined once and substituted in multiple places later.
It's standard practice for every makefile to have a variable named `objects', `OBJECTS', `objs', `OBJS', `obj'
or `OBJ' which is a list of all object file names. We would define such a variable `objects' with a line like this
in the makefile:
objects = main.o kbd.o commands.o display.o \
insert.o search.o files.o utils.o
Then, each place we want to put a list of the object file names, we can substitute the variable's value by writing
`$(objects)'. Here is how the rule for `edit' looks as a result:
edit : $(objects)
cc -o edit $(objects)
Letting `make' Deduce the Commands
It is not necessary to spell out the commands for compiling the individual C source files, because `make' can figure
them out: it has an "implicit rule" for updating a `.o' file from a correspondingly named `.c' file using
a `cc -c' command. For example, it will use the command `cc -c main.c -o main.o' to compile `main.c' into `main.o'.
We can therefore omit the commands from the rules for the object files. *Note Implicit::.
When a `.c' file is used automatically in this way, it is also automatically added to the list of dependencies.
We can therefore omit the `.c' files from the dependencies, provided we omit the commands.
Here is the entire example, with both of these changes, and a variable `objects' as suggested above:
objects = main.o kbd.o commands.o display.o \
insert.o search.o files.o utils.o
edit : $(objects)
cc -o edit $(objects)
main.o : defs.h
kbd.o : defs.h command.h
commands.o : defs.h command.h
display.o : defs.h buffer.h
insert.o : defs.h buffer.h
search.o : defs.h buffer.h
files.o : defs.h buffer.h command.h
utils.o : defs.h
This is how we would write the makefile in actual practice.
Another Style of Makefile
Since the rules for the object files specify only dependencies, no commands, one can alternatively combine them
by dependency instead of by target. Here is what it looks like:
objects = main.o kbd.o commands.o display.o \
insert.o search.o files.o utils.o
edit : $(objects)
cc -o edit $(objects)
$(objects) : defs.h
kbd.o commands.o files.o : command.h
display.o insert.o search.o files.o : buffer.h
Here `defs.h' is given as a dependency of all the object files; `commands.h' and `buffer.h' are dependencies of
the specific object files listed for them.
Whether this is better is a matter of taste: it is more compact, but some people dislike it because they find it
clearer to put all the information about each target in one place.
Rules for Cleaning the Directory
Compiling a program isn't the only thing you might want to write rules for. Makefiles commonly tell how to do a
few other things besides compiling the program: for example, how to delete all the object files and executables
so that the directory is "clean". Here is how we would write a `make' rule for cleaning our example editor:
clean:
rm edit ${objects}
This rule would be added at the end of the makefile, because we don't want it to run by default! We want the rule
for `all', which recompiles the editor, to remain the default goal.
Since `clean' is not a dependency of `all', this rule won't run at all if we give the command `make' with no arguments.
In order to make the rule run, we have to type `make clean'.
Make References
http://www.cs.wustl.edu/~cplus/makefiles.html
http://www.cs.colorado.edu/~main/supplements/hx.html