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:
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).
The other versions, both of which offer features provided by
make
(1),
are
make
(1u)
and
make
(1p).
In addition to its extended feature set, the
make
(1p)
version is POSIX compliant.
The
make
(1)
and
make
(1u)
versions are included in the base operating
system subsets.
The
make
(1p)
version is included in the "Software Development
Environment (Software Development)" subset.
Refer to the
make
(1),
make
(1u)
and
make
(1p)
reference pages
for further information.
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.
Refer to the
make
(1)
reference page for a complete list of the options that
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.
Refer to the
make
(1)
reference page for additional information on pseudotargets.
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 desired description file, 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:
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
( *
) and question
marks
( ?
).
Each line in the description file that contains a target name is called a
dependency line.
The dependency line is followed by one or more command lines
that specify the process steps to create the target.
Because
make
uses the dollar sign
( $
) to designate a macro, you
must not use this character in file names of targets and dependencies.
Similarly,
do not use the dollar sign in commands in the description file unless you
are referring to a defined
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 ( #
) to begin the comment text.
The
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 ( \
) at the
end of the line that is to be continued.
Do not extend comment lines in this
way; begin each new comment line with its own number sign.
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 ( ;
) on a dependency line or on
lines immediately following a dependency line.
Each command line after the
dependency line must begin with a single tab character.
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 ( :
) following the target name on
the dependency line.
For example, the following lines define a target,
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 ( ::
),
a dependency list, and a command list that
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
make
runs 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, thecd
command has no effect on thecc
command that follows it:test: test.o cd /u/tom/newtest cc main.o subs.o -o testTo make the
cd
command affect thecc
command, 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 testYou 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 testThis example works exactly the same as the one immediately before it. Each line continued with a backslash (the
cd
line 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
( @
) in the first character position (after the tab) of each
command line in the description file that
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 ( -
) in the
first character position (after the tab) of each command line in the description
file where
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 the
make
(1)
reference page
for more information on how
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
( :
) or a tab before the equal sign.
The
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"
).
Without the quotation marks, the shell interprets the blanks as parameter
separators and not as part of the macro.
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 ( $
)
before the name of the macro.
If the macro name is longer than one character,
put parentheses or braces around it, as illustrated by the following examples:
$(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 ( ^
) - The
string
value is
added as a prefix to each defined word.
For example:
# 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
( *
) - The
string
value replaces
all of each defined word.
For example:
# 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
( &
)
in the
string
value.
The ampersand represents
the defined word that is being substituted for, and it causes that word to
be interpolated in the result.
For example:
# 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 ( $
) - The
string
value is
appended to each defined word.
For example:
# 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 can also 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 ( @
) are echoed so that you can see
the entire process as
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)