By Robert Mecklenburg
Book Price: $29.95 USD
£20.95 GBP
PDF Price: $23.99
Cover | Table of Contents | Online Book | Colophon
target: prereq
1
prereq
2
commands
foo.o: foo.c foo.h
gcc -c foo.c
#include <stdio.h>
extern int fee_count, fie_count, foe_count, fum_count;
extern int yylex( void );
int main( int argc, char ** argv )
{
yylex( );
printf( "%d %d %d %d\n", fee_count, fie_count, foe_count, fum_count );
exit( 0 );
}gcc -c count_words.c
int fee_count = 0;
int fie_count = 0;
int foe_count = 0;
int fum_count = 0;
%%
fee fee_count++;
fie fie_count++;
foe foe_count++;
fum fum_count++;
.
\n
$ make
flex -t lexer.l > lexer.c
gcc -c lexer.c
gcc count_words.o lexer.o -lfl -ocount_words
$ count_words < lexer.l
3 3 3 3
$ make lexer.c
$ make lexer.c
make: `lexer.c' is up to date.
make will respond with:$ make non-existent-target
make: *** No rule to make target `non-existent-target'. Stop.
all, is
updated by default. More and more detailed targets follow with
targets for program maintenance, such as a clean
target to delete unwanted temporary files, coming last. As you can
guess from these target names, targets do not have to be actual
files, any name will do.
target
1
target
2
target
3 : prerequisite
1
prerequisite
2
command
1
command
2
command
3
$ make
Makefile:6: *** commands commence before first target. Stop.
vpath.o variable.o: make.h config.h getopt.h gettext.h dep.h
vpath.o: make.h config.h getopt.h gettext.h dep.h variable.o: make.h config.h getopt.h gettext.h dep.h
vpath.o: vpath.c make.h config.h getopt.h gettext.h dep.h vpath.o: filedef.h hash.h job.h commands.h variable.h vpath.h
# Make sure lexer.c is created before vpath.c is compiled.
vpath.o: lexer.c
...
# Compile vpath.c with special flags.
vpath.o: vpath.c
$(COMPILE.c) $(RULE_FLAGS) $(OUTPUT_OPTION) $<
...
# Include dependencies generated by a program.
include auto-generated-dependencies.d
$(variable-name)
COMPILE.c, for example. In
general, a variable name must be surrounded by $(
) to be recognized by make. As a special
case, a single character variable name does not require the
parentheses.$@
$%
$<
#include <lexer.h>
#include <counter.h>
void counter( int counts[4] )
{
while ( yylex( ) )
;
counts[0] = fee_count;
counts[1] = fie_count;
counts[2] = foe_count;
counts[3] = fum_count;
}
#ifdef COUNTER_H_ #define COUNTER_H_ extern void counter( int counts[4] ); #endif
#ifndef LEXER_H_ #define LEXER_H_ extern int fee_count, fie_count, foe_count, fum_count; extern int yylex( void ); #endif
count_words: count_words.o counter.o lexer.o -lfl
gcc $^ -o $@
count_words.o: count_words.c include/counter.h
gcc -c $<
counter.o: counter.c include/counter.h include/lexer.h
gcc -c $<
lexer.o: lexer.c include/lexer.h
gcc -c $<
lexer.c: lexer.l
flex -t $< > $@VPATH = src include CPPFLAGS = -I include count_words: counter.o lexer.o -lfl count_words.o: counter.h counter.o: counter.h lexer.h lexer.o: lexer.h
% character. This makefile
works because of three built-in rules. The first specifies how to
compile a .o file from a .c
file:%.o: %.c
$(COMPILE.c) $(OUTPUT_OPTION) $<
%.c: %.l
@$(RM) $@
$(LEX.l) $< > $@
%: %.c
$(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@
%: %.C
# commands to execute (built-in):
$(LINK.C) $^ $(LOADLIBES) $(LDLIBS) -o $@
%.html: %.xml
# commands to execute (from `Makefile', line 168):
$(XMLTO) $(XMLTO_FLAGS) html-nochunks $<
.PHONY, a special
target, which we've already seen, declares that its
prerequisite does not refer to an actual file and should always be
considered out of date. The .PHONY target is the
most common special target you will see, but there are others as
well..SUFFIXES special target is
used when specifying old-fashioned suffix rules (discussed in the
Section 2.4.3 earlier in
this chapter)..PHONY) are:.INTERMEDIATE
.SECONDARY
$ echo "#include <stdio.h>" > stdio.c $ gcc -M stdio.c stdio.o: stdio.c /usr/include/stdio.h /usr/include/_ansi.h \ /usr/include/newlib.h /usr/include/sys/config.h \ /usr/include/machine/ieeefp.h /usr/include/cygwin/config.h \ /usr/lib/gcc-lib/i686-pc-cygwin/3.2/include/stddef.h \ /usr/lib/gcc-lib/i686-pc-cygwin/3.2/include/stdarg.h \ /usr/include/sys/reent.h /usr/include/sys/_types.h \ /usr/include/sys/types.h /usr/include/machine/types.h \ /usr/include/sys/features.h /usr/include/cygwin/types.h \ /usr/include/sys/sysmacros.h /usr/include/stdint.h \ /usr/include/sys/stdio.h
gcc and use an
editor to paste the results of -M into my
makefiles. What a pain." And
you'd be right if this was the whole answer. There
are two traditional methods for including automatically generated
dependencies into $ ar rv libcounter.a counter.o lexer.o
a - counter.o
a - lexer.o
$ ar rv libcounter.a counter.o r - counter.o $ ar rv libcounter.a lexer.o r - lexer.o
cc count_words.o libcounter.a /lib/libfl.a -o count_words
cc and CC refer to different
variables. To get the value of a variable, enclose the variable name
in $( ). As a special case, single-letter variable
names can omit the
parentheses and simply use
$
letter. This is why
the automatic variables can be written without the parentheses. As a
general rule you should use the parenthetical form and avoid single
letter variable names.AWK, to hold the name of the
awk program you make it easier for other users of
your makefile. Also, if security is an issue in
your environment, a good practice is to access external programs with
absolute paths to avoid problems with user's paths.
Absolute paths also reduce the likelihood of issues if trojan horse
versions of system programs have been installed somewhere in a
user's path. Of course, absolute paths also make
makefiles less portable to other systems. Your
own requirements should guide your choice.DF = df
AWK = awk
free-space := $(DF) . | $(AWK) 'NR = = 2 { print $$4 }'
:=
assignment operator:MAKE_DEPEND := $(CC) -M
gcc -M
CC above had not yet been set, then
the value of the above assignment would be:<space>-M
$(CC) is expanded to its value (which contains no
characters), and collapses to nothing. It is not an error for a
variable to have no definition. In fact, this is extremely useful.
Most of the implicit commands include undefined variables that serve
as place holders for user customizations. If the user does not
customize a variable it collapses to nothing. Now notice the leading
space. The righthand side is first parsed by make
to yield the string $(CC) -M. When the variable
reference is collapsed to nothing, make does not
rescan the value and trim blanks. The blanks are left intact.=
assignment operator:MAKE_DEPEND = $(CC) -M
echo Creating $@... $(RM) $(TMP_JAR_DIR) $(MKDIR) $(TMP_JAR_DIR) $(CP) -r $^ $(TMP_JAR_DIR) cd $(TMP_JAR_DIR) && $(JAR) $(JARFLAGS) $@ . $(JAR) -ufm $@ $(MANIFEST) $(RM) $(TMP_JAR_DIR)
define directive. The term
"canned sequence" is a bit awkward,
so we'll call this a macro. A
macro is just another way of defining
a variable in make, and
one that can contain embedded newlines! The GNU
make manual seems to use the words
variable and macro
interchangeably. In this book, we'll use the word
macro specifically to mean variables defined
using the define directive and
variable only when assignment is used.define create-jar @echo Creating $@... $(RM) $(TMP_JAR_DIR) $(MKDIR) $(TMP_JAR_DIR) $(CP) -r $^ $(TMP_JAR_DIR) cd $(TMP_JAR_DIR) && $(JAR) $(JARFLAGS) $@ . $(JAR) -ufm $@ $(MANIFEST) $(RM) $(TMP_JAR_DIR) endef
define directive is
processed by make, the lines in the variable or
body of the macro are stored, including the newlines without being
expanded. The very last newline of a macro definition is not stored
as part of the macro. Otherwise, when the macro was expanded an extra
newline would be read by make.= and ?=
are deferred until they are used in the second phase.:= is expanded immediately.+= is expanded immediately
if the lefthand side was originally defined as a simple variable.
Otherwise, its evaluation is deferred.-DUSE_NEW_MALLOC=1, that
should not be provided to other compiles:gui.o: gui.h
$(COMPILE.c) -DUSE_NEW_MALLOC=1 $(OUTPUT_OPTION) $<
gui.o: CPPFLAGS += -DUSE_NEW_MALLOC=1
gui.o: gui.h
$(COMPILE.c) $(OUTPUT_OPTION) $<
CPPFLAGS
is built in to the default C compilation rule and is meant to contain
options for the C preprocessor. By using the +=
form of assignment, we append our new option to any existing value
already present. Now the compile command script can be removed
entirely:gui.o: CPPFLAGS += -DUSE_NEW_MALLOC=1 gui.o: gui.h
include directive shortly).$ make CFLAGS=-g CPPFLAGS='-DBSD -DDEBUG'
= is a
variable assignment. Each variable assignment on the command line
must be a single-shell argument. If the value of the variable (or
heaven forbid, the variable itself) contains spaces, the argument
must be surrounded by quotes or the spaces must be escaped.:=
or =, respectively. It is possible using the
override directive to allow a
makefile assignment to be used instead of a
command-line assignment.# Use big-endian objects or the program crashes! override LDFLAGS = -EB
# COMSPEC is defined only on Windows. ifdef COMSPEC PATH_SEP := ; EXE_EXT := .exe else PATH_SEP := : EXE_EXT := endif
COMSPEC is defined.
if-condition
text if the