=head1 NAME
makepp_incompatibilities -- Incompatibilities between makepp and GNU make
=
for
vc
$Id
: makepp_incompatibilities.pod,v 1.37 2012/03/25 18:34:48 pfeiffer Exp $
=head1 DESCRIPTION
Makepp was designed to be as
close
as possible to GNU make
see L<remark below|/Compatibility via the option:
--traditional-recursive-make>) 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 L<philosophy|makepp_build_algorithm>,
some of GNU make
's or POSIX make'
s
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.
=head1 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.
=head2 Compatibility via the option: C<--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 L<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.
=head2 Compatibility via the option: C<--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 C<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.
=head2 Compatibility via the option: C<--
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
L<:last_chance|makepp_rules/last_chance> mechanism partially remedies that.
Where this is good enough
for
legacy makefiles, this option allows turning it
on globally.
=head2 Compatibility via the option: C<--
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.
=head2 Compatibility via the option: C<--hybrid-recursive-make>
Recursive invocations of make are often considered to be an unsafe practice
(see L<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
C<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
=head2 Compatibility via the option: C<--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:
=over 4
=item *
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.
=item *
Recursive make processes
do
not know anything about repositories.
=item *
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.
=item *
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.
=back
Even
with
the C<--traditional-recursive-make> option, the environment
variables C<MAKEOVERRIDES> and C<MFLAGS> are not set up, and ignored, so
makefiles that depend on those will not work.
A B<Premake> generated F<Makefile> is only a funny wrapper to a
sub
-make
invocation in the same directory. If you have some project target I<XYZ> it
will have a line like
@${MAKE} --
no
-
print
-directory -C . -f XYZ.make
In this case you can avoid the C<--traditional-recursive-make> option by
directly invoking makepp
with
that C<-f I<XYZ>.make> option.
=head2 Compatibility without the option: C<--jobs=I<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.
=head2 Compatibility via the variable: C<makepp_simple_concatenation=1>
L<Rc-style substitution|makepp_variables/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 C<INCLUDES> to
S<C<-I/some/include/dir/other/include/dir -I/other/include/dir>>
if
rc-style substitution is enabled, whereas GNU make would set it
to S<C<-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)
OUTFILE = $(T)outfile
will set C<OUTFILE> to C<-ooutfile>
if
rc-style substitution is enabled,
whereas GNU make would set it to S<C<-o outfile>>.
Both of these incompatibilities are removed by setting the
C<makepp_simple_concatenation> variable. Note, however, that even
with
C<makepp_simple_concatenation>, makepp still treats whitespace incompatibly in
some situations:
T := -o
GNU make sets C<T> to contain C<-o> followed by a space, whereas makepp strips
out the trailing space anyway. If you want the trailing space, you must set
C<makepp_simple_concatenation> and also set C<T> using the technique involving
a dummy variable such as C<null>, as shown above.
=head2 Workaround option C<--defer-include>
Makepp reads makefiles in a single pass, where GNU make is multipass. Hence
this will not work, because F<GIT-VERSION-FILE> must be built to process the
C<include> statement. But it depends on something that is unknown at this
point. To solve this, the C<.PHONY> declaration must be moved up
before
the
C<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.
=head2 Workaround option C<--
no
-remake-makefiles>
Typical
open
source requires calling C<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.
=head2 Compatibility via the variable: C<makepp_percent_subdirs=1>
By
default
, C<%> 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 C<../shared/xyz.c>. If you want it to match
files in subdirectories too, then set the variable C<makepp_percent_subdirs=1>
on the command line or near the beginning of a makefile.
=head2 Compatibility via the environment variable: C<
$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:
=over 4
=item --I<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 C<--long=bla> or C<--long bla>.
=item --I<long>
A long option without an argument.
=item -I<s>x
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 C<-sbla> or C<-s bla>.
=item -I<s>
A short option without an argument.
=back
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'
=head1 Incompatibilities that
require
Makefile changes
=over 4
=item *
Makefiles that explicitly call make prevent makepp from building everything
itself. Alas Perl's own C<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
=item *
Setting the C<VPATH> variable to some value implicitly calls C<vpath % value>.
C<vpath> statements are emulated
with
the L<repository|makepp_repositories>
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.
=item *
A pattern rule present later in a makefile overrides one that is present
earlier. This is backwards from GNU make.
=item *
The set of L<builtin implicit rules|makepp_builtin> 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.
=item *
An action prefix of C<+> is silently ignored.
=item *
Archive members are not supported, and neither are the associated automatic
variables C<$%>, C<$(
%D
)>, and C<$(
%F
)>.
=item *
There is
no
SCCS support.
=item *
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 L<makepp_variables/Whitespace in variables>.
=item *
Makepp does not attempt to rebuild files included
with
the C<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.
=item *
The C<SHELL> variable is currently partially ignored. Makepp always uses
F</bin/sh>
unless
F</usr/xpg4/bin/sh> or F</sbin/xpg4/sh> is found or
unless
you export the C<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
B<
before
> calling makepp.
=item *
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.
=item *
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.
=item *
The only special target that is supported is C<.PHONY> and partially
C<.SUFFIXES>. The remaining are simply ingored.
Specifically, GNU make
has
the following special targets:
=over 4
=item .SUFFIXES
Makepp ignores C<.SUFFIXES> except
for
the special case of C<.SUFFIXES>
with
no
dependencies, like this:
.SUFFIXES:
which tells it not to load any of its
default
rules.
=item .INTERMEDIATE, .SECONDARY, .PRECIOUS
No special status is accorded to intermediate files and so these targets are
not meaningful.
=item .IGNORE
This target is ignored. If you want to ignore errors, put the word
C<ignore_error> (or a minus sign) in front of the command whose
exit
status is
to be ignored.
=item .SILENT
This target is ignored. If you want commands not to echo, put the word
C<noecho> (or the C<@> character) in front of the command which is not
supposed to be echoed, or
use
the C<--silent> option to makepp.
=item .DELETE_ON_ERROR
=item .EXPORT_ALL_VARIABLES
=item .NOEXPORT
=item .POSIX
=item .DEFAULT
These targets are not supported and are simply ignored.
=back
=item *
The GNU make functions C<
eval
>, C<flavor> and C<value> are not currently
supported. You can achieve the same thing as
eval
in a more straight-forward
way
with
C<$[...]> variable or function expansion.
=item *
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
a :: c
&cat
c -o >>a
it is B<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 C<clean> or
for
all the stuff that ExtUtils::MakeMaker puts into its makefiles. Don't
count on it
for
anything other than legacy makefiles.
=item *
The S<C<$(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 S<C<$(wildcard )>> function is evaluated.
=item *
The C<define> statement is supported, but handling of C<@> preceding it
is done differently. Currently in makepp, C<@> 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 S<C<
&echo
line2>> as it does in GNU make;
it will only suppress printing of S<C<
&echo
line1>>.
=item *
Makepp does not support the following environment variables (it does not set
them up, and it just ignores them):
=over 4
=item MAKEOVERRIDES
=item MFLAGS
=back
=back
=head2 Incompatibilities in order of expression expansion
=over 4
=item *
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 F<bar> is also a
dependency of this rule, and makepp can now
catch
it
when
lexically analyzing
the redirection.
=item *
Though I have not seen this used, GNU make allows the following:
colon = :
a$(colon) b
echo $^
Makepp expands C<$(colon)> too late
for
this to work. However it offers the
alternative C<$[colon]> syntax, which can
do
much more than GNU make, because
it is expanded very early.
=back
=head2 C<$(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
C<--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 C<
'$(MAKE)'
>. which doesn't break backward compatibility.
=head2 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
L<Target-specific assignments|makepp_variables/target_specific_assignments>.
=head2 Parentheses or braces don't nest
Makepp ends expressions at the first matching parenthesis or brace. Instead
of this
$(somefunction ... ( ) ...)
${somefunction ... ( ) ...}
$((somefunction ... ( ) ...))
This will probably be fixed in version 2.1, maybe optionally.
=head2 Minor points
=over
=item Pattern dependencies don't match phony targets
%.a: %.b; ...
$(phony x.b): ; ...
=item Comments don't have continuation lines
NOT a 2-line comment
=back
=head1 Command line incompatibilities
Makepp supports a few of make's more useful command line options. The
following, however, are not supported:
=over 4
=item -d or --debug
=item -f -
Makepp
's internal makefile objects are linked to file objects, so it can'
t
handle stdin.
=item -i
=item -l or --load-average or --max-load
=item -m
Makepp's C<-m> option
has
to
do
with
signature method selection, whereas GNU
make ignores -m.
=item -p or --
print
-data-base
=item -
q or
--question
=item -R or --
no
-builtin-variables
Makepp's C<-R> option actually does something completely different.
=item -S --
no
-keep-going or --stop
The C<--stop> option stops (puts to
sleep
) makepp
after
learning all the
rules, so you can
continue
editing.
=item -t or --touch
=item -w or --
print
-directory
This happens automatically.
=item --
warn
-undefined-variables
=back
Some of these can be easily supported
if
anyone cares.