The make utility is used in virtually all software development environments, including UNIX, Windows, and other operating systems. The program might be named make, nmake, mk, or gmake, or might be buried behind the "Build" button of an IDE (Integrated Development Environment), but it is virtually always there.
This web page introduces some basic concepts common to most implementations of make, but many of the details here are specific to the version used in our lab, which comes from the GNU project at MIT. There is a Documentation and References section below that you can consult for more information than what is given here.
The basic idea of make is that it can be used to automate common tasks efficiently. The tasks you automate almost always involve manipulating files by issuing commands. (The make utility is so general that just about every statement about it has to be qualified with phrases like "almost always," "usually," or "normally." In the interest of simplicity, I'll skip some of those qualifiers in what follows.)
Often, you supply one or more targets on the command line, which tell make what it is you want it to make. Targets are described below.
To the right of the make command name and to the left of any
targets you might specify on the command line, you may also provide
values for make "macros", using name=value
syntax.
(Macros are also called make variables), and are
described in more detail below.
For example, if you want make to use "-r1.3" for the value of its COFLAGS macro when making the target named "myprog," you could use the following make command line:
make COFLAGS="-r1.3" myprog
Most of make's implicit rules are based on filename pattern matching. For example, GNU make knows how to do the following file operations using its pattern matching rules:
.cc
or
.c
to produce an executable file with the same basename
as the .cc
or .c
file.
.cc
or .c
file to produce the
corresponding .o
file.
There is a web page with a fuller description of these implicit rules . There is also information about the the implicit rule for linking below. You can find the complete list of implicit rules that GNU make knows about in the info pages or make manual, referenced in theDocumentation and References section below.
Makefile
in the
current directory. Makefiles may contain comments (beginning with a
'#' character) and macro (variable) definitions as well as Explicit
Rules.An explicit rule has the following format:
<target> : [<dependency list>] [<command list>]The <target> is usually the name of a file that you want make to build, but it can be a "phony" name that is used just to get make to execute some commands for you. You can specify the rules that you want make to process by listing the target parts of those rules on the make command line, but if you don't give any targets on the command line, make will process the first rule it finds in the Makefile. If there is no Makefile in the current directory (even after make tries its implicit rule for obtaining it from an RCS or SCCS database), you must give a target on the make command line, and make will try to build the target using only its implicit rules.
The first thing make does once it has selected a rule to process is to use implicit or explicit rules to bring all the files listed in the <dependency list> "up to date." Once all the files in the dependency list are up to date (see below), make executes each of the commands in the <command list> for the rule. If the dependency list is empty, make executes the command list for the rule unconditionally.
In order to be "up to date" a file must be present, and it must have
been modified more recently than any files on its own dependency list.
A common example of this that you will encounter is when make
uses one of its implicit rules to build a .o
file from the
corresponding .cc
file: the target (the .o
file) must have a more recent modification time than the file it
depends on (the corresponding .cc
file). If it doesn't,
it means that you have edited the .cc
file since it was last
compiled, so make automatically executes a g++ command to
compile the .cc
file with the -c
command line
option.
Once all the files in the dependency list for a rule are up to date, make executes each command in the command list, if there are any. It doesn't matter if the commands actually build a file with the same name as the target, they just get executed.
Note on Implicit Linking. Normally, no commands get executed unless a rule includes at least one command in its command list, but there is an important exception to this: If rule consists of just a target with a list of .o files for its dependencies, make will bring all the .o files up to date using its implicit rules for compilation, and then will use another implicit rule to link all the .o files together to produce an executable file with the same name as the target. One of the .o files in the dependency list must have the same basename as the target for this rule to work. By the time you are finished with this web page, you should see that the line,
$(EXEC) : $(OBJS)in the Skeleton Makefile is an example of how this implicit rule can be used.
There is a syntax rule that says that each command in the command list
has to start with a <tab>
character, so that
make can tell where the list ends (by coming to a line that does
not start with a <tab>
). If a command is too long
to fit one one line, it can be continued by putting a '\' character at
the end of lines that are to be continued. Commands that are continued
have to start with a <tab>
on the first line, but
any additional lines don't have to have one.
Note: Every command that make executes, whether because
of an explicit or implicit rule, is executed by its own shell, which is
the Bourne shell (sh) by default. One implication of this is
that features that are specific to csh or tcsh (like
'~/
' representing your home directory) won't work in the
commands in a rule's command list. Also, setting an environment
variable in one command will have no effect during successive commands
because each invocation of a shell maintains its own environment list.
You can use environment variables that were already set when
make was started, though, (like $HOME
to represent
your home directory), but you have to make them look like make
macros, which will be covered in the next section.
Summary: Every rule has a target and either a dependency list or a command list (or both). A missing dependency list means to execute the command list unconditionally. For example, this rule causes the command, "make clean" to delete files that have been checked out of RCS without being locked, and then to remove some unwanted files:
clean :<tab>
rcsclean<tab>
rm core *.o *.bak
(The name "clean" is conventionally used as the target for the rule in a Makefile that removes all files from the project directory that can be regenerated either by checking them out of the RCS database or by rebuilding them using make rules. See the Skeleton Makefile web page for the definition of this and other "standard" rules.) |
A missing command list means that bringing the dependencies up to date
is all the user wants to do. For example, the rule below causes
make to process the rule with "depend" as its target (another
"standard" rule), and then to build "myprog" (perhaps by using an
implicit rule to compile and link myprog.cc
, or perhaps by
executing an explict rule for "myprog" that appears elsewhere in the
Makefile):
all : depend myprog(The name "all" is conventionally used as the target for the rule in a Makefile that names all the other targets except "clean.")
A macro is just the name of a string. Wherever make finds a reference to a macro, which consists of a dollar sign followed by the macro name in parantheses, it substitutes the string for the reference to the name. Here are examples of a macro definition and a macro reference from a Makefile:
MYFLAGS = These words are the value of the macro named "MYFLAGS" default : <tab> echo $(MYFLAGS)Now, the command "make default" generates this output:
% make default echo These words are the value of the macro named "MYFLAGS" These words are the value of the macro named MYFLAGSThe first output line is displayed by make as it shows you the command it is going to execute, and the second output line is the result of executing the echo command.
(The name "default" is conventionally used as the target for the first rule in a Makefile, so the commands "make default" and just plain "make" will have the same effect.)
You can define a macro in the Makefile as in the previous example, on the make command line, or by setting an environment variable. Defining a macro on the command line overrides both the other two methods:
% setenv MYFLAGS good-bye % make MYFLAGS=hello default echo hello helloNormally, defining a macro in the Makefile overrides defining an environment variable, but this can be reversed with the
-e
option on the make command line:
% make -e default echo good-bye goodbye % make default echo These words are the value of the macro named "MYFLAGS" These words are the value of the macro named MYFLAGSIt is perfectly all right to reference a make macro that isn't defined anywhere. In this case, make will silently substitute an empty string for the reference.
CXXFLAGS
| Used for g++ commands |
CFLAGS
| Used for gcc commands |
COFLAGS
| Used for RCS co commands |
LDFLAGS
| Used for g++ or gcc commands that involve linking, normally to specify linker options. |
LDLIBS or LOADLIBES
| Used for g++ or gcc commands that involve linking, normally to specify library names. |
NOTE: Make also uses macros to name the commands that it
generates for its implicit rules. In particular, it uses the same
macro name, CC
, in its implict rules for compiling
.c
files and in its implict rule for linking
.o
files. This macro name is different from
CXX
, which is used in its implicit rule for compiling
.cc
files. This convention "works" because the gcc
and g++ compiler drivers both use the same linker (ld)
when linking .o
files.
Thus, in the Skeleton Makefile the rule,
$(EXEC) : $(OBJS)says to be sure all the .o files are "up to date," which will cause make to using its implicit rules for compiling .cc files (and/or .c files) into .o files. It will generate the appropriate compiler driver command, gcc or g++ for each file it has to compile, based on whether the source file name ends with .c or .cc respectively. Then, regardless of what compiler driver was used to produce the .o files, make will use its single implicit rule for linking .o files to generate a gcc command to produce the executable file.
.o
files that will be used in
a rule that links the files into an executable file, and that you also
need a list of the corresponding .cc
files that will be
passed to a makedepend command. If you generate one list from
the other, you eliminate the chance that the two lists will get out of
sync with each other. Here is an example that shows how to do it:
MY_SRCS = my_main.cc my_sub1.cc my_sub2.cc MY_SRCS = $(MY_OBJS:.cc=.o)In this example,
MY_OBJS
is derived from
MY_SRCS
by substituting the suffix .o
for all
occurrences of the suffix .cc
. Later, both lists can be
updated by editing just the definition of MY_SRCS
.
Note: there must be no spaces inside the parentheses.
There is a man page for make availalable on any Unix system with make installed on it, but the most complete documentation is in GNU's info format. Type "info make" to get started on that. Unfortunately, info is hard to get used to. It does web-like hypertext without a mouse.
There is also a full manual on GNU make that contains all the information you can get from info. There is an HTML version of the manual available from ftp.gnu.org, and there is a PDF version of it here.
There is a small book on make called "Managing Projects with make, Second Edition", written by Andrew Oram and Steve Talbott, and published by O'Reilly and Associates. It's highly recommended for a good survey of the features available in the various implementations of make that are available.
Christopher Vickery
Computer Science Department
Queens College
of CUNY