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.
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:
The Digital UNIX system provides several versions of the make command; this chapter describes the default version, make(1). The other versions, both of which offer features not 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 respective reference pages for further information.
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:
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:
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.
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:
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 normally 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.
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.
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, the cd command has no effect on the cc command that follows it:
test: test.o cd /u/tom/newtest cc main.o subs.o -o test
To make the cd command affect the cc 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.
To prevent make from echoing the commands that it is executing to standard output, use any one of the following procedures:
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:
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.
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.
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.
# 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.
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.
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:
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 use 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.
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.
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:
$(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
$(MACRO/location/string)
The location parameter is restricted to the following values:
# 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
# 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
# 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
$(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.
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
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.
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.
Macro | Value |
$@ | 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.
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.
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.
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.
If the $< macro is in the command sequence in the description file, make replaces the symbol with the name of the file that started the file creation. The 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. The difference between this symbol and the $? symbol, 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.
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.
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:
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:
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.
# 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
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 | Command Options |
Macro | 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.
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
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.
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.
# 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)