|
|
| |
MAKEPP_STATEMENTS(1) |
Makepp |
MAKEPP_STATEMENTS(1) |
makepp_statements -- Various statements in a makefile
A: autoload, B: build_cache,
build_check, D: "define",
E: export, G: global,
I: ifdef,
ifeq,
ifmakeperl,
ifndef,
ifneq,
ifnsys,
ifntrue,
ifperl,
ifsys,
iftrue,
include,
_include, L: load_makefile,
M: make,
makeperl,
makesub, N: "no_implicit_load",
P: perl,
"perl_begin",
prebuild, R: register_command_parser,
register_input_suffix,
register_parser,
repository,
runtime, S: signature,
"sub", V: vpath
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
Makepp has a number of builtin statements which you may
occasionally need to use.
Note that wherever you see an underscore, you may also use a dash,
because makepp converts dashes to underscores in statement names.
Conditionals are special statements, which control what lines of the Makeppfile
are actually seen. The simplest form (where
"ifxxx" stands for any of the conditional
statements documented below) is:
ifxxx ...
lines seen if the statement evaluates as true
endif
or:
ifxxx ...
lines seen if the statement evaluates as true
else
lines seen if the statement evaluates as false
endif
There is also the possibility to do complex combinations like
this:
ifxxx ...
and ifxxx ...
and ifxxx ...
or ifxxx ...
and ifxxx ...
lines seen if the combined statements evaluate as true
else ifxxx ...
or ifxxx ...
and ifxxx ...
lines seen if the first combination evaluates as false
and these combined statements evaluate as true
else
lines seen if the statements above evaluate as false
endif
As is suggested by the indentation,
"and" has higher precedence than
"or". In other words an
"or" elects between two groups of
"and"`s. There may be any number of
"and ifxxx"`s, "or
ifxxx"`s and "else
ifxxx"`s.
The "ifxxx" conditional
statements are unique in that they may occur in the middle of rule actions,
as in the above example, without disrupting the rule.
- ifeq string1, string2
- ifneq string1, string2
-
ifeq ($(STR1),$(STR2))
makefile lines if true
else
makefile lines if false
endif
If the two strings match exactly (except for leading or
trailing whitespace), then the first set of lines is used; otherwise the
second is used. The else clause is optional.
There are two other acceptable syntaxes for the
"ifeq" and
"ifneq" statements:
ifeq string1, string2
ifeq string1 string2
which are equivalent. Of course you can quote the strings as
needed.
"ifeq" and its friends
"ifneq",
"ifdef",
"ifndef",
"ifperl",
"ifmakeperl",
"ifsys" and
"iftrue" are primarily useful when you
have to build a program under several different conditions. For
example,
BUILD_TYPE := debug # "debug" or "production"
ifeq ($(BUILD_TYPE), debug)
CFLAGS := -g
else
CFLAGS := -O2
endif
program : *.o
$(CC) $(CFLAGS) $(inputs) -o $(output) $(LIBS)
ifeq ($(BUILD_TYPE), production)
strip $(output)
endif
%.o : %.c
$(CC) $(CFLAGS) -c $(input) -o $(output)
If this is a production build, all files are compiled with the
"-O2" option instead of the
"-g" option. Furthermore, the program
"strip" is run on the resulting binary
(in case you happened to link with some libraries that were compiled in
debug mode).
Sometimes it is easier to use the
"$(if)" function or
"$(perl)" function function instead of
a "ifeq" statement.
If you just want to see whether a symbol is blank or not, you
only need to supply a single argument, like this:
ifneq $(EXE_SUFFIX)
# what to do if $(EXE_SUFFIX) is not blank
endif
- ifdef VARIABLE ...
- ifndef VARIABLE ...
- These statements work analogously to the
"ifeq" and
"ifneq" statements, except that they
test whether any of the variables is defined or not any is (i.e. none is
defined). A variable is defined if:
- It was given a value with an assignment earlier in the makefile. See
makepp_variables for details.
- It was given a value as a Perl variable in a
"perl_begin" block.
- The variable is present in the environment.
- The variable is present on the command line, e.g., to invoke your
makefile, you typed
makepp CFLAGS=-O2
For example,
ifndef CFLAGS
CFLAGS := -g
endif
In this case, "CFLAGS" is set to
"-g" only if it wasn't already defined.
Note that this statement could just as easily have been written using the
"?=" assignment, like this:
CFLAGS ?= -g
- ifperl perlcode
- ifmakeperl perlcode
- These statements work analogously to the
"ifeq" and
"ifneq" statements, except that the
tests are in Perl. The first variant is plain Perl code, while the second
variant first passes the statement through Make-style variable expansion.
VERSION := 3.0
# VERSION is automatically also a Perl variable:
ifperl $VERSION <= 2
CPPFLAGS := -DNEW
endif
# quotes necessary for CFLAGS, because Perl sees only the value:
ifmakeperl my $$x = '$(CFLAGS)'; $$x =~ /-g/
CFLAGS := -g -O2
endif
- ifsys wildcard ...
- ifnsys wildcard ...
- Tests if the current system makepp is running on matches any of the
wildcards or not any (i.e. none).
ifsys i[3-6]86
and ifsys Linux SunOS
... # An Intel platform with Linux or Solaris
else ifnsys sparc power*
... # Nor Sparc or PowerPC
endif
There are up to six different strings you can match against.
The actual strings are not standardized. Three of them reflect what the
Perl instance was built for (not necessarily the same as where it is
running), and the others come from the system and all vary wildly in
form. You can find all of what the current platform matches by typing
the following command at the Shell:
perl -MConfig -e'print "$^O @Config{qw(archname myarchname)} "'; uname -mps
- iftrue expression
- ifntrue expression
- Tests if the expression evaluates to some value other than zero or the
empty string.
Conditionals may control a whole multiline statement, but they cannot be inside
such a statement.
- define
- {export|global|override}* define
-
define VARIABLE [assignment-operator]
variable value line 1
variable value line 2
endef
Defines $(VARIABLE)'s value to be all the lines between the
"define" statement and the
"endef" statement. See multiline
variables. The keywords "export" and
"global" may not be given at the same
time.
- perl_begin
- This is the same as "perl", but using
GNU make style statement syntax. 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 to perform actions that are easier in Perl
than with makepp functions and rules.
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. There can be no spaces before
"perl_end".
One example that I use this for is to make directories that
might not necessarily exist. It's common in makefiles to put all the .o
files in a subdirectory (e.g., a directory with a name i386, or
sparc, or something that depends on the machine type). But what
if the directory does not exist yet? You can make each .o file depend on
the subdirectory, and put a rule in to build the subdirectory. But it's
a lot easier just to do this:
OBJDIR := $(ARCH) # Where we put .o files.
perl_begin
-d $OBJDIR or mkdir $OBJDIR; # Make sure the directory exists.
perl_end
This way, every time the makefile is run, the subdirectory
will be created if it does not exist.
Some operations are better expressed in terms of regular
expressions than makepp's text functions. For example,
perl_begin
if ($ARCH =~ /^i[56]86/) { # You could do this with: ifsys 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.
As a final example, some pieces of information are easier to
access directly from Perl than from makepp. For example, you can access
all of the configuration information that perl knows about your system,
including how to build shared libraries, etc. (Type
"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.
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.
- perl perlcode
- makeperl perlcode
- This is the same as "perl_begin", but
using Perl-style braces. The first variant is plain Perl code, while the
second variant first passes the statement through Make-style variable
expansion. Note that the difficulty of parsing Perl's braces has lead to
the following simple heuristic:
- If a double opening brace is found on the same or next line, a double
closing brace will terminate the block. It must be at the beginning of a
line, but may be preceded by whitespace.
- Else, if the closing brace is at the very end of the
"perl" line this is a one liner.
- Otherwise the closing brace must be at the very beginning of a following
line, i.e. no leading whitespace.
For an efficient way to call Perl scripts, see
"run". Unlike the
"$(perl)" function, the return value of
this block is ignored.
perl { print "passed this point in the makefile\n" }
perl
{
print "and this one too\n";
}
ifdef NOISY
perl {{
print "as well as this one\n"
}}
endif
You can use the Perl debugger for your embedded code, by running
makepp itself in the debugger, where ... are the arguments, if any, you
normally pass:
perl -d -S mpp ...
It is hard to set breakpoints in Perl code that has not been
loaded. You can work around this by putting this line into your embedded
Perl, just before where you want to break:
$DB::single = 1;
Then you can type "c" at the
debugger's prompt, to continue till that point.
- sub
- makesub
- This statement provides a way to define a Perl subroutine inside your
makefile. The first variant is plain Perl code, while the second variant
first passes the statement through Make-style variable expansion. The
syntax is identical to that of the Perl sub statement, except that
prototypes are meaningless.
For the three possibilities of putting the braces of the body,
see the explanation at the "perl"
statement.
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 ($file) = @_; # Name the argument.
open my $fh, $file or die "$file: $!\n";
local $/ = undef; # Slurp file in one read.
<$fh>;
}
ifdef NEWSUB
makesub f_VAR2
{{
$(VAR) * 2;
}}
endif
makesub f_VAR1 { $(VAR) + 1 }
Now, with this function defined, you can write
X = $(file_contents filename) # equivalent to builtin $(&cat filename)
and the variable "$(X)" will
fetch the contents of the given file every time it gets expanded. Use
":=" to do this exactly once, or
";=" to do this at most once.
See makepp_extending for more details and examples.
- autoload filename ...
- Specifies one or more makefiles to load should an attempt to find a rule
for a file in this directory otherwise fail. This is useful when the
makefile has rules whose definitions depend (possibly indirectly) on a
file in another directory that depends (possibly indirectly) on other
files in this directory (built by rules that do not depend on the
file in the other directory).
For example, your Makeppfile might look like this:
rules-to-build-files-that-otherdir/x-depends-on
more_rules.makeppfile: otherdir/x
action-to-build-more_rules.makeppfile
autoload more_rules.makeppfile
Note that we cannot reliably replace
"autoload" with
"include" here, because if something
other than the rule for more_rules.makeppfile tries to build
otherdir/x first, then more_rules.makeppfile will probably
fail because otherdir/x won't exist yet, because there is already
an attempt to build it underway when Makeppfile is implicitly
loaded on its behalf.
WARNING: Be very careful about doing things in an autoloaded
makefile that change the behavior of rules in the directory's other
makefile(s), as this will cause that behavior to depend on whether or
not some previously built target caused makefiles to be autoloaded.
- build_cache /path/to/build/cache
- [global] build_cache /path/to/build/cache
- Specifies a path to a build cache. See makepp_build_cache for details. The
build cache must already exist; see "How to manage a build
cache" in makepp_build_cache for how to make it in the first place. A
"build_cache" statement in a makefile
overrides the "--build-cache" command
line option for rules in the makefile, but it may be overridden by the
":build_cache" rule modifier on a
per-rule basis.
The keyword "global" may
precede this statement with the same effect as the command line option,
i.e. the build cache applies in every makefile. This should best be
given in a RootMakeppfile to be certain it is seen early
enough.
Specify "none" instead of a
path to a directory if you want to disable the build cache for all rules
in this makefile.
- build_check build_check_method
- [global] build_check build_check_method
- Specifies the default build check method for all rules in this makefile.
See makepp_build_check for details. The
"build_check" statement overrides the
"--build-check-method" command line
option for all rules in the makefile, but may be overridden by the
":build_check" modifier on a per-rule
basis.
The keyword "global" may
precede this statement with the same effect as the command line option,
i.e. the build check method applies in every makefile which does not
specify its own. This should best be given in a RootMakeppfile to
be certain it is seen early enough.
Specify
"build_check default" instead
of a name if you want to return to the default. With the keyword
"global" this means the
"exact_match" method, else this
reverts the current makefile to not having its own specific method.
- export VAR ...
- export assignment
-
export PATH := $(PWD):$(PATH)
Marks the given variables for export to subprocesses. See
setting variables.
- global VAR ...
- global assignment
-
global MYPROJECT.INFO = info to be seen in all makefiles
Marks the given variables as global to all makefiles. See
setting variables.
- include makefile
- 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" first considers
the current directory, then the parent of the current directory, then
its parent, etc. It stops considering directories when it reaches the
root of the file system or when the file system device ID changes. (This
means that it will not find files located in other NFS mounts. This is
to prevent problems with network file systems or automounters and dead
servers.) If it does not find a file of the given name by the time its
search is stopped, then it looks in the makepp data 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)
If you're working on a build that needs to work with both GNU
make and makepp, sometimes it's convenient to have exactly identical
makefiles but a different include file. For example, all of your
makefiles may contain a line like this:
include $(TOPDIR)/standard_rules.mk
and you want standard_rules.mk to be different for GNU
make and makepp. To facilitate this, the
"include" statement first looks
for a file with the suffix of .makepp before looking for the file
you asked for. In this case, it would first look for a file called
standard_rules.mk.makepp, and if that exists, it would load it
instead of standard_rules.mk. This way, when you run the makefile
with GNU make, it loads standard_rules.mk, but with makepp, it
loads standard_rules.mk.makepp.
- _include makefile
- A minor variant on "include", 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 with GNU make, but is seldom useful
for makepp.
- 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 "Tips for multiple
directories" in makepp_cookbook for info on building with multiple
directories.
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.
- no_implicit_load
- This statement turns off implicit loading of makefiles from a set of
directories. This can be useful if you want to load makefiles
automatically from most directories, but there are some directories which
for various reasons you do not want makepp to attempt to update. (E.g.,
maybe the directory has a makefile for some other version of make which
makepp does not understand.) For example,
no_implicit_load dir1 dir2/*
The above statement will turn off implicit loading for
makefiles in "dir1" and all of its
subdirectories. It will also turn of implicit makefile loading for
all subdirectories of "dir2" (and all
of their subdirectories), but not for
"dir2" itself.
You may use wildcards in the statement. Non-directory files
that match the wildcard are ignored. You can also use functions to
further specify the directories that you are interested in, e.g.,
no_implicit_load $(filter-out dir1 dir2, *)
will turn off implicit loading for all subdirectories except
dir1 and dir2 and their subdirectories.
- prebuild target
- make target
- The arguments (which undergo Make-style variable expansion) are built
immediately. This is useful when the list of targets that the Makefile can
build depends on a generated file in another directory.
Currently, it will quietly fail to build targets if there is a
dependency loop among the prebuilt targets and the Makefiles that must
be loaded to build them, but that ought to be treated as an error.
- register_command_parser command_word parser
- register_parser command_word parser
- When lexically analyzing rule actions, use parser for
command_word, which may be the full path or just the basename. The
basename is usually enough because the lexer tries both.
The parser may either be a classname with or without
the leading "Mpp::CommandParser::".
Such a class must have a member function called
"factory" that returns an object of
that class. If the classname contains colons, it must be quoted, so as
not make this line look like a rule.
Or, because that class is usually not yet loaded, instead the
factory function may reside in the Makefile namespace. These functions
have a prefix of "p_" which must not
be given. This is the case of the builtin parsers.
The effect is comparable to the
":parser" rule option. But for
multi-command rules this is the better way.
- register_input_suffix command_word suffix ...
- Add "suffix" ... to the list of input
file suffixes recognized when an action beginning with
"command_word" is parsed. The parser
would normally pick this up via Mpp::CommandParser::input_filename_regexp,
but it might instead ignore this entirely.
Parsers don't normally pick up all the arguments that aren't
recognized as options, because they might be arguments of unrecognized
options. (For example, i386v is not an input file of the
command "gcc -b i386v
foo.c".) Instead, they pick up only
positional arguments that look like input filenames.
It is not unusual to use standard tools with site-specific
nonstandard suffixes in order to signify that those files require
special handling, such as different command options and/or
postprocessing steps. For example:
register_input_suffix cpp .vpp
%.v: %.vpp
cpp $< > $@
- repository directory
- repository 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. See
makepp_repositories for more details about repositories.
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
You should put the repository statement near the top of your
makefile, before any rules that may need to use it.
- runtime program,library
- Store "library" as a runtime dependency
of "program". Both
"program" and
"library" may contain multiple words, in
which case each word in "library" is
stored as a runtime dependency of each word in
"program". When
"program" is added automatically as the
executable dependency of a command by the
"Mpp::CommandParser" base class, its
runtime dependencies (if any) are added as well. In order for this to
happen, "program" must be specified in
the rule with a directory component, and without any shell meta
characters. The purpose of this statement is to capture dependencies on
libraries and other executables that are often loaded by the program,
without having to specify them explicitly as dependencies of each rule
that invokes "program", or to scan
"program" to determine those
dependencies (which could be prohibitively difficult.)
Runtime dependencies are traversed recursively, so if
"a" has a runtime dependency on
"b" and
"b" has a runtime dependency on
"c", then any rule that uses
"./a" will have implicit dependencies
on both "b" and
"c" (unless it uses a special
"Mpp::CommandParser" class that
overrides this behavior).
Note that missing dependencies won't necessarily be added
after you add this statement to a makefile, unless the rule is
re-scanned. Use the "--force-rescan"
command line option to ensure that this happens.
- signature name
- [global] [override] signature name
-
signature md5
signature C
signature c_compilation_md5
signature xml
signature xml-space
signature default
Sets the signature method for all rules following the
"signature" statement, for which no
command parser chooses a method. You can override this for individual
rules with the ":signature" rule
modifier.
If you add the keyword
"override", then this method will
override even the the choice made by command parsers, but not those
specified with the ":signature" rule
modifier. If you add the keyword
"global", the effect applies to all
rules yet to be read, unless their makefile also has its own
"signature" statement. This is
equivalent to the "--signature"
command line option if given before any rule is read, e.g. in a
RootMakeppfile to be certain it is seen early enough. Likewise
the keywords "global override" for
this statement are equivalent to the
"--override-signature" command line
option.
Specify
"signature default" instead of
a name if you want to return to the default. With the keyword
"global" this means the simple
modification time and file size method. Else this reverts the current
makefile to not having its own specific method, using a global method if
one was set.
For more information about signature methods, see
makepp_signatures.
- vpath pattern directory ...
- Fetch all files matching pattern from each given directory. Pattern may
contain at most one "%" wildcard. This
uses the transparent repository mechanism (unlike gmake which rewrites
filenames), but it does not recurse into subdirectories.
All builtin and self defined commands (see builtin commands and extending
makepp), as well as external cleanly programmed Perl scripts can be used like
statements. In this case they differ from rule actions in that they run in the
same process as makepp and any input or output files are not noted as
dependencies or as having been built by makepp.
As with all statements, they are considered as such, if they are
indented less than the actions of the previous rule, if any.
This can be used for messages to be output while reading the
makefile:
&echo The value of $$(VAR) is $(VAR)
Or instead of making many rules each depend on a directory
creation rule, you can simply create it on the fly. Note that commands which
create files are processed again every time the makefile is read., That's
why we protect this one with a test -- though in this special case that
would not be necessary, as this command would do no harm when repeated:
ifperl !-d 'include'
&mkdir -p include # Create only if not present
endif
Gary Holt (holt-makepp@gholt.net)
Visit the GSP FreeBSD Man Page Interface. Output converted with ManDoc. |