makepp -- Compatible but improved replacement for make
makepp [ -e ]
[ -C dir ] [ -f makefile]
[ -F makefile_or_dir ]
[ -j n] [ -k ]
[ -m method ]
[ --noremake-makefiles ]
[ --nowarn ] [ -q ]
[ -R dir]
[ --traditional-recursive-make ]
[ -v ] [ --version ]
[ VAR=value ... ]
[ target ... ]
mpp [-options]
[ VAR=value ... ]
[ target ... ]
Makepp, a build program which has a number of features that allow
for reliable builds and simpler build files, is a drop-in replacement for
GNU make. It supports almost all of the syntax that GNU make supports, and
can be used with makefiles produced by utilities such as automake. It is
called makepp (or make++) because it was designed with special
support for C++, which has since been extended to other languages like Swig
or embedded SQL. Also its relationship to make is analogous to C++'s
relationship to C: it is almost 100% backward compatible but adds a number
of new features and much better ways to write makefiles.
Makepp passes an extensive test-suite, and is used in several big
projects. If you have any issues with the latest CVS version, holler, and
we'll try to fix it quickly. Makepp runs with any version of Perl since
5.8.
The following manual pages contain further information on how to
use makepp:
- Tutorial
- How to write a makefile. This is mostly intended for someone with little
or no experience using any implementation of make.
- Compilation
Tutorial
- What the Unix compilation commands do.
- Release Notes
- What changed with each release.
- Incompatibilities
- What works differently between GNU make and makepp.
- Speedup
- Various tips for making makepp go much faster.
- Perl Performance
- Various tips for making Perl programming (within your makefiles and
elsewhere) go faster.
- Cookbook
- Quick answers to "How do I ...?" or "What's the best way to
...?"
- FAQ
- Quick answers to questions people have stumbled upon.
- Build Algorithm
- How makepp's build algorithm differs in fundamental ways from traditional
make.
- Build Cache
- A build cache is a directory that stores the results of prior builds in
case they are needed again in the same directory, or in a separate build
in a different directory.
- Build Check
Methods
- How makepp decides when to build.
- Builtin
Commands
- Powerful, efficient commands available everwhere makepp 2.0 or newer
is.
- Builtin
Rules
- For very simple programs, you may not need a makefile at all! These are
the builtin rules that makepp knows about.
- Compatibility
- Where and and with what version of Perl makepp works.
- Extending
- How you can add functions to makepp by writing your own Perl code.
- Functions
- Functions for text manipulation and various other purposes.
- Repositories
- Repositories are a technique that simplifies both variant builds and
keeping a central set of sources.
- Rules
- Specifying rules to build files.
- Sandboxes
- Using sandboxes to partition the build.
- Scanning
- How makepp scans for dependencies like include files.
- Signatures
- How makepp decides when files have changed.
- Statements
- Additional directives to control makepp.
- Variables
- Using variables to simplify rules.
- makepp, mpp
- Command line syntax of the main utility.
- makeppclean,
mppc
- An efficient stand-alone cleanup script to remove files generated by
makepp.
- makeppgraph,
mppg
- A stand-alone utility to graphically analyze dependencies and the reasons
for a rebuild.
- makeppinfo,
mppi
- A stand-alone utility to readably dump the build info makepp remembers
about each file.
- makepplog,
mppl
- A stand-alone utility to analyze dependencies and the reasons for a
rebuild.
- makeppreplay,
mppr
- A stand-alone utility to repeat things makepp has done, but much
faster.
- Index
- All keywords, functions and operators in makepp.
- Automatic scanning
for include files
- Makepp scans automatically for include files. This obviates the need for
tools like makedepend. Makepp's scanner works even if the included files
don't exist yet but have to be built. (This is true no matter where on the
include path they come from, unlike programs that depend on gcc's
"-MM -MG" option.) Makepp has a
flexible system for doing this which is based on scanning the build
command; you can adapt it for other languages or build commands by writing
a Perl subroutine.
- Better system for
hierarchical builds
- Makepp has a better system for handling builds involving multiple
directories and multiple makefiles. The traditional technique is to have
make invoke itself recursively in each directory. Depending on how
complicated the interdependencies are, several recursive passes are
sometimes needed. This makes the makefiles very complicated if they
guarantee a correct build. The real problem is that unless dependencies
are trivial (e.g., just one library file), it is almost impossible to
express accurately dependencies of targets in one makefile in terms of
targets from the other makefile. Unix make isn't smart enough to realize
that a target in one makefile depends on a file that is a target in a
lower-level makefile; it can't take build commands from the lower-level
makefile while it is trying to build the target in the upper-level
makefile. So the usual solution is to build everything that can be built
with the lower-level makefiles, hoping that that's adequate to build
everything that's needed for the upper-level makefile.
Makepp loads all the needed makefiles in at once, so it has no
problem dealing with situations where a file from one makefile depends
on a file produced by a different makefile. Makepp cd's automatically to
the directory containing the makefile before executing a command from a
makefile, so each makefile may be written independently without
knowledge of the top-level build directory. But if access to the root of
your build tree is important (e.g. because that's where your include
directory resides), you can name the makefile in that directory
specially. Then makepp gives you the path to that directory in a
variable.
Makepp also can figure out where all the makefiles for the
entire project are without being told, if each makefile is in the same
directory as the files it is supposed to produce. This can also simplify
makefiles a great deal.
For more details on building with multiple directories, see
"Tips for multiple directories" in makepp_cookbook.
- Reliable
wildcards
- Makefiles can use wildcards reliably, because wild cards match either
files that exist, or files that do not yet exist but makepp knows
how to build. So even for a program with dozens of modules, your entire
makefile could simply read something like this:
CXX = g++
CXXFLAGS = -g
%.o : %.c
$(CXX) $(CXXFLAGS) -c $(input) -o $(output)
my_program: *.o
$(CXX) $(inputs) -o $(output)
and this will work even if none of the
".o" files have been built yet.
- Reliable builds:
remembers build command
- Makepp keeps track of the build commands, so that if compilation options
change, files are automatically rebuilt. This is important to guarantee
correct builds. (This idea was taken from Bob Sidebothem's
"cons" utility, which was described in the Perl Journal in 1998
and is available from CPAN.)
To illustrate why this is important, consider the following
structure definition:
class ABC {
int x;
#ifndef SPECIAL_OPTION
int y;
#endif
int z;
};
Now suppose you decide to turn on the
"SPECIAL_OPTION" option by adding
"-DSPECIAL_OPTION" to the command
line. A recompilation of everything is needed, but a traditional Unix
make will not detect this, and will only recompile source files which
have actually changed. As a result, some of your modules will be
compiled with -DSPECIAL_OPTION, and others won't. After a very
frustrating debugging session, you will discover that all that needs to
be done is to rebuild everything. Then you will curse make and hopefully
switch to an improved implementation of it, like makepp. At least,
that's what I did.
As another example, suppose that you are working on a project
which is pretty well debugged, so it's usually compiled with
"-O2". Now you run into a bug which
you need to look at in the debugger. Code compiled with optimization is
difficult to examine in the debugger, so you want to recompile your code
so that you can look at it. If your makefile is set up to store the
compiler options in the usual variables, you can just do this:
makepp CFLAGS=-g CXXFLAGS=-g
and makepp will know that the command line has changed for all
the modules. Then when you've found your bug, just type
makepp
and it will be recompiled with optimization. You don't need to
type "make clean" when you change
build options.
Some makefiles (e.g., those for the Linux kernel) go to
incredible lengths to force recompilation when the compile command
changes. With makepp, it's taken care of automatically--you don't have
to do anything.
- Reliable builds:
exact matching of signature
- By default, makepp doesn't merely ensure that all targets are newer than
all dependencies; if you replace a dependency with an older file, makepp
knows that it has to rebuild the target, simply because the input file has
changed. This is another important feature to guarantee correct builds
which was taken from the "cons" utility.
- Smart signature
calculations
- Some modifications to source files do not actually require a rebuild. For
example, if you just change a comment line, or if you reindent some code,
there is no particular reason to force a compilation. For C/C++
compilation, makepp determines whether a file needs recompilation by
computing a cryptographic checksum of the file's contents, ignoring
comments and whitespace, instead of looking at the file time.
This is particularly useful if you have include files that are
generated by files that change, and yet the generated include files
themselves seldom change. Suppose you have a complicated yacc grammar in
your program, with a build rule like this:
y.tab.c y.tab.h: parser.y
yacc -d parser.y
Ordinarily, every time you make even a tiny change to
"parser.y", every file that depends on
"y.tab.h" must be rebuilt since the
file time of "y.tab.h" has changed.
However, most changes to "parser.y"
won't actually change the contents of
"y.tab.h" (except possibly a comment),
so all that recompilation is unnecessary.
- Repositories
- Makepp can automatically incorporate files from a different directory tree
(the "repository") into the current build tree as needed. (This
idea was also taken from the "cons" program.) This has several
interesting uses:
- Variant builds
- Suppose you have been compiling your program with optimization on and
debugging off. Now a bug crops up and you have to recompile everything
with debugging enabled. Once you find the bug, however, you're going to
turn debugging off and optimization back on, and with most make programs
you would have to recompile all the sources again, even the ones that did
not change. The procedure would look like this:
% makepp CFLAGS=-O2 # Compile everything.
# oops, bug discovered here
% makepp CFLAGS=-g # Recompiles everything again.
gdb my_program
# ... find the bug
% makepp CFLAGS=-O2 # Recompiles everything a third time.
With makepp, you can simply cd to an empty directory, and
specify your original directory as a repository. This will create new
object files in the empty directory, while leaving your old object files
intact. Now you can find the bug in the directory compiled with debug,
fix it in your original sources, and then go back to your original
directory. Now only the few files that you changed actually need to be
recompiled.
The entire procedure would look like this:
% makepp CFLAGS=-O2 # Compile everything.
# oops, bug discovered here
% mkdir debugging
% cd debugging
% makepp -R .. CFLAGS=-g # Compile with debugging enabled, but
# put objects in debugging subdir.
% gdb my_program
# ... find the bug
% cd .. # Back to original directory.
% makepp CFLAGS=-O2 # Recompiles only those files
# that you changed.
This can be a tremendous savings in time if there are many
modules.
- Development team
with common sources
- Suppose you have a team of developers working on a standard set of
sources. Each developer is making independent changes, but doesn't need to
have a copy of the whole source tree. Using makepp's repositories, you can
have each developer have copies only of the files he has changed. Makepp
will automatically and temporarily create symbolic links for the other
files that have not been changed to the corresponding files in the
repository. It can even do this for object files which exist in the
repository and do not need to be recompiled in the developer's individual
directory.
- Guarantee correct
rules
- If your rules do somthing which you didn't tell makepp about, the
repository mechanism will not know to fetch those things. So something
that builds normally but fails from a repository tells you to fix your
rules.
- Automatic
inference of needed ".o" files
- Makepp can often infer exactly which objects are actually necessary
without being explicitly told. If you use this feature, then if one of
your source file includes "xx.h", and
there is a file called "xx.o" that
makepp knows how to make, then makepp adds
"xx.o" to the link command line. I don't
use non-shared libraries now in many places where I used to, because
makepp can automatically pick out the modules I need.
- Correct handling of
aliases for directories
- Makepp won't be confused by soft links to a directory or by different
relative filenames that refer to the same file. All directory paths to a
file are recognized, including foo, ./foo,
../src/foo, /auto_mnt/somedisk/bob/src/foo, and
/users/bob/src/foo.
- Filenames with
special characters
- Makepp can support filenames with colons or spaces or other special
characters that cause trouble for the traditional make. Just surround the
filename with quotes. (See "Special characters" in makepp_rules
for details.)
- Extensible textual
substutition functions
- Makepp can use arbitrary Perl subroutines for textual substitution in the
makefile. If you know Perl, you are not constrained at all by the set of
makepp's builtin textual manipulation functions.
You can also simply write Perl code in your makefile. You can
manipulate Make variables with the full power of the entire Perl
language. See makepp_variables for details.
- Logging of build
decisions
- By default, makepp makes a log-file viewable with makepplog, mppl that
contains a description of every file that it tried to build, what rule was
used to build it, what it depended on, and (if the file was rebuilt) why.
This can be extremely useful for debugging a makefile--if you're wondering
why makepp decided to rebuild a file, or why it didn't, you can just look
in the log file where it explains the decisions.
- Improved support for
parallel builds
- Makepp supports parallel compilations, but (unlike other make
implementations) it won't mix output from separate processes which are
running simultaneously.
- Synonyms for cryptic
variables
- Makepp supports easier-to-remember synonyms for the cryptic make variables
$@, $^, and
$<. See makepp_variables for details.