* Introduction
Building a program from source code typically involves a few common steps:
– Writing the source code
– Process the code to expand all *#include* files, macros, etc.
– Compiling the expanded source code to machine assembly language
– Compiling assembly language to machine binary code
– Linking binary code in multiple files or libraries into
an executable binary program
Executing these steps on a small set of source code may be manageable, but
as the source code gets larger, the process becomes more complex.
* The Make System
The *make* command looks for a file called *Makefile* which
defines targets and their prerequisites, and the rules, or
recipes, used to create them.
#+BEGIN_EXAMPLE
all: myprog
myprog: myprog.o
gcc myprog.o -o myprog
myprog.o:
gcc -c myprog.c
clean:
rm -f *.o myprog core
#+END_EXAMPLE
To build *myprog* with this *Makefile*:
#+BEGIN_EXAMPLE
make myprog
#+END_EXAMPLE
We could shorten it to just this:
#+BEGIN_EXAMPLE
make
#+END_EXAMPLE
** Rules, Targets, Dependencies
A /rule/ consists of a /target/, the files it depends on and the
actions required to build it.
A rule defines:
– name of the target(s)
– how to decide if the target is out of date and needs to be built
– how to create or update the target
*Make* uses the modification times of the
dependencies to determine when the actions should be invoked.
The commands to build a target are executed if:
– the target file does not exist
– the modification time of the prerequisite(s) are newer than
the existing target file
What happens if the target file exists but the prerequisites do not?
Execution lines must begin with a *<TAB>* character; spaces are not permitted.
Command lines can be continued with a backslash as the last character.
Each line is executed as a separate shell command and processed
by the command interpreter defined in the “SHELL” variable which
defaults to “/bin/sh”.
The exit status of each shell is examined by *make*. If the shell
completed successfully (exit 0), then *make* continues its execution
with the next line. Otherwise, it exits.
The exit value of a line can be ignored by prefacing it with a *-*.
#+BEGIN_EXAMPLE
clean:
-rm -f *.o a.out core
#+END_EXAMPLE
** Common Targets
Some common targets are *all* and *clean*. The target *all* typically
builds all of the program targets of the *Makefile*. The *clean*
target typically cleans up after the compiler to leave the build directory
in its pre-build state. These are not required nor predefined, you must
define them, if desired.
#+BEGIN_EXAMPLE
all: mywc
mywc: mywc.o
clean:
@rm -f *.o mywc a.out core
#+END_EXAMPLE
Normally, *make* will echo each line before executing it. This can be
turned off with an /’@’/ at the beginning of the line.
** Multiple Targets in a Rule
If multiple targets are defined in a rule, *make* treats each as if it
is a separate target with identical prerequisites and commands.
This is useful to add a prerequisite or when similar recipes are used
for all targets.
#+BEGIN_EXAMPLE
king.o queen.o knight.o rook.o: moves.h
#+END_EXAMPLE
** Variables and Macros
*Make* uses variables extensively. Some variables are predefined by *make*.
Environment variables are inherited from the calling
program, and there can be user-defined variables.
Macros are used similarly to variables.
#+BEGIN_EXAMPLE
CC = gcc
OBJECTS = myprog.o
CFLAGS = -g -v
myprog = “myprog”
$(myprog): $(OBJECTS)
$(CC) $(CFLAGS) $(OBJECTS) -o $@
#+END_EXAMPLE
Environment variables are inherited from the calling environment.
Every environment variable that *make* sees is turned into a *make*
variable with the same name and value.
An explicit variable assignment in a *Makefile* will override the
environment.
In order to prefer the inherited values, use the command-line
flag /-e/.
Environment variables are passed to rule command lines and
recursive *make* commands.
Variables can be added to the environment to make it available
to shell commands, or prevented from being exported:
#+BEGIN_EXAMPLE
export MYVAR1 MYVAR2
unexport GCC CFLAGS
#+END_EXAMPLE
The value of a variable can be appended after it is set:
#+BEGIN_EXAMPLE
SOURCEFILES = main.c printf.c
…
SOURCEFILES += add.c
#+END_EXAMPLE
Some variables are defined automatically.
Automatic variables are evaluated fresh for each rule that is
executed, instead of having a fixed value. Some examples:
– $@ Name of the target
– $< Name of the first prerequisite
– $^ Names of all the prerequisites
– $? Names of all prerequisites which are newer than the target
A link to a table of automatic variables is included in the References.
** Suffix & Pattern Rules
By itself, *make* knows how to create a /.o/ file from
its corresponding /.c/ file. It has the following
rule based on filename suffixes predefined:
#+BEGIN_EXAMPLE
.c.o:
$(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $<
#+END_EXAMPLE
The rule may also be written as a /Pattern/ rule:
#+BEGIN_EXAMPLE
%.o: %.c
$(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $<
#+END_EXAMPLE
The /%/ represents the basename of the target file. Note the use of
/variables/ to generalize the rule. The /$@/ is the current target and
the /$</ is the current dependency.
Similar to the implicit rule for /.o/ files, *make* has
a predefined implicit rule for making an executable
file from a /.c/ file.
#+BEGIN_EXAMPLE
$(LINK.c) -o $@ $< $(LDLIBS)
#+END_EXAMPLE
The rule uses a macro that is defined as:
#+BEGIN_EXAMPLE
LINK.c=$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS)
#+END_EXAMPLE
Because of predefined macros and implicit rules, our previous example can
be shortened to this:
#+BEGIN_EXAMPLE
all: myprog
myprog:
clean:
rm -f *.o myprog core
#+END_EXAMPLE
Implicit rules make used of many variables, such as:
– AR Program to make archive libraries; default *ar*
– CC Program for compiling C programs; default *cc*
– CFLAGS Extra flags for the C compiler
– LDFLAGS Extra flags for the linker
A link to a table of some common variables used by implicit rules
as part of the References.
** Directives
Several /directives/ are available to modify the behavior of *make*:
*** Conditonal Directives
/Conditional/ directive causes parts of the *Makefile* to be used or ignored
based on the value of variables:
– ifeq /( arg1 , arg2 )/
– ifneq /( arg1 , arg2 )/
– ifdef /condition/
– ifndef /condition/
– else
– endif
*** Other Directives
The *include* directive causes *make* to read the specified file(s)
before continuing. The *override* directive changes the value of a
variable which was set on the *make* command line:
– include /file1/ /file2/ /…/
– override /var = value/
** Recursive *make*
The *make* command can be used in a *Makefile* just as any other
command. This is useful when there are multiple susbsystems which
comprise one larger system:
#+BEGIN_EXAMPLE
subdir = /some/other/dirname
subtarget:
$(MAKE) -C $(subdir)
#+END_EXAMPLE
Environment variables are passed to each command line and recursive *make*.
By default, only environment variables that came from the environment or the
*make* command line will be passed. The /export/ directive can pass other
variables.
What happens in the following example?
#+BEGIN_EXAMPLE
FOO = foo
show:
echo $$FOO
#+END_EXAMPLE
** Command Line Arguments
*Make* has many command line arguments which can alter its behavior.
Variables can be set on the command line.
Some common arguments:
– make -i /# Ignore the exit value of shell commands/
– make -d /# Print debugging information/
– make -n /# Dry-run; only print what would be done/
– make -t /# Touch files instead of running rules/
– make -e /# Environment variables override *Makefile* assignments/
– make -r /# Disable the built-in implicit rules/
– make -j /N/ /# Run N jobs at once/
– make VAR=value /# Set the value of variable VAR/
** Further Exploration
Most GNU source code (and many others) use
*autoconf* and *automake* to create templates for *make*
which make it more portable and can better account for the
build machine environment. These are commands that make
*Makefiles*.
* Make Tutorials Available on the Web
** A Simple Makefile Tutorial:
[[http://www.cs.colby.edu/maxwell/courses/tutorials/maketutor/]]
** Tutorial by Example:
[[http://mrbook.org/blog/tutorials/make/]]
** A tutorial and reference *PDF*:
[[https://www.tutorialspoint.com/makefile/makefile_tutorial.pdf]]
* Make References
** The GNU *make* reference manual:
[[https://www.gnu.org/software/make/manual/make.html
** Catalogue of Built-In Rules
[[https://www.gnu.org/software/make/manual/make.html#Catalogue-of-Rules]]
** Default Suffix Rules and Predefined Macros
[[https://docs.oracle.com/cd/E19504-01/802-5880/6i9k05dhg/index.html#make-95873]]
** List of Automatic Variables
[[https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html]]
** Variables Used by Implicit Rules
[[https://www.gnu.org/software/make/manual/html_node/Implicit-Variables.html]]
** A Short Guide to Makefiles:
[[https://users.cs.duke.edu/~ola/courses/programming/Makefiles/Makefiles.html]]
** A GNU *make* cheat sheet on /GitHub/
Includes a *Makefile* for building a PDF version from LaTex source files:
[[https://github.com/mxenoph/cheat_sheets.git]]