Make: A Quick and Easy Guide
Table of Contents
- 1. Introduction
- 2. Basics
- 2.1. Syntax
- 2.2. Variables (Macros)
- 2.3. Suffix and Pattern Rules
- 2.4. Functions
- 3. Evolution Example
- 4. EmpClone
- 5. EmpWeb
- 6. Resources
1. Introduction
GNU make is a common unix programming helper that controls the building of targets
from prerequisites. At its most basic, it takes a look at the time-stamp of a target file
and compares that to the timestamp of its prerequisites. Think of targets as completed pieces of
a larger whole, or the whole itself. Think of prerequisites as source files. Any target whose
prerequisites have been changed (they are newer) is regenerated with the build rules you supply.
make can be used for any task where you want to turn sources into completed code.
You can use it to convert many .tex files into a final .ps, or
many .c files into a final object (making all the little .o files in between.)
Imagine you have 30 .c files,
each of which makes a .o, and then you link them into the final ELF executable.
Since make only rebuilds targets whose sources have changed, if you only change one
.c file, only one .o file is regenerated, and is then relinked with the pre-existing
and unchanged .o object files.
2. Basics
When you type make at the command prompt, make looks
in makefile or Makefile in the pwd
for your rules (how targets and prereqs. are related. You can
make a specific target to build:
make target, or even define macros: make EMPREL=emp_2410p4i kernel,
or with just make build the first target in the Makefile.
From the man page:
-f file | file | use file as a makefile |
-n | notify | show what make would do, but don’t do it |
-s | silent | do not print the commands as they are executed |
-o file | old | file is treated as very old and its rules are ignored |
-j # | jobs | number of jobs (commands) to run simultaneously |
-d | debug | which files are being considered for remaking? … |
The basic rule set to make a target from a dep is:
target: sources
________rule(s)/command(s) to turn sources into target (runs in a sh shell)
Don’t put in the underscores, this indicates a tab. If you forget to make this
a tab, and instead have spaces, make will give you very hard to diagnose errors.
2.1. Syntax
Make has a fairly picky language. You must write perfect Makefiles, or it will whine.
every command in a Makefile that make decides needs to be run is run inside it’s
own sub-shell. If you need sequential commands in one shell, you must &&
them together, or use ( ; ; 😉. You can use \ to split long lines.
: | separates a target from a dep |
= | separates a macro name from its value |
:= | appends to the end of a macro name |
+= | appends to the end of a macro name |
[TAB] | is required before any command |
# | makes the rest of the current line a comment |
\ | continues this line to the next (kill the \n newline) |
- | before a command tells make to continue on failure |
@ | before a command prevents its echo to the terminal |
$ |
token stands for the input file (first dependency) |
$^ | token stands for the input files (all dependencies) |
$@ | token stands for the output file (target) |
$* | token is the input file without its suffix |
% | glob’s files together like the shell’s * |
2.2. Variables (Macros)
Make variables are defined in NAME = value pairs anywhere in the file.
You then use these later as $(NAME).
You can define things to be evaled by the shell with backticks (``).
Or, you can just make shorthand for easier coding later.
NAME = empclone#
EXT = .tgz#
VER = 248-saic#
TGZFILE = .$(NAME).v$(VER)$(EXT)#
DATE = `date +%m%d%y`#
UNAME = `uname -r`#
INS = /usr/bin/install -D -m 644#
MKD = /bin/mkdir -p#
SYSLINUX_FILES = boot.msg vmlinuz.emp
SYSLINUX_FILES := $(SYSLINUX_FILES) ldlinux.sys param.msg\
SYSLINUX_FILES += ldlinux.sys param.msg syslinux.cfg empclone.ird
2.3. Suffix and Pattern Rules
The following suffix rule is built into make, and it says to build
an object file from C source:
.c.o:
Pattern rules are better, they use the % sign to glob, just
like the shell does with
*. So now we have:
%.o: %.c
Now, any time there is a .o file requested by some other
dependency, make will run off and build it from the .c using:
gcc -c -o source.o ${CFLAGS} source.c
2.4. Functions
If you info make, you will discover a vast amount of good stuff built into make.
There are several of these constructs used in our sample makefiles, but there are a
great many more available. Some examples: $(wildcard, $(shell, $(subst,
$(foreach, $(suffix, and $(basename.
3. Evolution Example
Usually we start with a simple makefile for a simple program and it evolves,
adding increasing complexity as our needs dictate.
Here we just give the full compilation command line. All intermediate objects
must be re-built every time.
foobar: foo.c bar.c foo.h
clean:
Now, we split the objects out, so if only foo.c is touched,
only foo.o is made.
But we paid a terrible price, in that we typed foo.o4 times!
foobar: foo.o bar.o
foo.o: foo.c foo.h
bar.o: bar.c foo.h
clean:
We really don’t want to keep typing foo.o bar.o foo.c and bar.c everywhere.
What if we were to split off modules called baz.c and fie.c?
Now we can just add them once to OBJECTS and SOURCES.
CC:=gcc
HEADERS:=foo.h
OBJECTS:=foo.o bar.o fie.o baz.o
SOURCES:=foo.c bar.c fie.c baz.c
foobar: $(OBJECTS)
$(OBJECTS): $(SOURCES) $(HEADERS)
clean:
Now, what if someone gave us a bum gcc? We don’t want to replace gcc -c 29 times,
so right now before this gets any bigger, we just define CC:=gcc and use it as $(CC).
This will also allow us to issue make CC=kgcc and not even edit the makefile.
On a quad processor machine, we might even say make -j 16 for this small sample.
Be aware that inheritance in recurvive make can make make MAKE=`make -j 16` really a bad idea (its broke).
We also notice that we can obfuscate this a bit, and type less if we replace (in the commands)
$(SOURCES) with $
a target with multiple files, and each is built seperately using the same
template. Also note that foobar becomes $(FOOBAR)
and then becomes $@, the output file!
CC:=gcc
HEADERS:=foo.h
OBJECTS:=foo.o bar.o fie.o baz.o
SOURCES:=foo.c bar.c fie.c baz.c
FOOBAR:=foobar
$(FOOBAR): $(OBJECTS)
$(OBJECTS): $(SOURCES)
clean:
4. EmpClone
Download this
example file (text format).
5. EmpWeb
Download this
example file (text format).