makepp tries to be extremely compatible with GNU make, so almost everything that GNU make supports in its makefile is supported. If you're not familiar with writing makefiles, you'll want to read the tutorial before reading this file.
Every nonblank line in the makefile is either a comment, a variable assignment, part of a rule, a conditional, or a statement.
include
or begin_perl
.
include
load_makefile
perl_begin
and perl_end
repository
sub
"'\:*%
, then makepp may be confused unless you
quote them.
$(VARIABLE)
is actually used somewhere.
Thus, if you do the following:
X = 1 Y = $(X) X = 2Then
$(Y)
later in the makefile will evaluate to "2".
Leading and trailing whitespace around the text string is
stripped. If you need to control the whitespace in a variable,
you must (currently) disable rc-style substitution using the
--norc-substitution
command line option, and then use a syntax like this:
null = T = -o $(null)
When you do this, the variable T
contains
-o
followed by a space.
X := 1 Y := $(X) X := 2then
$(Y)
later in the makefile will evaluate to "1" since
that's what $(X)
was when $(Y)
was
defined. The same warnings about leading and trailing
whitespace apply to this syntax as well.
Makepp's variable substitution rules are similar to those
of other makes, but somewhat more powerful. $(CC)
or
${CC}
both represent the value of the variable CC. If
you need a literal dollar sign, put in a double dollar sign
($$
).
By default, makepp uses rc-style substitution (so called because it was pioneered by the rc shell). This is best illustrated by an example:
MODULES = a b c d mylib.a : module_dir/$(MODULES).o $(OTHER_OBJECTS) $(CXX) $(dependencies) -o $(target)
The prefix module_dir/
is prepended to each word in
MODULES, and the suffix .o
is appended to each word.
Makepp also supports substitution references. A
substitution reference has the form $(VAR:A=B)
, where
A is a pattern to match and B is a pattern to replace it with.
For example:
source_files = a.c b.c c.c d.c object_files = $(source_files:%.c=%.o)
will set $(object_files)
to
a.o b.o c.o d.o
. The %
is
a special character matches any arbitrary string. Substitution
references are an abbreviation for the
patsubst
function.
If rc-style substitution gets in the way, or if you need to have
leading or trailing whitespace in your make variables, then you
can turn off rc-style substitution with the --norc-substitution
command line option.
makepp supports most of the automatic variables that other
versions of make use. In addition, it has less cryptic, longer
names for most of them that you can use instead. (For legacy
makefiles that redefine these names, the definition in the makefile
overrides the default meaning. For example, if you say
"target = abc
" in your makefile, then
$(target)
will always expand to abc
, and
will no longer be equivalent to $@
.)
$(target)
or $(output)
or $@
$(targets)
or $(outputs)
$(target)
unless there is more than one target.
$(dependency)
or $(input)
or $<
$(dependencies)
or $(inputs)
or $^
.h
files discovered by scanning for includes.
$(sorted_dependencies)
or
$(sorted_inputs)
or $+
$(sort $(inputs))
.
$?
$+
).
This variable has no long name because its use is highly discouraged.
$(stem)
or $*
$(basename $(input))
.
$(foreach)
foreach
clause. See
below for more details on
foreach
.
Any expression of the format
$(name arg1 arg2 arg3)
or
$(name)
where name
is not the name of a
variable, is interpreted as a function call. The name may contain
letters, underscores, or hyphens; to avoid confusion, you may use
hyphens or underscores interchangeably, since internally hyphens are
converted to underscores. Evaluating such an expression simply
invokes a perl subroutine. You can define perl subroutines to do
whatever you like. See the sub
statement and the section on extending makepp for more
details.
makepp has a number of builtin functions which may be useful. It supports almost all of GNU make's textual functions (see GNU make's documentation for details), and some of its own. The most useful functions are:
absolute-filename
files)
$(absolute-filename xyz.c)
might return
/usr/src/our_project/subdir/xyz.c
.
basename
filenames)
$(basename myfile/version-1.0-module.c)
is
myfile/version-1.0-module
filter
patterns, words)
%
character, which means to match any string at
that point.
filter-out
patterns, words)
%
character, which means to match any string at
that point.
notdir
filenames)
only-targets
filenames)
.PHONY: clean clean: rm -f $(only_targets *)
Now if you type makepp clean
, it will delete
everything it knows how to build.
Note that this refers only to files that are known to be
targets at the time you invoke
only-targets
. If only-targets
appears in the dependencies or actions of a rule, then all
possible targets will be known. If you evaluate try to
evaluate it earlier in the makefile with a :=
variable like this:
ALL_TARGETS := $(only_targets *) target1: dependency1 actions target2: dependency2 actions
then only_targets
will not know about the
subsequent rules.
Similarly, only_targets
doesn't know about
targets produced in makefiles that are loaded with recursive
make.
only-nontargets
filenames)
.PHONY: distribution distribution: mkdir our_product-$(VERSION) cp $(filter-out %~, $(only_nontargets *)) our_product-$(VERSION) tar cf - our_product-$(VERSION) | gzip -9c > our_product-$(VERSION).tar.gz
In this case, the $(only_nontargets *)
returns
every file in the current directory that is not a target of
some rule. The $(filter-out %~, ...)
removes
editor backups.
Similar to only-targets
(see above),
only-nontargets
only knows about targets that have
been defined already. This is only a problem if you use it to
define variables with the :=
assignment.
patsubst
pattern, substitute, words)
%
character matches any string. This is best
illustrated by an example:
OBJS = $(patsubst %.c, object_dir/%.o, $(C_SOURCES))takes every file in C_SOURCES and returns the name of an object file in object_dir. Sometimes it is more concise to use a substitution reference, e.g., the above could have been written as
OBJS = $(C_SOURCES:%.c=object_dir/%.o)
phony
words)
$(phony all): my_program $(phony clean): rm -f *.o my_program
You can also declare one or more targets as phony with a line like this anywhere in your makefile:
.PHONY: all clean
print
text)
XYZ := $(print $(patsubst %.c, %o, $(SOURCE_FILES)))will print out the result of the
patsubst
call.
XYZ := $(patsubst %.c, %o, $(print $(SOURCE_FILES)))will print out the last argument to the
patsubst
call.
shell
shell-command)
makepp also supports many other, less useful functions
that GNU make has (see the GNU make documentation for details,
because I don't feel like typing it in now). (The only ones it does
not support are origin
, call
,
error
, and warning
.) These are intended
mainly to support existing makefiles; it's very easy to write your own functions in perl,
or to put perl code to manipulate
variables directly in your makefile, so you can do any kind of
manipulation even if one of these built-in functions isn't
adequate.
A rule is what tells makepp how to build a file or a class of files. Makepp supports the same rule syntax as other makes, plus some additions of its own.
target1 target2: dependency1 dependency2 ... actions to be performed
This syntax specifies that in order to make either target1 or target2, all the files dependency1, dependency2, etc., must already have been made. Then the given actions are executed by the shell to make the targets. Unlike traditional makes, makepp usually assumes that one invocation of the action makes all of the targets (unless there are no dependencies). For example, one invocation of yacc creates both output files for this rule:
y.tab.c y.tab.h : parser.y $(YACC) -d parser.y
In some cases, however, makepp will execute the rule actions once for each target, so that old makefiles don't break. This happens if all of the following are true:
$@
.
(The synonymns $(output)
or $(target)
do not trigger this behavior.)
$(outputs)
(or its synonymn
$(targets)
).
For example,
all test install: for subdir in $(SUBDIRS); do cd $$subdir && $(MAKE) $@; cd ..; done
is a common idiom in makefiles, and makepp supports it.
(Note that you should never use recursive make in any new makefiles
you write--use the load_makefile
statement, or implicit makefile loading instead).
The list of targets may not contain any automatic variables (except
$(foreach)
). The dependency list may contain only
automatic variables referring to the target ($(output)
,
$(outputs)
, or their
synonymns). The action may contain any automatic variables.
If makepp decides that the rule needs to be reexecuted,
each line of the rule is executed sequentially, and if any returns a
non-zero status, the remainder are not executed (and makepp
aborts with an error unless you specified the -k
option on the command line.) Each action should be only one
line. If an action is too long to write conveniently on a single
line, you can split it into several lines and put a backslash to
indicate that the several lines should be combined into one.
In order to distinguish actions from the next rule, the action should be indented more than the line containing the targets and dependencies. Unlike other implementations of make, makepp doesn't really care how much you indent it or whether you use tab characters rather than spaces (since such things are hard to see by looking at the makefile on the screen). To keep backward compatibility, the rules makepp uses to decide when actions end and the next rule begins are somewhat complicated:
#
character at the right margin ends the rule, unless the next
non-blank line is indented more than 8 spaces (or more than one
tab).
As with other implementations of make, the first explicit rule in a file is the default target, and is made if you do not specify any targets on the command line.
It is safe to specify wildcards in the dependency list. Wildcards match not only files that exist, but files which can be created given the rules in the makefile. (See below for more information on wildcards.) For example, to build a library from all .o files in a directory, you could write this:
libmine.a: *.o ar ru $(target) $(dependencies)
This will work even if none of the .o
files have
been created yet.
As usual, the actions must be indented, though (unlike the standard make) makepp doesn't really care how much. The actions are terminated by a line that does not begin with whitespace or a comment.
Normally, each shell command is printed as it is executed.
However, if the first word of the action is noecho
(or
if it begins with the character @
), then the command is
not printed. For example,
%.o: %.cxx noecho $(LIBTOOL) --mode=compile $(CC) -c $(input)
This means that when the libtool command is executed, it is not printed. (Libtool itself usually prints the modified command that it executes, so it's redundant to print it twice.)
Normally, if the shell command returns a non-zero status, then
makepp aborts because the command failed. However, some
programs incorrectly set the status on exit, or there may be an
error which really isn't fatal and shouldn't abort the whole
compilation. You can cause makepp to ignore the return
status by specifying ignore_error
as the first word of
the command line (or -
as the first character). For
example,
$(phony distribution): ignore_error rm -r my_program-$(VERSION) # Get rid of previous junk. mkdir my_program-$(VERSION) cp $(FILES) my_program-$(VERSION) tar cf my_program-$(VERSION).tar my_program-$(VERSION)
This command makes a directory, copies a bunch of files into it,
and then puts everything into a tar file for distribution. It's a
good idea to clean out the previous contents of the directory, if
there was anything there previously, and that's what the first line
does. The rm
might fail, but its return status is
ignored.
A pattern rule is a rule that is applied based on some textual pattern. This is used to apply the same rule to a whole class of files. The syntax is the same as GNU make's pattern rules:
%.o: %.c $(CC) -c $(input) -o $(output)
This says that any file which matches *.c
can be
converted into the corresponding .o file using the given command.
(Note that if you specify the command line option --percent-subdirs
,
then the above rule will also compile .c
files in
subdirectories as well.)
(If you're used to traditional make, you might not recognize the
automatic variables
$(input)
and $(output)
.
$(input)
is a synonymn for $<
, and
$(output)
is a synonymn for $@
.)
Note that several pattern dependencies may be supplied. For
example, if your xyz.o
file depends on the
corresponding xyz.cpp
file, and also on a file called
moc_xyz.cpp
, this could be expressed with:
%.o: %.cpp moc_%.cpp $(CXX) -c $(inputs) -o $(output)
You may also have several pattern targets. For example,
%.tab.h %.tab.c : %.y yacc -d $(input) mv y.tab.h $(stem).tab.h mv y.tab.c $(stem).tab.c
The above pattern rule syntax is powerful enough to support
almost all builds, but occasionally it is necessary to do something
more complicated. Makepp provides a more powerful syntax:
the :foreach
clause for the rule.
target-expression : dependency-expression : foreach file-list actions
The variable $(foreach)
is set in turn to each file
matching the file-list, and the target and dependency expressions
are evaluated. The file-list may contain wildcards, and these match
even files which don't exist yet but which can be built (see the
section on wildcards for details).
The above pattern rule can be expressed in this format as follows:
$(patsubst %.c, %.o, $(foreach)) : $(foreach) : foreach *.c ... shell commands here
(In fact, it's converted to that internally.) This is an
unwieldy syntax but it is extremely flexible, because the
$(foreach)
variable may appear in any way in the
expression. For example, if you want to specify to make a .o file
from a .cpp file, but only if a corresponding .h file exists, you
could do it like this:
$(foreach:%.h=%.o) : $(foreach:%.h=%.cpp) : foreach *.h ... shell commands here
(This uses the slightly more concise substitution reference syntax rather
than calling patsubst
explicitly. See the section on
variable substitution for
details.)
For backward compatibility, makepp supports the old-style suffix rules.
.suffix1.suffix2: actions
is equivalent to
%.suffix2: %.suffix1 actions
but much harder to remember.
When there is more than one way to make a file, makepp uses a simple procedure to determine which rule to use.
:foreach
clause doesn't make something a pattern
rule. It must have a wildcard (like "*" or "?") as part of the
filename in the :foreach
clause. If it is just an
explicit list of files, it is treated as an explicit rule for
those files.)
%.s: %.c $(CC) -s $(input) -o $(output) %.o: %.s $(AS) $(input) -o $(output) %.o: %.c $(CC) -c $(input) -o $(output)
If we need to build xyz.o
, we could either build
the intermediate .s
file and then run that through
the assembler using the first two rules, or we could go directly
to a .o
file using the last rule. The last rule is
preferred because there are fewer steps in the chain of
inference (one instead of two).
%.o: %.c # General compilation rule. action special_%.o: special_%.c # Special rule for files with a different action # "special_" prefix.
Sometimes it is necessary to supply additional options to modify
how makepp executes the rule. These options are specified as
:optionname value
, either on the line containing the
dependencies, or separated on subsequent lines.
Supplying the options on separate lines may make it possible for you to use the same makefile with makepp and a traditional make. For example,
target : dependencies : signature target_newer actions
will work fine with a traditional unix make, because it
interprets the : signature
line as a shell
command, and a command beginning with a colon does nothing.
:signature
signature_method
This tells makepp what algorithm to use to determine
if the file is out of date. See the section on signature checking for more
details. Legal values for this option are
exact_match
, target_newer
,
md5
, and c_compilation_md5
. This
overrides any signature method specified with the -m
or --signature-method
command line options, or
with the signature
statement.
:scanner
name
This tells makepp how to scan for include files. Usually, makepp guess how to do this based on the words in the command itself (see the section on scanning for more details). However, if makepp guesses wrongly, you may want to explicitly indicate the scanner, like this:
%.o: %.abc : scanner c_compilation action here
This causes makepp to perform the same scanning that it does for C/C++ build commands, even if it doesn't recognize the action as a C compilation.
Legal values for :scanner
are (currently):
none
c_compilation
The default scanner depends on the command. If you do not
specify a :scanner
option, then the first word of
the command is examined. If it looks like a compile command,
then makepp will use the c_compilation
scanner; otherwise it usese the none
scanner. For
more details on this, or if you want to write your own scanner
or change makepp's default scanners, see the section on
scanning.
A statement is any line beginning with a word which does not have
a ":
" in it. (A colon implies that the line is a
rule.) For example, these are statements:
include extra_rules.mk load_makefile subdir
The command word is actually the name of a perl subroutine, and you can define your own perl subroutines to do whatever you want.
Makepp has a number of builtin statements which you may occasionally need to use.
This inserts the contents of another makefile into the current
makefile. It can be useful if you have boilerplate files with a
number of rules or variables, and each directory only needs to make
a few modifications. The include
statement also used
to be commonly used in traditional makes in conjunction with
automatic include file scanners, but this is no longer necessary
with makepp.
include
searches the current directory, then the
parent of the current directory, then its parent, etc. If it does
not find a file of the given name by the time it reaches the top of
the directory hierarchy, then it looks in the makepp dadta
directory (/usr/local/share/makepp
if you installed
makepp in /usr/local
) for one of the include files that
comes with makepp. If you want to include a template file in
every makefile in a whole directory hierarchy, you can place your
makefile template at the top directory. The makefiles do not have
to know exactly where they are in the hierarchy; each makefile can
contain a line like this:
include standard_definitions.mk
instead of something more complicated, like this:
include ../../../standard_definitions.mk # Is this the right number of ..?
You can specify as many files as you want, and variables are allowed:
include file1 file2 file3 $(other_include_files)
A minor variant on this, the -include
statement,
includes the file if it exists but doesn't generate a fatal error if
it does not. The -include
statement used to be
important for include file scanning, but is seldom useful for
makepp. (Makepp will not try to make the file and
then reread it, unlike GNU make.)
load_makefile /some/directory/somewhere/Makefile load_makefile subdir load_makefile VAR1=value1 VAR2=value2 subdir
This statement causes makepp to cd to the directory
containing the makefile and load its rules into makepp's
internal database. If you specify just a directory instead of a
makefile, load_makefile
looks for
Makeppfile
, makefile
, or
Makefile
in that directory.
Any variables you specify with the syntax VAR=value
(or VAR="value1 value2"
) are passed to the loaded
makefiles. They override any settings in those makefiles, just as
if you had typed them on the command line.
Using load_makefile
is different from the command
include dir/makefile
in two ways. First, load_makefile
does not transfer
any variables from the top-level makefile into the subordinate
makefile; each makefile exists in its own namespace. The
subordinate makefile cannot influence the variables in the top-level
makefile in any way.
Second, each build command is tagged with the directory of the
makefile that it came from. When makepp executes a rule from
a different makefile, it first cd's to the directory containing that
makefile before executing the command. Makefiles which are seen
with the include
statement are actually treated as part
of the makefile that included them, and therefore their rules are
not tagged with a different directory.
You usually do not have to load a makefile explicitly, unless it has an unusual name, or it has targets which are not contained in the same directory as the makefile itself, or you have disabled implicit makefile loading. By default, if makepp is trying to build a file and doesn't have a rule to build it, or if it is evaluating a wildcarded filename in a directory, it will automatically attempt to load a makefile from that directory. See the section on building with multiple directories for more details.
You cannot use load_makefile
to load several
makefiles that apply to the same directory. Use
include
for several pieces of the makefile that apply
to the same directory, and load_makefile
for makefiles
that apply to different directories.
This statement introduces a block of code which is interpreted verbatim by perl. It can be useful for defining functions, but you can do this more concisely with the sub statement. A block of perl code in your makefile can be useful for several reasons:
perldoc Config
if you want to see what
configuration information perl has available.)
perl_begin use Config; $ARCH = $Config{'archname'}; # Use perl's knowledge of the architecture. $CC = $Config{'cc'}; # Use the same C compiler as perl did. $SHARED_OBJ_CFLAGS = $Config{'cccdlflags'}; # Flags needed to compile objects which will # go into a shared library. $SHARED_OBJ_LDFLAGS = $Config{'ccdlflags'} . " " . $Config{'lddlflags'}; # Linker flags to make a shared library. $SHARED_CC_LINK = $Config{'ld'}; # Command to produce shared libraries. $SHARED_EXTENSION = $Config{'dlext'}; # Extension of shared libraries. if ($ARCH =~ /^i[56]86/) { # Some sort of intel machine > 486? $CFLAGS = "-O6 -malign-double"; # These do better with quadword alignment. } else { $CFLAGS = "-O6"; } perl_end %.o: %.c $(CC) $(CFLAGS) $(SHARED_OBJ_CFLAGS) -c $(input) -o $(output) libmylib.$(DLEXT): *.o $(SHARED_CC_LINK) $(inputs) -o $(output) $(SHARED_OBJ_LDFLAGS)
Note how we define a bunch of variables in the perl block, and then we use them afterwards in the rest of the makefile. You can use the full power of the perl interpreter to set your variables in arbitrarily complicated ways. You can run shell commands from your perl code, access a database, or whatever you want.
The remainder of the line following the perl_begin
statement is ignored. All text up until a line that begins at the
left margin with perl_end
is sent verbatim to the perl
interpreter.
repository dirname repostiory destdir=srcdir
Specifies one or more repository directories. The first repository specified has precedence over the others if the same file exists in multiple repositories and there is no build command for it.
If you specify just a directory after repository
,
its contents are linked into the current directory. You can link
its contents into any arbitrary place in the file system by
specifying the location before an equals sign, e.g,
repository subdir1/subdir2=/users/joe/joes_nifty_library
signature exact_match signature target_newer signature md5 signature c_compilation_md5 signature default
Overrides the default signature method for all
rules following the signature
statement. This
overrides the signature method specified on the command line with
-m
or --signature-method
, but does not
override signature methods specified with the
:signature
rule modifier.
Specify signature default
to return to
makepp's default, either the builtin default or the default
specified on the command line.
For more information about signature methods, see the section on signature checking.
This statement provides a way to define a perl subroutine inside your makefile. The syntax is identical to that of the perl sub statement, except that the closing brace must be at the left margin.
A perl subroutine is invoked whenever a statement is seen, or
when an expression like $(name words)
is seen.
For example, suppose that for some reason you need to load the
contents of a file into a make variable. (You could do this by
saying $(shell cat filename)
but it's possible to do it without ever invoking the shell.) This
can be done by placing the following into your makefile:
sub f_file_contents { my ($filename) = @_; # Name the arguments. my $file_contents; open FILE, $filename || die "$!\n"; my $line; while (defined($line = <FILE>)) { # Read another line. $file_contents .= $line; } close FILE; return $file_contents; }
Now, with this function defined, you can write
X = $(file_contents filename)
and the variable $(X)
will contain the contents of the
given file.
See the section on extending makepp for more details.
Often it is convenient to do different things in your makefile depending on what architecture you are on, or what set of options you are building with. Makepp supports several ways of doing such conditionals.
ifeq
, ifneq
, ifdef
, and
ifndef
perl_begin if ($ARCH =~ /^i[56]86/) { $CFLAGS = '-O6 -malign-double'; # On intel machines > 486, there # is a substantial speed penalty # for doubles that aren't quadword aligned. } else { $CFLAGS = '-O6'; } perl_end %.o: %.c $(CC) $(CFLAGS) -c $(input) -o $(output)
Any make variable can be accessed directly as a perl scalar.
In this case, we've set the value of CFLAGS
differently based on a regular expression match on the
architecture flags.
makepp makes it much safer and more reliable to use wildcards in your makefile. makepp's wildcard expansion returns all existing files that match the wildcard, and all files which do not yet exist but which can be built using the rules. Thus a rule like this:
libmylib.a : *.o $(CC) $(inputs) -o $(output)
will do exactly what it should, even if none of the .o files
exists in the directory yet. (Of course, if you create extra bogus
.o files in the directory, makepp has no way of knowing that
you don't want them in mylib.a
.) In other versions of
make, the *.o
wildcard will only return existing object
files and so the dependency list will vary depending on what files
have been created.
makepp supports all the usual shell wildcards
(*
, ?
, and []
). It also has
a wildcard **
which matches any number of intervening
directories. (This idea was stolen from zsh.) For example,
**/*.c
matches all the .c
files in the
entire source tree. objects/**/*.o
matches all the
.o
files contained anywhere in the subdirectory
objects
or any of its subdirectories or any of their
subdirectories. The **
wildcard will not follow soft
links to directories.
makepp can support filenames that have special characters
in them like a colon or a space. Suppose, for example, you want to
create a file called a:thing
from the file
b:thing
. You can't write the rule this way:
a:thing : b:thing commands herebecause makepp won't know which colons separate targets from dependencies and which are part of the filenames. Instead, simply enclose the name in quotes, like this:
"a:thing" : "b:thing" commands here
Now the rule is unambiguous.
makepp's quoting rules are quite similar to the shell's. You can, for example, use single quotes instead of double quotes, or you can escape special characters with a backslash:
a\:thing : 'b:thing' commands here
Suppose, for example, that your filename is '"!;\$
.
Now why you'd want such a filename I don't know, but here are
several ways you could specify it to make (and the shell):
\''"!;\$$' "'\"!;\\$$"
Note that (unlike the shell) variables beginning with $
are expanded even inside single quotes. Dollar signs cannot be
protected by quotes or backslashes. To get a literal dollar sign,
use a double dollar sign.
Generally, you should be able to deal with just about any special
character by quoting it in some way. This includes spaces, control
characters, etc. However, be aware that at present, makepp's
comment stripping is somewhat simplistic, and any #
characters preceded by whitespace will be interpreted as comments no
matter how they are quoted.
When a target or dependency name is put into an automatic variable like
$(target)
, then the quotes and any backslashes are
stripped. This means that if you want to reference the filename in
the actions, you will probably have to quote it again, like this:
"a file name with spaces": echo "Special contents" > "$@"
If you don't put the quotes around $@
, then the
shell will see the command
echo "Special contents" > a file name with spaces
which writes the string "Special contents file name with spaces"
to the file called a
. This is probably not what you
want.