# Functions and Advanced Variable Usage

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.

## Lists of corresponding files

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 patsubst function

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.

### Substitution references

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)

### rc-style substitution

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`.

### In-line perl code

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
    begin_perl
    ($OBJS = $SOURCES) =~ s/\.cpp/.o/g;
    end_perl

Any text between the `begin_perl` statement and the `end_perl` 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.

Tutorial index | Next (source/binary separation) | Previous (wildcards)
Last modified: Fri Aug 25 23:48:38 PDT 2000