Make originated as a system for building compiled code. It is now used as a system for making changes across many files and directories. It is useful whenever a change in one file requires changes or actions elsewhere.
Make is useful for system administrators as well as developers. This article primarily discusses Make as a compilation tool, but it can be effective for program installation or system configuration changes.
Make requires a configuration file. Once this file is constructed for your project, you usually type
make to build the changed files.
The usual name for this file is
Makefile; the capitalization lists the makefile with
README and other special files.
When run with no arguments, GNU Make looks for the configuration files named
makefile in the current working directory. If using other names, call Make with
make -f filename.
The makefile in this example displays
make complete and does nothing else. By default, Make lists the commands it runs. To have it run quietly, call Make with
$ls makefile renamed_makefile $make echo make complete make complete $make -f renamed_makefile echo make complete make complete $make -s make complete
The examples in this article are written for C, and produce the
sample target file. Make can produce any target file, use any shell commands, and work from any source files. Make works best with languages where the compiler does not itself try to resolve dependencies.
Experienced users of Make will see redundant lines in the example makefile. Make already knows how to compile some types of files, and the rules for those files can be left out. (These are called
implicit rules.) For clarity, the examples show these rules.
# Linking object files sample: main.o example.o cc -o sample main.o example.o echo sample: make complete # Compiling source files main.o: main.c main.h cc -c main.c example.o: example.c defs.h cc -c example.c
A Make rule is composed of:
target: prerequisites commands
A target is considered "up to date" if it exists and is newer than its prerequisites.
Make works backwards, starting with the target of the first rule in the file. In our example, that's
sample. Make checks the prerequisites for sample --
example.o -- to see if they have rules. If they do, it recursively checks their rules.
Make walks down the recursion chain until it finds a target that has no prerequisites, or whose prerequisites have no rules. Once it hits one of those, it walks back up its recursion chain and runs commands as necessary. It creates a recursion chain for every prerequisite it encounters that has a rule.
Once all of the prerequisite rules have been run, it eventually returns to
sample's rule. If the file doesn't exist, or is older than its prerequisites now are (after their rules have been recursively tested), it runs the commands to generate
In the example makefile, Make:
sample's prerequisites have rules. They do.
main.o's prerequisites have rules. They don't.
main.ois up to date. If not, it runs the commands for
example.o's prerequisites have rules. They don't.
example.ois up to date. If not, it runs the commands for
sampleis up to date. If not, it runs the commands to update it.
Make can run the prerequisites in any order. The important part of this sequence is that it runs recursively backwards from the first target (or the target named in the command parameters), and tests only the rules that it encounters in the prerequisites chain.
Make aborts compilation if it receives an error. This is usually useful behavior -- it lets you correct compiler-detected problems during a compile-and-test cycle. The option
-i tells Make to ignore errors.
In software development, it's very convenient to create a script to remove old compiled code so that the next build recompiles everything. It's also convenient to have a script for installing the code. Make allows scripts like this to be included in the makefile, as phony targets. Phony targets may have prerequisites, and may themselves be prerequisites.
The special rule
.PHONY tells Make which targets are not files. This avoids conflict with files of the same name, and improves performance.
If a phony target is included as a prerequisite for another target, it will be run every time that other target is required. Phony targets are never up-to-date.
To run a phony target from the command line, call Make with the name of the phony target, e.g.:
# Naming our phony targets .PHONY: clean install # Removing the executable and the object files clean: rm sample main.o example.o echo clean: make complete # Installing the final product install: cp sample /usr/local echo install: make complete
As a project gets larger, more files are usually added. If you repeat a list of files, you can accidentally leave files out of the list. It's simpler to make use of a variable that expands into the list.
The syntax for declaring and setting a makefile variable is
varname = variable contents. To call the variable, use
# Defining the object files objects = main.o example.o # Linking object files sample: $(objects) cc -o sample $(objects) echo sample: make complete # Compiling source files main.o: main.c main.h cc -c main.c example.o: example.c defs.h cc -c example.c # Removing the executable and the object files clean: rm sample $(objects) echo clean: make complete
There are a few touches which make the difference between a usable and a professional makefile. The next example adds those extra touches.
# 1 # Defining the compiler: CC=gcc # Defining the object files: objects = main.o example.o # 2 # The default rule - compiling our main program: all: sample echo all: make complete # 3 sample: $(objects) # If we get here, all the dependencies are now built. # Link it: $(CC) -o $@ $+ # 4 # Tell make how to build .o files from .c files: %.o:%.c $(CC) -c $+ # 5 #Now make sure that make rebuilds files if included headers change: main.o: main.h defs.h example.o: example.h defs.h
Use a variable for the compiler, in case you want to use the same makefile with a different compiler.
When called without a rule parameter, Make runs the first rule it encounters. It is more human-readable to explicitly state your first rule.
all is a common name for a first rule.
The automatic variable
$@ means "the name of the target." The automatic variable
$+ means "all prerequisites, space-separated." Automatic variables are pre-defined in Make.
A pattern rule tells make how to convert the prerequisite to the target. The
% in the pattern means "one or more characters," and refers to the same string in the prerequisite and the target. This particular pattern tells make how to convert a
*.c file to a
*.o file of the same name.
The automatic variable
$+ means "all prerequisites, space-separated."
These rules are relying on "implicit rules." Make has built-in patterns for converting a
*.h file to the dependent
*.o. These rules are included to define the prerequisites for the relevant
Make has many features I haven't mentioned, and is useful in any situation where a file is dependent on files that may change. Experiment, and develop your own interesting variations on makefiles.
Jennifer Vesperman is the author of Essential CVS. She writes for the O'Reilly Network, the Linux Documentation Project, and occasionally Linux.Com.
Return to the Linux DevCenter.
Copyright © 2009 O'Reilly Media, Inc.