Makepp has a number of extremely powerful ways of manipulating text. This tutorial shows a few of the more useful ways, but you might want to glance through the section in the reference manual on variables and functions for a complete list of the things you can do.
A common problem in makefiles is the maintenance of two lists of files which correspond. Consider the following two variables:
SOURCES := a.cpp bc.cpp def.cpp OBJS := a.o bc.o def.o
We might want to have a list of sources if the makefile can build source distributions, and we might need a list of objects for the link command. It's tedious to change both lines whenever a new module is added, and it's not unlikely that a programmer will change one line and forget to change the other. Here we will show four different ways to avoid the duplication.
The first is to use makepp's functions to convert one list into another. A function invocation looks a little like a variable, except that a function can take arguments:
$(function arg1 arg2 arg3 ...)
Makepp supplies many powerful functions, but probably the
most useful of them is the patsubst
function. You
could write the above lines like this:
SOURCES = a.cpp bc.cpp def.cpp OBJS = $(patsubst %.cpp, %.o, $(SOURCES))
The patsubst
function applies a pattern to every
word in a list of words, and performs a simple textual substitution.
Any words in the list that match the pattern in the first argument
are put into the output after making the substitution indicated by
the second argument. The %
wildcard matches any string
of 0 or more characters. In this example, the pattern
%.cpp
is applied to every word in
$(SOURCES)
. The first word, a.cpp
matches
the pattern, and the %
wildcard matches the string
a
. The %
in the second argument is then
replaced by a
, and the result is a.o
. For
the second argument, %
matches bc
, so the
result is bc.o
.
Makepp's builtin functions can strip directory names, remove extensions, filter out matching words, return the output from shell commands, and other useful tricks. In addition, you can also write your own functions in perl that can be called from other parts of the makefile.
Since the patsubst
function is so common, there is
an abbreviated syntax for it called a substitution reference.
We could have written the above lines like this:
SOURCES = a.cpp bc.cpp def.cpp OBJS = $(SOURCES:%.cpp=%.o)
Sometimes invocations of patsubst
or the equivalent
substitution references can be somewhat cryptic. Makepp
provides another option which is sometimes more convenient:
rc-style substitution (so called because it was pioneered by
the rc shell).
MODULES := a bc def SOURCES := $(MODULES).cpp OBJS := $(MODULES).o
What happened here is that when it evaluated
$(MODULES).cpp
, makepp appended
.cpp
to every word in $(MODULES)
, and
similarly for $(MODULES).o
. In general, any characters
preceding the $(variable)
(up to a word delimiter) are
placed before each word in $(variable)
, and any
characters following $(variable)
are placed after each
word in $(variable)
. Thus the result of evaluating
x$(MODULES)y
would be
xay xbcy xdefy
.
If you know perl, you can insert perl code to perform arbitrary manipulations on variables into your makefile. This is best illustrated by an example:
SOURCES := a.cpp bc.cpp def.cpp perl_begin ($OBJS = $SOURCES) =~ s/\.cpp/.o/g; perl_end
Any text between the perl_begin
statement and the
perl_end
statement is passed off to the perl
interpreter. All variables in the makefile (except automatic
variables) are accessible as perl scalars. Any variables you set
with perl code will be accessible in the makefile.
So what the above example does is to copy the text from
$SOURCES
to $OBJS
, then substitute each
occurence of .cpp
with .o
.
In this example, using inline perl code is probably unnecessary since there are easier and clearer ways of doing the same manipulation. But the full power of the perl interpreter is available if you need it.