Makepp was designed to be as close as possible to GNU make. However, because of the difference in philosophy (see makepp_build_algorithm), some of GNU make's features cannot be supported. Others have not been implemented because I haven't had time. Also, in order to emulate GNU make's behavior precisely, you may in some cases have to add additional command line options to the makepp command line, as noted below. Most of the differences from GNU make are quite technical and only rarely cause problems.
Makepp will give warning messages for many things which the traditional unix
make accepts without flinching. This is because there are better ways to do
them with makepp. If these warnings annoy you, you can turn them off with the
--nowarn command line option.
VPATHvariable is currently ignored.
vpathstatements are unsupported and will cause errors. Use repositories (see makepp_repositories) instead.
--percent-subdirsoption, in its subdirectories). This means that a rule like this:
will not be applied to files like
includestatement unless the makefile contains a rule for building them before the include statement is seen. (It will attempt to rebuild the makefile itself, however.) This is normally used for handling include file dependencies, and is not as useful with makepp since you don't need to do that anyway.
SHELLvariable is currently ignored. makepp always uses
$?is equivalent to
$+. See the the description of
$?for the reasons.
.PHONY. The remaining are simply ingored.
Specifically, GNU make has the following special targets:
.SUFFIXESexcept for the special case of
.SUFFIXESwith no dependencies, like this:
which tells it not to load any of its default rules.
ignore_error(or a minus sign) in front of the command whose exit status is to be ignored.
@character) in front of the command which is not supposed to be echoed.
$(wildcard )function matches not only files which exist, but also files which do not yet exist, but which have a rule which makepp has seen at the time the
$(wildcard )function is evaluated.
overridestatement is not supported.
-includewill not attempt to make the include file if it doesn't exist. Also, if the file exists but is out of date with respect to its dependencies, it will not be remade; it is not considered an implicit target.
This is usually used for files containing dependency information, and since
makepp is able to compute a lot of this without depending on additional tools,
-include is not as important as it used to be.
The makefile itself is ordinarily considered an implicit target. It will be rebuilt and reread if any of its dependencies have changed since the last time makepp rebuilt it.
definestatement) are not supported.
prog : CFLAGS = -g prog : prog.o foo.o bar.o
and each of the
.o files that will be compiled with
-g. This will
<bnot</b work with makepp. The reason is that it can lead to inconsistent
builds. Consider the following makefile:
all: prog1 prog2 .PHONY: all CFLAGS = -O2 prog1: prog1.o a.o b.o $(CC) $(CFLAGS) $^ -o $@ prog2: CFLAGS = -g prog2: prog2.o a.o b.o $(CC) $^ -o $@ %.o: %.c $(CC) $< $(CFLAGS) -c -o $@
Now with the above makefile, suppose the user types
make all. What
compilation option will
b.o be compiled with? There are
contradictory specifications for
prog2. The file
only be compiled once on each invocation of makepp, so it cannot be compiled
both ways. The result is an incorrect build of at least one of the programs.
For this reason, makepp does not propagate target-specific variables to
prerequisites of a rule.
%in a pattern rule does not match directories. Thus
.cfiles in the current directory. If you want it to match files in subdirectories too, then add the
--percent-subdirsoption to the command line. You can also enable this in your makefile by the assignment
By default, makepp will attempt to rebuild all targets if any of the
dependencies have changed since the last build, or if the command has changed
(see makepp_signatures for details). This is normally what you want.
Sometimes, however, you don't want the target to be rebuilt if it has been
modified apart from the control of makepp (e.g., by editing it, or by running
a program manually to make the file). You can force makepp to use the
traditional make algorithm, which only rebuilds if any of the targets are
newer than the dependencies, by adding the option
-m target_newer to the
As a special exception, any targets which are built while rebuilding the
makefile are automatically checked using the
target_newer method in order
to avoid problems with configure procedures.
Recursive invocations of make are often considered to be an unsafe practice
(see makepp/Better system for hierarchical builds for details), but they
are extremely common in existing makefiles. Makepp supports recursive make
for backward compatibility; for new makefiles, it is much better to use the
load_makefile statement, or makepp's implicit makefile loading mechanism.
In order to be able to use repositories for variant builds, and to help make recursive invocations of make safter, makepp normally does not actually invoke itself recursively even if you tell it to. Instead, a subprocess communicates with the parent process, and the actual build is done by the parent process.
This works in most cases, but there are a few incompatibilities. (All of
these incompatibilities are removed by adding the
--traditional-recursive-make option to the command line.)
target: dependencies $(MAKE) -f other_makefile targets
However, this will work:
target: dependencies cd subdir && $(MAKE) -f other_makefile targets
MAKEFLAGSvariable is not set up, and altering it has no effect.
This may seem like a long list of restrictions, but many makefiles obey them.
For example, as far as I know, all makefiles produced by
All of these restrictions go away if you add the
--traditional-recursive-make option to the command line, but that has the
following undesirable side effects:
Even with the
--traditional-recursive-make option, the environment
MFLAGS not set up, and are ignored, so
makefiles that depend on those will not work.
Rc-style substitution is the default way makepp performs variable substitution into text strings because it very rarely breaks legacy makefiles and is often useful in new makefiles. However, it does introduce occasional incompatibilities in the substitution of variables not surrounded by spaces. For example,
INCLUDE_PREFIX := -I/some/include/dir -I INCLUDES := $(INCLUDE_PREFIX)/other/include/dir
if rc-style substitution is enabled, whereas GNU make would set it
There is also an incompatibility in the handling of whitespace in a variable:
null := T := -o $(null) # T contains -o followed by one space. OUTFILE = $(T)outfile
-ooutfile if rc-style substitution is enabled,
whereas GNU make would set it to
Both of these incompatibilities are removed by the
option. Note, however, that even with
--norc-substitution, makepp still
treats whitespace incompatibly in some situations:
T := -o # Don't delete this comment.
GNU make sets
T to contain
-o followed by a space, whereas makepp strips
out the trailing space anyway. If you want the trailing space, you must
--norc-substitution and also set
T using the technique involving
a dummy variable such as
null, as shown above.
At present, you may not combine single character options into a single word.
E.g., you may not say
makepp -ejk 2 instead of
makepp -e -j 2 -k.
Makepp supports a few of make's more useful command line options. The following, however, are not supported, and are ignored after a warning message is printed:
-moption has to do with signature method selection, whereas GNU make ignores -m.
-qoption suppresses makepp's chatty informational messages, which is different from -q in GNU make.
-Roption actually does something completely different.
Some of these can be easily supported if anyone cares.