Table of Contents
Now that you know how to use subprograms, you have the ability to create programs from multiple source files.
Most real-world programs contain several thousand or tens of thousands of lines of code, and are broken into many separate source files. A single source file of 50,000 lines of code would take a very long time to recompile every time we make a small change. Using many smaller source files allows us to recompile only a small fraction of the program following each change. Only the source files that have changed need to be recompiled.
The make utility is a standard Unix program that automatically rebuilds a designated set of target files when the source files from which they are built have changed. For example, an object file or executable is a target file where the source files are C source code. The PDF form of this document is a target file built from hundreds of DocBook XML source files.
The relationships between the files
are spelled out in a Makefile, which is
usually simply called Makefile
(note the
capital M). The Makefile indicates which source files are needed to
build each target file, and contains
the commands for performing the builds.
A Makefile consists of a set of build rules in the following
form, where "target-file" begins in column 1 and each command
is indented with a TAB character.
target-file: source-file1 source-file2 ... command1 command2 ...
Each rule is interpreted as "if any source file is newer than the target file, or the target file does not exist, then execute the commands". This is made possible by the fact that Unix records the last modification time of every file on the system. When you edit a source file, it becomes newer than the target that was previously built from it. When you rebuild the target (probably using make), it becomes newer than the sources.
Before executing any rule, make automatically checks to see if any of the sources are targets in another rule. This ensures that all targets are rebuilt in the proper order.
# The Makefile # # Before executing this rule, make checks for other rules where # program.o is the target program: program.o cc -o program program.o -lm # This rule will be executed before any rule where program.o is a source # no matter where it is located in the Makefile program.o: program.c program.h cc -c program.c
If we edit program.c
or program.h
,
Unix records the modification time upon saving the file. When we run
make, it first sees that program
depends on program.o
. It then searches the Makefile
to see if program.o
is built from other files
and finds that it depends on program.c
and
program.h
.
It then sees that the edited source file is newer than
program.o
and executes the command
cc -c program.c. It then returns to the rule
to build program
and sees that
program.o
is now newer, so it runs the
command cc -o program program.o -lm.
What we will see:
shell-prompt: vi program.h # Make some changes and save shell-prompt: make cc -c program.c cc -o program program.o -lm
There is really nothing more to it than this. The make command knows nothing about the target or source files. It simply compares time stamps on the files and runs the commands in the Makefile. You specify the targets, the sources, and the commands, and make blindly follows your instructions. You can make it as simple or as complicated as you wish.
One of the quirky things about make is that every command must be preceded by a TAB character. We cannot substitute spaces.
Note that not all editors insert a TAB character when you press the TAB key. Many use soft tabs, where some number of spaces are inserted instead. The APE editor uses soft tabs and indents only 4 columns when the TAB key is pressed by default. However, it will save Makefiles with TAB characters for lines that are indented 8 columns (i.e. start in column 9 or later). Just be sure to indent commands at least to column 9, e.g. by pressing TAB twice.
Make can be used to generate any kind of file from any other files, but is most commonly used to build an executable program from a group of source files written in a compiled language. Once we have a proper Makefile, we can edit any or all of the source files, and then simply run make to rebuild the executable. The make command will figure out the necessary compile commands based on the rules.
shell-prompt: make
By default, make
looks for a file called Makefile
and
if present, executes the rules in it. A Makefile with a
different name can be specified following -f
.
The traditional filename for a Makefile other than
Makefile
is ".mk".
shell-prompt: make -f myprog.mk
What does make do?
How is each rule in a makefile interpreted?
How does make know what is a target file and what is a command?
What is make most commonly used for?