DragonFly On-Line Manual Pages
MAKEPP_INCOMPATIBILITIES(1) Makepp MAKEPP_INCOMPATIBILITIES(1)
NAME
makepp_incompatibilities -- Incompatibilities between makepp and GNU
make
DESCRIPTION
Makepp was designed to be as close as possible to GNU make
(<http://www.gnu.org/software/make/manual/make.html>). Gnu autotools
(<http://www.gnu.org/software/automake/manual/automake.html>), CMake
(<http://www.cmake.org/>), Premake (<http://industriousone.com/premake>
and see remark below) or handcrafted legacy build systems should be
buildable with makepp. This is so you can either migrate projects
effortlessly. Or if you don't want to enjoy all of makepp's advantages
(e.g. so others can still build your project with GNU make) while you
profit from the reliability advantage for your development.
However, because of the difference in philosophy, some of GNU make's or
POSIX make's
(<http://pubs.opengroup.org/onlinepubs/009695399/utilities/make.html>)
features cannot be supported. A few have not been implemented because
we haven't had time. Most of the differences from GNU make are quite
technical and only rarely cause problems. Alas the workarounds for the
short-comings of traditional make are becoming more and more complex,
and are giving makepp a hard time.
In a nutshell, if it doesn't build out of the box, try:
makepp --no-warn makepp_simple_concatenation=1 makepp_percent_subdirs=1 \
--build-check=target_newer --last-chance-rules --no-remake-makefiles
If that succeeds, you can try to eliminate those arguments one by one.
But if that fails, try adding either one or both of:
--defer-include
--traditional-recursive-make
If that also fails, the build system needs some tweaking to cooperate
with makepp. Even if some options described here make something
buildable, it is still recommended to adapt things slightly, so they
become compatible out of the box with both makes.
Forcing more POSIX or GNU make compatibility
Here are some command line possibilities for getting many legacy build
systems to work without modification. They cause makepp to emulate GNU
make's behavior precisely.
Compatibility via the option: "--build-check=target_newer"
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_build_check 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 this option to the command line.
Compatibility via the option: "--dont-build=config.status"
There are packages which try to autoconfigure themselves, or do other
things, which gmake ignores unless being asked to, like:
config.status : configure
./config.status --recheck
configure : configure.in aclocal.m4
autoconf
Most people don't even have "autoconf" installed, so conscientiously
doing everything by the rules, as makepp does, will fail. This option
prevents that, if you figure out what not to build.
Compatibility via the option: "--last-chance-rules"
Default rules (pattern rules with no pattern dependencies) are not
normally supported. Makepp instantiates all rules based on the
existing files, so that it is aware of every file that could be
generated. Alas this way it does not know how to instantiate a pattern
rule with no pattern dependency. The :last_chance mechanism partially
remedies that. Where this is good enough for legacy makefiles, this
option allows turning it on globally.
Compatibility via the option: "--no-warn"
This one doesn't improve the result. 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 this
option.
Compatibility via the option: "--hybrid-recursive-make"
Recursive invocations of make are often considered to be an unsafe
practice (see "Better system for hierarchical builds" in makepp 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 safer, 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 you may not invoke several makefiles from
the same directory, e.g., the following will not work:
target: dependencies
$(MAKE) -f other_makefile targets
In this case makepp notices it is loading a 2nd makefile and complains.
With this option instead it will fall back to the traditional way of
building from additional makefiles in a separate makepp process each.
Note: Technically loading several makefiles would be no problem, but
they usually have the same phony target names. Keeping that apart
would mean a complete redesign of makepp internals. However, this will
work, but it is not equivalent:
target: dependencies
cd subdir && $(MAKE) -f other_makefile targets
Compatibility via the option: "--traditional-recursive-make"
Sometimes the previous option is not enough, especially if the
recursive invocations use contradictory options. Makepp uses only one
set of global options, so a submake is not allowed to modify them, as
that would also pertain to other makefiles.
Adding this option to the command line, has the following undesirable
side effects:
o Recursive makes do not internally execute in parallel, even if the
parent does. Unlike gmake there is no overall coordination of the
number of processes. This will not be implemented because this way
of working is not a design goal of makepp.
o Recursive make processes do not know anything about repositories.
o Each recursive make process produces its own log file, in the
directory it is invoked in, instead of producing one log file for
the entire build.
o Since makepp usually builds more than traditional make deems
necessary, and since many build systems provide recursive calls in
all directions, this may lead to endless recursion. Makepp will
pull the brake after 50 rounds and tell you how to increase that,
in case you really have such deep nesting.
Even with the "--traditional-recursive-make" option, the environment
variables "MAKEOVERRIDES" and "MFLAGS" are not set up, and ignored, so
makefiles that depend on those will not work.
A Premake generated Makefile is only a funny wrapper to a sub-make
invocation in the same directory. If you have some project target XYZ
it will have a line like
@${MAKE} --no-print-directory -C . -f XYZ.make
In this case you can avoid the "--traditional-recursive-make" option by
directly invoking makepp with that "-f XYZ.make" option.
Compatibility without the option: "--jobs=n"
Legacy makefiles will sometimes not list all dependencies, relying on
the order of execution to make them in time. In this situation makepp
may manage to call a rule before its dependencies have all been made.
Then results may be better with less, or even no parallel execution.
Compatibility via the variable: "makepp_simple_concatenation=1"
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
will set "INCLUDES" to
"-I/some/include/dir/other/include/dir -I/other/include/dir" if rc-
style substitution is enabled, whereas GNU make would set it to
"-I/some/include/dir -I/other/include/dir".
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
will set "OUTFILE" to "-ooutfile" if rc-style substitution is enabled,
whereas GNU make would set it to "-o outfile".
Both of these incompatibilities are removed by setting the
"makepp_simple_concatenation" variable. Note, however, that even with
"makepp_simple_concatenation", 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 set "makepp_simple_concatenation" and also set "T" using the
technique involving a dummy variable such as "null", as shown above.
Workaround option "--defer-include"
Makepp reads makefiles in a single pass, where GNU make is multipass.
Hence this will not work, because GIT-VERSION-FILE must be built to
process the "include" statement. But it depends on something that is
unknown at this point. To solve this, the ".PHONY" declaration must be
moved up before the "include" statement:
GIT-VERSION-FILE: FORCE
@$(SHELL_PATH) ./GIT-VERSION-GEN
include GIT-VERSION-FILE
.PHONY: FORCE
This option internally reorders the include statements to the end of
the makefile. That may in turn cause variables to have different
values, in which case you should set the problematic ones on the
command line.
Workaround option "--no-remake-makefiles"
Typical open source requires calling "configure" to create the
makefiles. But then these makefiles can contain rules to remake the
makefile, by calling some command. Makepp will happily comply and
update it according to the rule. But sometimes this is harmful, so
just skip it.
Compatibility via the variable: "makepp_percent_subdirs=1"
By default, "%" in a pattern rule does not match directories. This
means that a rule like this:
%.o: %.c
$(CC) $(CFLAGS) -c $(input) -o $(output)
will not be applied to files like "../shared/xyz.c". If you want it to
match files in subdirectories too, then set the variable
"makepp_percent_subdirs=1" on the command line or near the beginning of
a makefile.
Compatibility via the environment variable: $MAKEPP_IGNORE_OPTS
Sometimes legacy recursive invocations pass options that makepp doesn't
understand. Hopefully the option is not important, but it prevents
makepp from running. With this environment variable you can ask makepp
to silently ignore certain options. The value shall be a space
separated list of options, which can come in 4 variants:
--long=x
A long option that expects an argument. This fact must be declared
through the equals sign, though the actual use may also separated
by whitespace, either "--long=bla" or "--long bla".
--long
A long option without an argument.
-sx A short option that expects an argument. This fact must be
declared by adding something directly after the option, though the
actual use may also separated by whitespace, either "-sbla" or "-s
bla".
-s A short option without an argument.
E.g. override makepp's -R option by one without an argument and accept
gmake's debug option with an argument:
export MAKEPP_IGNORE_OPTS='-R --debug=x'
Incompatibilities that require Makefile changes
o Makefiles that explicitly call make prevent makepp from building
everything itself. Alas Perl's own "ExtUtils::MakeMaker" commits
the second of the following two forms of this mistake up to version
6.56 (Perl 5.12.1):
subdir:
cd subdir; make
MAKE = make
o Setting the "VPATH" variable to some value implicitly calls "vpath
% value". "vpath" statements are emulated with the repository
mechanism. So, where gmake substitutes the path to the file found
in the vpath, makepp will instead link it symbolically to where it
is needed. Thus makepp will provide an unmodified string, which is
usually not a problem.
Targets in a vpath are not supported. (Gmake considers them if
they are newer than their dependencies, but if not, the target will
be recreated in the current directory -- rather inconsistent.)
Unsetting vpaths is not supported.
o A pattern rule present later in a makefile overrides one that is
present earlier. This is backwards from GNU make.
o The set of builtin implicit rules is somewhat different from those
for GNU make, though the variable names are largely compatible.
The builtin rules should successfully compile C/C++/Fortran
programs, and in fact may be able to guess the proper libraries in
some cases too. Support for Modula-2 and RatFor and other rare
languages is deliberately not present, because I kept running into
problems with GNU make's rules when I accidentally reused the
extensions for those languages.
o An action prefix of "+" is silently ignored.
o Archive members are not supported, and neither are the associated
automatic variables $%, "$(%D)", and "$(%F)".
o There is no SCCS support.
o Leading and trailing whitespace in variable assignments is ignored
(even if the whitespace is followed by a comment). For more
details on whitespace handling incompatibilities, see "Whitespace
in variables" in makepp_variables.
o Makepp does not attempt to rebuild files included with the
"include" statement 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.
o The "SHELL" variable is currently partially ignored. Makepp always
uses /bin/sh unless /usr/xpg4/bin/sh or /sbin/xpg4/sh is found or
unless you export the "SHELL" variable in your makefile. But if
you do, the command parser might not fully understand what your
shell command does. On Windows Strawberry or ActiveState Perl you
must instead set your SHELL variable before calling makepp.
o Dependencies of anything on the Makefile still work, but are
usually unnecessary. This is usually used to force a rebuild when
compilation options change. Makepp knows when build commands have
changed without anything special in the makefile; it stores this on
a file-by-file basis. If you change the makefile, it knows exactly
which files need recompilation.
o Intermediate files are not deleted. (Because makepp insists on
having all of the file dates be the same as they were on the last
build, intermediate files must all be present or else rebuilds will
occur.) There is no special status accorded to intermediate files.
o The only special target that is supported is ".PHONY" and partially
".SUFFIXES". The remaining are simply ingored.
Specifically, GNU make has the following special targets:
.SUFFIXES
Makepp ignores ".SUFFIXES" except for the special case of
".SUFFIXES" with no dependencies, like this:
.SUFFIXES:
which tells it not to load any of its default rules.
.INTERMEDIATE, .SECONDARY, .PRECIOUS
No special status is accorded to intermediate files and so
these targets are not meaningful.
.IGNORE
This target is ignored. If you want to ignore errors, put the
word "ignore_error" (or a minus sign) in front of the command
whose exit status is to be ignored.
.SILENT
This target is ignored. If you want commands not to echo, put
the word "noecho" (or the "@" character) in front of the
command which is not supposed to be echoed, or use the
"--silent" option to makepp.
.DELETE_ON_ERROR
.EXPORT_ALL_VARIABLES
.NOEXPORT
.POSIX
.DEFAULT
These targets are not supported and are simply ignored.
o The GNU make functions "eval", "flavor" and "value" are not
currently supported. You can achieve the same thing as eval in a
more straight-forward way with "$[...]" variable or function
expansion.
o Double colon rules are not fully supported. (They cannot be: in
makepp's paradigm, there cannot be more than one way to update a
target.) Currently, each successive double colon rule for a given
target simply appends its command string and dependency list to the
command string and dependency list for this target. For example,
if you write this:
a :: b
&cat b -o a
# Later in your makefile:
a :: c
&cat c -o >>a
it is exactly the same as if you had written
a : b c
&cat b -o a
&cat c -o >>a
This is certainly not what double colon rules are intended for, and
it will not always work, but it does work for targets like "clean"
or for all the stuff that ExtUtils::MakeMaker puts into its
makefiles. Don't count on it for anything other than legacy
makefiles.
o The "$(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.
o The "define" statement is supported, but handling of "@" preceding
it is done differently. Currently in makepp, "@" in front of a
variable which has a multi-line value will only suppress echoing of
the first line. For example,
define echo-lines
&echo line1 -o $@
&echo line2 -o>>$@
endef
x:
@$(echo-lines)
will not suppress printing of "&echo line2" as it does in GNU make;
it will only suppress printing of "&echo line1".
o Makepp does not support the following environment variables (it
does not set them up, and it just ignores them):
MAKEOVERRIDES
MFLAGS
Incompatibilities in order of expression expansion
o In makepp, rule actions are expanded before all of the dependencies
are guaranteed to have been built. You can work around this by
changing rules such as this:
foo: bar
genfoo < $(shell cat bar)
to this:
foo: bar
genfoo < `cat bar`
or this, which will make the file during the expansion:
foo: bar
genfoo < $(&cat $(make bar))
This is preferable here, because the file listed in bar is also a
dependency of this rule, and makepp can now catch it when lexically
analyzing the redirection.
o Though I have not seen this used, GNU make allows the following:
colon = :
a$(colon) b
echo $^
Makepp expands "$(colon)" too late for this to work. However it
offers the alternative "$[colon]" syntax, which can do much more
than GNU make, because it is expanded very early.
"$(MAKE)" may include spaces
In an uninstalled makepp or if the platform doesn't seem to support
starting a Perl script by magic number or with
"--traditional-recursive-make" this variable will include at least one
space. That is not a problem when using it as a command. But when
passing it as an unquoted parameter to a script (as the Perl 5.14.0
build system does), it will tear it apart into separate parameters,
leading to confusion. So as a parameter it is safer to quote it as
'$(MAKE)'. which doesn't break backward compatibility.
Target-specific assignments don't propagate
Makepp's target-specific variables are slightly different from GNU
make's in that they only apply to the rule for the one file mentioned,
and not to any of its predecessors; see Target-specific assignments.
Parentheses or braces don't nest
Makepp ends expressions at the first matching parenthesis or brace.
Instead of this
$(somefunction ... ( ) ...) # Gnu make style
you must use either of these
${somefunction ... ( ) ...} # Gnu make compatible
$((somefunction ... ( ) ...)) # Makepp extension
This will probably be fixed in version 2.1, maybe optionally.
Minor points
Pattern dependencies don't match phony targets
%.a: %.b; ...
$(phony x.b): ; ... # does not provide a way to build x.a
Comments don't have continuation lines
# This is \
NOT a 2-line comment
Command line incompatibilities
Makepp supports a few of make's more useful command line options. The
following, however, are not supported:
-d or --debug
-f -
Makepp's internal makefile objects are linked to file objects, so
it can't handle stdin.
-i
-l or --load-average or --max-load
-m Makepp's "-m" option has to do with signature method selection,
whereas GNU make ignores -m.
-p or --print-data-base
-q or --question
-R or --no-builtin-variables
Makepp's "-R" option actually does something completely different.
-S --no-keep-going or --stop
The "--stop" option stops (puts to sleep) makepp after learning all
the rules, so you can continue editing.
-t or --touch
-w or --print-directory
This happens automatically.
--warn-undefined-variables
Some of these can be easily supported if anyone cares.
perl v5.20.3 2012-03-19 MAKEPP_INCOMPATIBILITIES(1)