The
make
utility builds up-to-date
versions of programs.
It is most useful for large programming projects in
which multiple source files are combined to form a single program or for building
a set of programs that are part of a single product or application.
This chapter explains the following information:
Operation of the
make
utility (Section 7.1)
Description files (Section 7.2)
The
make
command accepts options to control or modify
how the building process is performed.
The
make
utility
does not address the problem of maintaining more than one version of the same
source file.
By using the
make
utility to maintain programs, you
can do the following:
Combine the instructions for creating a large program in a single file
Define macros to use within the
make
description
file
Use shell commands
Create or update libraries
Include files from other programs
The operating system provides several versions of the
make
command; this chapter describes the default version,
make(1)make(1)make(1u)make(1p)make(1p)
The
make(1)make(1u)make(1p)
See
make(1)make(1u)make(1p)7.1 Operation of the make Utility
The
make
utility works
by comparing the creation date of a program to be built, called the target
or target file,
with the dates of the files that make it up,
called
dependency files or dependents.
If any of a given target's dependents are newer than the target,
make
considers that the target is out of date.
In this case,
make
rebuilds the target by performing the necessary compiling,
linking, or other steps.
Each dependent can also be a target; for example,
an executable program is made from object modules, which are in turn made
from source files.
Dependents that are newer than the target are called
younger files.
The
make
utility uses the following sources of information:
A description file that you create
File names
Time stamps of the files from the file system
The
make
utility depends on files' time stamps.
For
make
to work properly on a distributed system, the date and time
on all systems in the network must be synchronized.
The
make
utility creates a target file using the following
step-by-step procedure:
Finds the name of the target file in the description file
Finds a line that describes the dependents of the target, called a dependency line
Ensures that all the target's dependency files exist and are up to date
Determines if the target is current with respect to its dependents
Creates the target by one of the following methods if the target or one of the dependents is out of date:
Executes commands from the description file
Uses internal rules to create the file (if they apply)
Uses default rules from the description file
If all files described on the dependency line are up to date when
make
is run,
make
indicates that the target is
up to date and then stops.
If any dependents are newer than their targets,
make
recreates only those targets that
are out of date.
Any missing files are deemed to be out of date.
If a given target has no dependents, it
is always out of date, and
make
rebuilds it every time you run
make.
The
make
process works from the top down in determining what targets
need to be rebuilt and from the bottom up in the actual rebuilding stage.
When the
make
utility runs commands to create a target,
it replaces macros with their values, echoes each command line to the standard
output, and then runs
the command.
(See
Section 7.2.9
for information about macros.)
The
make
utility runs commands that it can execute directly,
such as
rm
or
cc,
without invoking a new shell.
The utility invokes each command
line that includes shell functions, such as pipes or redirection, in a new
shell.
You start the
make
utility in the directory that contains the description file.
The syntax of
the
make
command is as follows:
make
[
[-f ]
makefile
]
[ options
]
[ targets
]
[ macro definitions
]
The
make
utility examines the command line entries
to determine what to do.
First,
it assigns values for the macro definitions on the command line (entries containing
equal signs), if there are any, and for the macro definitions in the description
file.
If there is a definition on the command line for a macro name that
is also defined in the description file,
make
uses the command line definition and ignores
the definition in the description file.
Next,
make
looks at the options.
See
make(1)make
supports.
The
make
utility interprets the remaining command
line entries as the names of targets.
It processes the targets in left-to-right
order.
If there are no targets on the command line,
make
processes the first target named in the description file and then stops.
7.2 Description Files
The description file tells
make
how to build the target by defining what dependencies are involved
and what their relationships are to the other files in the procedure.
The
description file contains the following information:
Definitions of macros in the description file
One or more target names
Dependency file names that make up the target files
Commands that create the target files from the dependents
Any of the pseudotargets
.DEFAULT,
.IGNORE,
.PRECIOUS,
.SILENT,
or
.SUFFIXES.
These identifiers are called pseudotargets
because they are not real targets.
They are built-in names that
make
interprets in special ways.
For example, the
.SILENT
pseudotarget instructs
make
not to echo command lines as it runs them.
Do
not use any of these names for a real target.
See
make(1)
The
make
utility determines what files to create
to get an up-to-date copy of the target by checking the dates of the dependency
files.
If any dependency file was changed more recently than the target,
make
creates all the files that are affected by the change, including
the target.
In most cases, the description file is easy to write and does
not change often.
The
make
utility usually looks for a description
file named either
makefile
or
Makefile.
If you name the description file
makefile
or
Makefile
and are working in the directory containing that description
file, you enter the
make
command without any options or
arguments to bring the first target and its dependency files up to date, regardless
of the number of files that were changed since the last time
make
created the target file.
You can override the default file name
by using the
-f
option to the
make
utility to specify the name of the description file you want, as in the following
example:
% make -f my_makefile
This option lets you keep several description files in the same directory.
This section explains the description file:
Format of a description file entry (Section 7.2.1)
Using commands in a description file (Section 7.2.2)
Preventing the
make
utility from echoing
commands (Section 7.2.3)
Preventing the
make
utility from stopping
on errors (Section 7.2.4)
Defining default conditions (Section 7.2.5)
Preventing
make
from deleting files (Section 7.2.6)
Simple description file (Section 7.2.7)
Making the description file simpler (Section 7.2.8)
Defining macros (Section 7.2.9)
Using macros in a description file (Section 7.2.10)
Calling the
make
utility from a description
file (Section 7.2.11)
Internal macros (Section 7.2.12)
How the utility
make
uses environment variables
(Section 7.2.13)
Internal rules (Section 7.2.14)
Including other files (Section 7.2.15)
Testing description files (Section 7.2.16)
Description file (Section 7.2.17)
7.2.1 Format of a Description File Entry
The general format of a description file entry is as follows:
[target1 [ target2... ] ]
[:]
[
[:]
]
[
[dependent...]
]
[
[; ]
commands
]
[
[# ]
comment...
]
The items inside brackets are optional.
Targets and dependents are
file names (strings of letters, numbers, periods, and slashes).
The
make
command recognizes wildcard characters, such as asterisks
(*?
Because
make
uses the dollar sign
($make
macro.
(Macros are described
in
Section 7.2.9,
Section 7.2.10,
and
Section 7.2.12.)
To place comments in the description file, use a number sign (#make
utility ignores the number sign and all characters on the same line after
the number sign.
The
make
utility also ignores blank lines.
You can enter lines that are longer than the line width of the input
device by putting a backslash (\7.2.2 Using Commands in a Description File
A command is any string of characters,
except a number sign or a newline character.
Commands can appear after a
semicolon (;
When you define command sequences for the targets in the description file, either specify one command sequence for each target or specify separate command sequences for special sets of dependencies.
To use one command sequence for every use of the target, use a single
colon (:test, with a set of dependency files and a set of commands to create
the target:
test: dependency list1...
command list...
.
.
.
test: dependency list2...
As shown here, a target name can appear in several places in the description
file with different dependency lists, but there can be only one command list
associated with the target name.
The
make
utility finds
all the dependency lines for a given target and concatenates all their dependency
lists into a single list.
When any of the dependents have been changed,
make
can run the commands in the one command list to create the
target.
To specify more than one set of commands to create a particular target
file, enter more than one dependency definition.
Each dependency line must
have the target name followed by two colons (::make
uses if
any of the files in the dependency list changes.
For example, the following
lines define two separate processes to create the target file
test:
test:: dependency list1...
command list1...
.
.
.
test:: dependency list2...
command list2...
If any of the files in dependency
list1
changes,
make
runs command
list1; if any of the files
in dependency
list2
changes,
make
runs
command
list2.
To avoid conflicts, a given dependency file
cannot appear in both dependency
list1
and dependency
list2.
Note
Because
makeruns the commands on each command line independently of preceding or subsequent command lines, be careful when using certain commands (for example,cd). In the following example, thecdcommand has no effect on thecccommand that follows it:test: test.o cd /u/tom/newtest cc main.o subs.o -o test
To make the
cdcommand affect thecccommand, place both commands on the same line, separated by a semicolon. For example:test: test.o cd /u/tom/newtest; cc main.o subs.o -o test
You can simulate a multiline shell script by using backslashes on continued lines:
test: test.o cd /u/tom/newtest; \ cc main.o subs.o -o test
This example works exactly the same as the one immediately before it. Each line continued with a backslash (the
cdline in this example) must have a semicolon before the backslash.
7.2.3 Preventing the make Utility from Echoing Commands
To prevent
make
from echoing the commands that it is executing to standard
output, use any one of the following procedures:
Use the
-s
flag on the command line when
you enter the
make
command.
Put the pseudotarget name
.SILENT:
on a
line by itself in the description file.
See
Section 7.2
for an explanation of pseudotargets.
Put an at sign
(@make
should not
echo.
7.2.4 Preventing the make Utility from Stopping on Errors
The
make
utility usually stops if any command returns a nonzero status code
to indicate an error.
To prevent
make
from stopping on errors, use any
of the following procedures:
Use the
-i
flag on the command line when
you enter the
make
command.
Put the pseudotarget name
.IGNORE:
on a
line by itself in the description file.
See
Section 7.2
for an explanation of pseudotargets.
Put a hyphen (-make
should not stop on errors.
7.2.5 Defining Default Conditions
When
make
creates a target but cannot
find either explicit command lines or internal rules to create the file, it
looks at the description file for default conditions.
To define the commands
that
make
performs in this case, use the
.DEFAULT:
pseudotarget name in the description file, entering the default
command sequence as for any other target.
Use the
.DEFAULT:
pseudotarget for an error recovery
routine or for a general procedure to create all files in the program that
are not defined by an internal rule of the
make
utility.
7.2.6 Preventing make from Deleting Files
To prevent completion
of a build using potentially corrupted target files,
make
usually removes target files if an error is returned during the build.
To
prevent
make
from removing files when an error is detected,
use the
.PRECIOUS:
pseudotarget in the description file.
After the pseudotarget name, list the target names to be saved.
If you specify
the
-u
option on the command line,
make
does not remove any RCS files it checked out.
See
make(1)make
interacts with RCS.
7.2.7 Simple Description File
In
Example 7-1, a program named
prog
is made by compiling and loading three C language files:
x.c,
y.c, and
z.c.
The files
x.c
and
y.c
share some declarations in a file named
defs.
The
z.c
file does not share those declarations.
Example 7-1: A Simple Description File
# Make prog from 3 object files
prog: x.o y.o z.o
# Use the cc program to make prog
cc x.o y.o z.o -o prog
# Make x.o from 2 other files
x.o: x.c defs
# Use the cc program to make x.o
cc -c x.c
# Make y.o from 2 other files
y.o: y.c defs
# Use the cc program to make y.o
cc -c y.c
# Make z.o from z.c
z.o: z.c
# Use the cc program to make z.o
cc -c z.c
If this file is called
makefile, you can enter
the
make
command with no options or arguments to make an
up-to-date copy of
prog
after making changes to any of
the four source files
x.c,
y.c,
z.c, or
defs.
7.2.8 Making the Description File Simpler
To
make the description file simpler, use the internal rules of the
make
utility.
Using file system naming conventions,
make
knows that there are three
.c
files corresponding
to the needed
.o
files.
It also knows how to generate
an object from a source file (that is, issue a
cc -c
command).
By taking advantage of these internal rules, the description file becomes
the following:
# Make prog from 3 object files
prog: x.o y.o z.o
# Use the cc program to make prog
cc x.o y.o z.o -o prog
# Use the file defs and the appropriate .c file
# when making x.o and y.o
x.o y.o: defs
Section 7.2.14
describes
the internal rules used by
make.
7.2.9 Defining Macros
A macro is a name to use in place of one or more other names. It is a shorthand way of using the longer string of characters. You can define macros in the description file or on the command line. To define a macro in the description file, do the following:
Start a new line with the name of the macro.
Follow the name with an equal sign (=
To the right of the equal sign, enter the string of characters that the macro name represents. The string can contain blanks.
The macro definition can contain blanks before and after the equal sign
without affecting the result.
The macro definition cannot contain a colon
(:make
utility ignores leading and trailing blanks in the defining
string.
The following examples are macro definitions:
# Macro ABC has a value of "ls -la" ABC = ls -la # Macro LIBES has a null value LIBES = # Macro DIRECT includes the definition of macro ROOT # The expanded value of DIRECT is "/usr/home/fred" ROOT = /usr/home DIRECT = $(ROOT)/fred
The
DIRECT
macro
in this example uses another definition as part of its own definition.
See
Section 7.2.10
for instructions on using macros.
To define
a macro on a command line, follow the same syntax as for defining macros in
the description file, but include all of your macro definitions on the same
line.
When you define a macro with blanks from the command line, enclose
the definition in quotation marks ("name = definition"7.2.10 Using Macros in a Description File
After
you define a macro in a description file, refer to the macro's value in the
description file by putting a dollar sign ($
$(CFLAGS)
${xy}
$Z
$(Z)
The effect of the last two examples is identical.
7.2.10.1 Macro Substitution
You can substitute a different value for part or all of a macro's defined value. The three forms of macro substitution are as follows:
The first form replaces every occurrence of string1 in the defined value of MACRO with string2:
[$(MACRO:string1=string2)]
For example:
# Define macro MAC1 MAC1 = xxx yyy zzz
.
.
.
# Evaluate MAC1 project: @ echo $(MAC1:yyy=abc)
When you run
make
with this description file,
make
substitutes
abc
for the occurrence of
yyy, and displays the
following line:
xxx abc zzz
The second form applies a substitution to each word in the defined value. The location parameter specifies what portion of the word is to be replaced with string:
[$(MACRO/location/string)]
The location parameter is restricted to the following values:
Circumflex (^
# Define macro MAC1 MAC1 = abc def ghi
.
.
.
# Evaluate MAC1 project: @ echo $(MAC1/^/xyz)
When you run
make
with this description file,
make
adds
xyz
to the beginning of each defined word and displays the following line:
xyzabc xyzdef xyzghi
Asterisk
(*
# Define macro MAC1 MAC1 = abc def ghi
.
.
.
# Evaluate MAC1 project: @ echo $(MAC1/*/xyz)
When you run
make
with this description file,
make
substitutes
xyz
for each defined word and displays the following line:
xyz xyz xyz
With the asterisk, you can use an
ampersand
(&
# Define macro MAC1 MAC1 = abc def ghi
.
.
.
# Evaluate MAC1 project: @ echo $(MAC1/*/x&z)
When you run
make
with this description file,
make
substitutes
x&z
for each defined word, interpolating the defined word for
the ampersand, and displays the following line:
xabcz xdefz xghiz
Dollar sign ($
# Define macro MAC1 MAC1 = abc def ghi
.
.
.
# Evaluate MAC1 project: @ echo $(MAC1/$/xyz)
When you run
make
with this description file,
make
appends
xyz
to the end of each defined word and displays the following line:
abcxyz defxyz ghixyz
The third form makes one of two possible substitutions depending on whether MACRO is defined:
[$(MACRO?string1:string2)]
If MACRO is defined, string1 is substituted for the entire defined value. If MACRO is not defined, string2 is used. For example:
# Define macro MAC1 MAC1 = abc def ghi
.
.
.
# Evaluate MAC1 and MAC2. MAC2 is not defined. project: @ echo $(MAC1?uvw:xyz) @ echo $(MAC2?123:456)
When you run
make
with this description file,
make
substitutes
uvw
for the value of
MAC1
and
456
for the undefined
MAC2, and displays the following lines:
uvw 456
The first two forms of substitution produce a null string
if
MACRO
is undefined.
7.2.10.2 Conditional Macros
The value of a macro can be assigned based on a preexisting condition. This type of macro is a conditional macro. You cannot define conditional macros on the command line; all conditional macro definitions must be in the description file. The syntax of the conditional macro is as follows:
[target:=MACRO = string]
The macro is assigned the value of the string if the specified
target is the current target of the
make
command.
Otherwise,
the macro's value is null.
The following description file uses a conditional
substitution for
MAC1:
# Define the conditional macro MAC1 target2:=MAC1 = xxx yyy xxxyyy
.
.
.
#list targets and command lines # target1:;@echo $(MAC1) target2:;@echo $(MAC1)
When you run
make
with this description file, you
get the following results:
% make target1 % make target2 xxx yyy xxxyyy
7.2.11 Calling the make Utility from a Description File
You can nest calls to the
make
utility within a
make
description file by including the
$(MAKE)
macro in one of the command lines in the file.
If this macro is present,
make
executes another copy of
make, even if the
-n
option is set.
See
Section 7.2.16
for a description of the
-n
option.
7.2.12 Internal Macros
The
make
utility has built-in macro definitions for use in the description
file.
These macros help specify variables in the description file.
The
make
utility replaces the macros with the values indicated in
Table 7-1.
Table 7-1: Internal make Macros
| Macro | Valuex |
$@ |
The name of the current target file |
$$@ |
The target names on the dependency line |
$? |
The names of the dependency files that have changed more recently than the target |
$< |
The name of the out-of-date file that caused a target file to be created |
$* |
The name of the current dependency file without the suffix |
Each of these macros resolves to a single file name at the time
make
is actually using it.
You can modify the interpretation of
any of these macros by using a
D
suffix to indicate that
you want only the directory portion of the name.
For example, if the current
target is
/u/tom/bin/fred, the
$(@D)
macro returns only the
/u/tom/bin
portion of the name.
Similarly, an
F
suffix returns only the file name portion.
For example, the
$(@F)
macro returns
fred
if given the same target.
All internal macros except the
$?
macro can take the
D
or
F
suffix.
Before using any internal macros on a distributed file system, you must
ensure that the system clocks show the same date and time for all nodes that
contain files for
make
to process.
The
make
utility replaces these symbols only when
it runs commands from the description file to create the target file.
The
following sections explain these macros in more detail.
7.2.12.1 Internal Target File Name Macro
The
make
utility substitutes the full name of the current target for
every occurrence of the
$@
macro in the command sequence for building
the target.
The replacement is made before running the command.
For example:
/u/tom/bin/test: test.o
cc test.o -o $@
This example produces an executable
file named
/u/tom/bin/test.
7.2.12.2 Internal Label Name Macro
If the
$$@
macro is used on the right side of the colon on a dependency
line in a description file,
make
replaces this symbol with
the label name that is on the left side of the colon in the dependency line.
This name could be a target name or the name of another macro.
For example:
cat: $$@.c
The
make
utility
interprets this line as follows:
cat: cat.c
Use this macro to build a group of files, each of which has only one source file. For example, to maintain a directory of system commands, use a description file like the following:
# Define macro CMDS as a series of command names
CMDS = cat dd echo date cc cmp comm ar ld chown
# Each command depends on a .c file
$(CMDS): $$@.c
# Create the new command set by compiling the out of
# date files ($?) to the current target file name ($@)
cc -O $? -o $@
The
make
utility changes the
$$(@F)
macro to the file part of
$@
when it runs.
For example,
you could use this symbol when maintaining the
usr/include
directory while using a description file in another directory.
That description
file would look like the following example:
# Define directory name macro INCDIR
INCDIR = /usr/include
# Define a group of files in the directory
# with the macro name INCLUDES
INCLUDES = \
$(INCDIR)/stdio.h \
$(INCDIR)/pwd.h \
$(INCDIR)/dir.h \
$(INCDIR)/a.out.h
# Each file in the list depends on a file
# of the same name in the current directory
$(INCLUDES): $$(@F)
# Copy the younger files from the current
# directory to /usr/include
cp $? $@
# Set the target files to read only status
chmod 0444 $@
This description file creates a file
in the
/usr/include
directory when the corresponding file
in the current directory has been changed.
7.2.12.3 Internal Younger Files Macro
If the
$?
macro is in the command
sequence in the description file,
make
replaces the symbol
with a list of dependency files that have been changed since the target file
was last changed.
7.2.12.4 Internal First Out-of-Date File Macro
If the
$<
macro is in the command
sequence in the description file,
make
replaces the macro
with the name of the first file that started the file creation.
This file
name is the name of the specific dependency file that was out of date with
the target file and therefore caused
make
to create the
target file again.
This is different from the
$?
macro,
which returns a complete list of younger files.
The
make
utility replaces this symbol only when it
runs commands from its internal rules or from the
.DEFAULT:
list.
The symbol has no effect in an explicitly stated command line.
7.2.12.5 Internal Current File Name Prefix Macro
If the
$*
macro is in the command sequence in the description file,
make
replaces the symbol with the file name part (without the suffix) of the dependency
file that
make
is currently using to generate the target
file.
For example, if
make
is building the target
test.c, the
$*
symbol represents the file name
test.
The
make
utility replaces this symbol only when it
runs commands from its internal rules or from the
.DEFAULT:
list.
The symbol has no effect in an explicitly stated command line.
7.2.13 How make Uses Environment Variables
Each time
make
runs, it reads the current environment variables and adds them
to its defined macros.
In addition, it creates a new macro called
MAKEFLAGS.
This macro is a collection of all the options that were entered
on the command line.
Command line options and assignments in the description
file also can change the value of the
MAKEFLAGS
macro.
When
make
starts another process, it exports
MAKEFLAGS
to that process.
See
Section 7.2.16
for a discussion of how the
MAKEFLAGS
macro affects recursive
make
processes.
The
make
utility assigns macro definitions in the
following order with later steps overriding earlier ones where there are conflicts:
Reads the
MAKEFLAGS
environment variable
to set options specified by the variable.
If
MAKEFLAGS
is not present or is null,
make
sets its internal
MAKEFLAGS
macro to the null string.
Otherwise,
make
assumes that each letter in
MAKEFLAGS
is an input option.
The
make
utility uses these options (except for
-f,
-p, and
-r)
to determine its operating conditions.
Reads and sets the input flags from the command line.
Any
options specified explicitly on the command line are added to the settings
from the
MAKEFLAGS
environment variable.
Reads macro definitions from the command line. These definitions override any definitions for the same names in the description file.
Reads the internal macro definitions.
Reads the environment, including the
MAKEFLAGS
macro.
The
make
utility treats all environment variables
as macro definitions and passes them to shells it invokes to execute commands.
The
make
utility has a set of internal rules that it uses to determine how
to build a target.
You can override these rules by invoking
make
with the
-r
option; in
this case, you must supply any rules that are required to build the targets
in your description file.
The internal rules contain a list of file name
suffixes defined using the pseudotarget
.SUFFIXES:, along
with the rules that tell
make
how to create a file with
one suffix from a file with another suffix.
To see the complete list of conversions
supported by
make's internal rules, run the following command:
% make -p | more
If you do not change the list by default,
make
understands
the following suffixes:
| Suffix | File Type |
.o |
Object file |
.c |
C source file |
.e |
efl
source file |
.r |
Ratfor source file |
.f
or
.F |
FORTRAN source file |
.s |
Assembler source file |
.y |
yacc
C source grammar |
.yr |
yacc
Ratfor source grammar |
.ye |
yacc efl
source grammar |
.l |
lex
source grammar |
.out |
Executable file |
.p |
Pascal source file |
.sh |
Bourne shell script |
.csh |
C shell script |
.h |
C header file |
You can add suffixes
to this list by including a
.SUFFIXES:
line in the description
file with one or more space-separated suffixes.
For example, the following
line adds the suffixes
.f77
and
.ksh
to the existing list.
For example:
.SUFFIXES: .f77 .ksh
To erase
make's default list of suffixes,
include a
.SUFFIXES:
line with no names on it.
You can replace the default list with
a completely new list by using first an empty list and then your new list:
.SUFFIXES: .SUFFIXES: .o .c .p .sh .ksh .csh
Because
make
looks at the suffixes list in left-to-right order, the order of the entries
is important.
The preceding example ensures that
make
will look first for an object file, then a C source file, and so on.
The
make
utility uses the first entry in the list
that satisfies the following two requirements:
The entry matches input and output suffix requirements.
The entry has a rule assigned to it.
If you add suffixes to the list that
make
recognizes,
you must provide rules that describe how to build a target from its dependents.
A rule looks like a dependency line and the corresponding series of commands.
The
make
utility creates the name of the rule from the two suffixes of the files that
the rule defines.
For example, the name of the rule to transform a
.r
file to a
.o
file is
.r.o.
Example 7-2
illustrates a portion of the standard default
rules file.
Example 7-2: Default Rules File
# Create a .o file from a .c
# file with the cc program
.c.o
$(CC) $(CFLAGS) -c $<
# Create a .o file from either a
# .e , a .r , or a .f
# file with the efl compiler
$(EC) $(RFLAGS) $(EFLAGS) $(FFLAGS) -c $<
# Create a .o file from
# a .s file with the assembler
.s.o:
$(AS) -o $@ $<
.y.o:
# Use yacc to create an intermediate file
$(YACC) $(YFLAGS) $<
# Use cc compiler
$(CC) $(CFLAGS) -c y.tab.c
# Erase the intermediate file
rm y.tab.c
# Move to target file
mv y.tab.o $@
.y.c:
# Use yacc to create an intermediate file
$(YACC) $(YFLAGS) $<
# Move to target file
mv y.tab.c $@
The
make
utility also has a set of single suffix rules to create targets
with no suffixes, such as command files.
The
make
utility
has rules to change the following source files with a suffix to object files
without a suffix:
| Suffix | Source File Type |
.c |
From a C language source file |
.sh |
From a shell file |
For example, to maintain a program like
cat
if
all of the needed files are in the current directory, enter the following
command:
% make cat
7.2.14.2 Overriding Built-In make Macros
The
make
utility uses macro definitions in its internal
rules.
To change these macro definitions, enter new definitions for those
macros on the command line or in the description file.
For commands and language
processors, the
make
utility uses the following macro names:
| Command or Function | Command Macro | Command Options or Other Macros |
Archive program (ar) |
AR | ARFLAGS |
| Archive table of contents creation | RANLIB | |
| Assembler | AS | ASFLAGS |
| C Compiler | CC | CFLAGS |
| C libraries | LOADLIBS | |
| RCS checkout | CO | COFLAGS |
The copy command (cp) |
CP | CPFLAGS |
efl
compiler |
EC | EFLAGS |
Linker command (ld) |
LD | LDFLAGS |
The
lex
command |
LEX | LFLAGS |
The
lint
command |
LINT | LINTFLAGS |
The
make
command |
MAKE | |
Recursive
make
calling
flags |
MAKEFLAGS | |
The
mv
command |
MV | MVFLAGS |
The
pc
command |
PC | PFLAGS |
The
f77
compiler |
RC | FFLAGS |
| Ratfor compiler flags | RFLAGS | |
The
rm
command |
RM | RMFLAGS |
| For locating files related to dependency | VPATH | |
The
yacc
command |
YACC | YFLAGS |
The
yacc -e
command |
YACCE | YFLAGS |
The
yacc -r
command |
YACCR | YFLAGS |
For example, the following command runs
make, substituting
the
newcc
program in place of the previously defined C
language compiler:
% make CC=newcc
Similarly, the following command tells
make
to optimize the final object code produced by the C language
compiler.
% make "CFLAGS=-O"
To look at the internal rules that
make
uses, enter
the following command from the Bourne shell:
$ make -fp -< /dev/null 2>/dev/null
The output appears on the standard output.
7.2.15 Including Other Files
You can include files in addition
to the current description file by using the word
include
as the first word on any line in the description file.
Follow the word with
a blank or a tab and then the set of file names for
make
to include in the operation.
For example:
include /u/tom/temp /u/tom/sample
7.2.16 Testing Description Files
To test a description file, run
make
with the
-n
command option.
This option instructs
make
to echo command lines without executing them.
Even commands preceded by at
signs (@make
would execute it.
When the
-n
option is in effect, the
$(MAKE)
macro, unlike all other commands, is
actually executed.
If the description file includes an instance of the
$(MAKE)
macro,
make
calls the new copy of
make
with the
MAKEFLAGS
macro's value set to
the list of options, including
-n, that you entered on
the command line.
The new copy of
make
observes that the
-n
option is set, and it bypasses command execution in the same
way as the copy that called it.
You can test a set of description files that
use recursive calls to
make
by entering a single
make
command.
7.2.17 Description File
Example 7-3
shows the description file that maintains the
make
utility.
The source code for
make
is contained
in a number of C language source files and a
yacc
grammar
file.
For more information on
yacc, see
Chapter 4.
Example 7-3: The makefile for the make Utility
# Description file for the Make program
# Macro def: send to be printed
P = lpr
# Macro def: source file names used
FILES = Makefile version.c defs main.c
doname.c misc.c files.c
dosy.c gram.y lex.c gcos.c
# Macro def: object file names used
OBJECTS = version.o main.o doname.o \
misc.o files.o dosys.o gram.o
# Macro def: lint program and flags
LINT = lint -p
# Macro def: C compiler flags
CFLAGS = -O
# make depends on the files specified
# in the OBJECTS macro definition
make: $(OBJECTS)
# Build make with the cc program
cc $(CFLAGS) $(OBJECTS) -o make
# Show the file sizes
size make
# The object files depend on a file
# named defs
$(OBJECTS): defs
# The file gram.o depends on lex.c
# uses internal rules to build gram.o
gram.o: lex.c
# Clean up the intermediate files
clean:
rm *.o gram.c
# Copy the newly created program
# to /usr/bin and deletes the program
# from the current directory
install:
cp make /usr/bin/make ; rm make
# Empty file ''print'' depends on the
# files included in the macro FILES
print: $(FILES)
# Print the recently changed files
lpr $?
# Change the date on the empty file,
# print, to show the date of the last
# printing
touch print
# Check the date of the old
# file against the date
# of the newly created file
test:
make -dp | grep -v TIME >1zap
/usr/bin/make -dp | grep -v TIME >2zap
diff 1zap 2zap
rm 1zap 2zap
# The program, lint, depends on the
# files that are listed
lint: dosys.c doname.c files.c main.c misc.c \
version.c gram.c
# Run lint on the files listed
# LINT is an internal macro
$(LINT) dosys. doname.c files.c main.c \
misc.c version.c gram.c
rm gram.c
# Archive the files that build make
arch:
ar uv /sys/source/s2/make.a $(FILES)