[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
make
itself suffers a great number of limitations, only a few
of which are listed here. First of all, remember that since commands
are executed by the shell, all its weaknesses are inherited....
$<
make
for instance
will replace it with the argument.
make
s don't support leading underscores in macro names,
such as on NEWS-OS 4.2R.
$ cat Makefile _am_include = # _am_quote = all:; @echo this is test $ make Make: Must be a separator on rules line 2. Stop. $ cat Makefile2 am_include = # am_quote = all:; @echo this is test $ make -f Makefile2 this is test |
make
will read multiple newlines
following a backslash, continuing to the next non-empty line. For
example,
FOO = one \ BAR = two test: : FOO is "$(FOO)" : BAR is "$(BAR)" |
shows FOO
equal to one BAR = two
. Other make
s
sensibly let a backslash continue only to the immediately following
line.
According to POSIX, `Makefile' comments start with #
and continue until an unescaped newline is reached.
% cat Makefile # A = foo \ bar \ baz all: @echo ok % make # GNU make ok |
However in Real World this is not always the case. Some implementations
discards anything from #
up to the end of line, ignoring any
trailing backslash.
% pmake # BSD make "Makefile", line 3: Need an operator Fatal errors encountered -- cannot continue |
Therefore, if you want to comment out a multi-line definition, prefix each
line with #
, not only the first.
# A = foo \ # bar \ # baz |
make macro=value
and sub-make
s.
A command-line variable definition such as foo=bar
overrides any
definition of foo
in the `Makefile'. Some make
implementations (such as GNU make
) will propagate this
override to sub-invocations of make
. This is allowed but not
required by POSIX.
% cat Makefile foo = foo one: @echo $(foo) $(MAKE) two two: @echo $(foo) % make foo=bar # GNU make 3.79.1 bar make two make[1]: Entering directory `/home/adl' bar make[1]: Leaving directory `/home/adl' % pmake foo=bar # BSD make bar pmake two foo |
You have a few possibilities if you do want the foo=bar
override
to propagate to sub-make
s. One is to use the -e
option, which causes all environment variables to have precedence over
the `Makefile' macro definitions, and declare foo as an environment
variable:
% env foo=bar make -e |
The -e
option is propagated to sub-make
s automatically,
and since the environment is inherited between make
invocations, the foo
macro will be overridden in
sub-make
s as expected.
Using -e
could have unexpected side-effects if your environment
contains some other macros usually defined by the Makefile. (See
also the note about make -e
and SHELL
below.)
Another way to propagate overrides to sub-make
s is to do it
manually, from your `Makefile':
foo = foo one: @echo $(foo) $(MAKE) foo=$(foo) two two: @echo $(foo) |
You need to foresee all macros that a user might want to override if you do that.
SHELL
macro
POSIX-compliant make
s internally use the $(SHELL)
macro to spawn shell processes and execute `Makefile' rules. This
is a builtin macro supplied by make
, but it can be modified
from the `Makefile' or a command-line argument.
Not all make
s will define this SHELL
macro. OSF/Tru64
make
is an example; this implementation will always use
/bin/sh
. So it's a good idea to always define SHELL
in
your `Makefile's. If you use Autoconf, do
SHELL = @SHELL@ |
POSIX-compliant make
s should never acquire the value of
$(SHELL) from the environment, even when make -e
is used
(otherwise, think about what would happen to your rules if
SHELL=/bin/tcsh
).
However not all make
implementations will make this exception.
For instance it's not surprising that OSF/Tru64 make
doesn't
protect SHELL
, since it doesn't use it.
% cat Makefile SHELL = /bin/sh FOO = foo all: @echo $(SHELL) @echo $(FOO) % env SHELL=/bin/tcsh FOO=bar make -e # OSF1 V4.0 Make /bin/tcsh bar % env SHELL=/bin/tcsh FOO=bar gmake -e # GNU make /bin/sh bar |
Never put comments in a rule.
Some make
treat anything starting with a tab as a command for
the current rule, even if the tab is immediately followed by a #
.
The make
from Tru64 Unix V5.1 is one of them. The following
`Makefile' will run # foo
through the shell.
all: # foo |
Never name one of your subdirectories `obj/' if you don't like surprises.
If an `obj/' directory exists, BSD make
will enter it
before reading `Makefile'. Hence the `Makefile' in the
current directory will not be read.
% cat Makefile all: echo Hello % cat obj/Makefile all: echo World % make # GNU make echo Hello Hello % pmake # BSD make echo World World |
make -k
Do not rely on the exit status of make -k
. Some implementations
reflect whether they encountered an error in their exit status; other
implementations always succeed.
% cat Makefile all: false % make -k; echo exit status: $? # GNU make false make: *** [all] Error 1 exit status: 2 % pmake -k; echo exit status: $? # BSD make false *** Error code 1 (continuing) exit status: 0 |
VPATH
There is no VPATH
support specified in POSIX. Many
make
s have a form of VPATH
support, but its
implementation is not consistent amongst make
s.
Maybe the best suggestion to give to people who need the VPATH
feature is to choose a make
implementation and stick to it.
Since the resulting `Makefile's are not portable anyway, better
choose a portable make
(hint, hint).
Here are a couple of known issues with some VPATH
implementations.
VPATH
and double-colon rules
Any assignment to VPATH
causes Sun make
to only execute
the first set of double-colon rules. (This comment has been here since
1994 and the context has been lost. It's probably about SunOS 4. If
you can reproduce this, please send us a test case for illustration.)
$<
in inference rules:
make
would not prefix $<
if this
prerequisite has been found in a VPATH
dir. This means that
VPATH = ../src .c.o: cc -c $< -o $@ |
would run cc -c foo.c -o foo.o
, even if `foo.c' was actually
found in `../src/'.
This can be fixed as follows.
VPATH = ../src .c.o: cc -c `test -f $< || echo ../src/`$< -o $@ |
This kludge was introduced in Automake in 2000, but the exact context
have been lost. If you know which make
implementation is
involved here, please drop us a note.
$<
not supported in explicit rules
As said elsewhere, using $<
in explicit rules is not portable.
The prerequisite file must be named explicitly in the rule. If you want
to find the prerequisite via a VPATH
search, you have to code the
whole thing manually. For instance, using the same pattern as above:
VPATH = ../src foo.o: foo.c cc -c `test -f foo.c || echo ../src/`foo.c -o foo.o |
Some make
implementations, such as SunOS make
, will
search prerequisites in VPATH
and rewrite all their occurrences
in the rule appropriately.
For instance
VPATH = ../src foo.o: foo.c cc -c foo.c -o foo.o |
would execute cc -c ../src/foo.c -o foo.o
if `foo.c' was
found in `../src'. That sounds great.
However, for the sake of other make
implementations, we can't
rely on this, and we have to search VPATH
manually:
VPATH = ../src foo.o: foo.c cc -c `test -f foo.c || echo ../src/`foo.c -o foo.o |
However the "prerequisite rewriting" still applies here. So if
`foo.c' is in `../src', SunOS make
will execute
|
which reduces to
cc -c foo.c -o foo.o |
and thus fails. Oops.
One workaround is to make sure that foo.c never appears as a plain word in the rule. For instance these three rules would be safe.
VPATH = ../src foo.o: foo.c cc -c `test -f ./foo.c || echo ../src/`foo.c -o foo.o foo2.o: foo2.c cc -c `test -f 'foo2.c' || echo ../src/`foo2.c -o foo2.o foo3.o: foo3.c cc -c `test -f "foo3.c" || echo ../src/`foo3.c -o foo3.o |
Things get worse when your prerequisites are in a macro.
VPATH = ../src HEADERS = foo.h foo2.h foo3.h install-HEADERS: $(HEADERS) for i in $(HEADERS); do \ $(INSTALL) -m 644 `test -f $$i || echo ../src/`$$i \ $(DESTDIR)$(includedir)/$$i; \ done |
The above install-HEADERS
rule is not SunOS-proof because for
i in $(HEADERS);
will be expanded as for i in foo.h foo2.h foo3.h;
where foo.h
and foo2.h
are plain words and are hence
subject to VPATH
adjustments.
If the three files are in `../src', the rule is run as:
for i in ../src/foo.h ../src/foo2.h foo3.h; do \ install -m 644 `test -f $i || echo ../src/`$i \ /usr/local/include/$i; \ done |
where the two first install
calls will fail. For instance,
consider the foo.h
installation:
install -m 644 `test -f ../src/foo.h || echo ../src/`../src/foo.h \ /usr/local/include/../src/foo.h; |
install -m 644 ../src/foo.h /usr/local/include/../src/foo.h; |
Note that the manual VPATH
search did not cause any problems here;
however this command installs `foo.h' in an incorrect directory.
Trying to quote $(HEADERS)
in some way, as we did for
foo.c
a few `Makefile's ago, does not help:
install-HEADERS: $(HEADERS) headers='$(HEADERS)'; for i in $$headers; do \ $(INSTALL) -m 644 `test -f $$i || echo ../src/`$$i \ $(DESTDIR)$(includedir)/$$i; \ done |
Indeed, headers='$(HEADERS)'
expands to headers='foo.h
foo2.h foo3.h'
where foo2.h
is still a plain word. (Aside: the
headers='$(HEADERS)'; for i in $$headers;
idiom is a good
idea if $(HEADERS)
can be empty, because some shell produce a
syntax error on for i in;
.)
One workaround is to strip this unwanted `../src/' prefix manually:
VPATH = ../src HEADERS = foo.h foo2.h foo3.h install-HEADERS: $(HEADERS) headers='$(HEADERS)'; for i in $$headers; do \ i=`expr "$$i" : '../src/\(.*\)'`; $(INSTALL) -m 644 `test -f $$i || echo ../src/`$$i \ $(DESTDIR)$(includedir)/$$i; \ done |
make
creates prerequisite directories magically
When a prerequisite is a sub-directory of VPATH
, Tru64
make
will create it in the current directory.
% mkdir -p foo/bar build % cd build % cat >Makefile <<END VPATH = .. all: foo/bar END % make mkdir foo mkdir foo/bar |
This can yield unexpected results if a rule uses a manual VPATH
search as presented before.
VPATH = .. all : foo/bar command `test -d foo/bar || echo ../`foo/bar |
The above command
will be run on the empty `foo/bar'
directory that was created in the current directory.
GNU make
uses a rather complex algorithm to decide when it
should use files found via a VPATH
search. See section `How Directory Searches are Performed' in The GNU Make Manual.
If a target needs to be rebuilt, GNU make
discards the
filename found during the VPATH
search for this target, and
builds the file locally using the filename given in the `Makefile'.
If a target does not need to be rebuilt, GNU make
uses the
filename found during the VPATH
search.
Other make
implementations, like BSD make
, are
easier to describe: the filename found during the VPATH
search
will be used whether the target needs to be rebuilt or not. Therefore
new files are created locally, but existing files are updated at their
VPATH
location.
When attempting a VPATH
build for an autoconfiscated package
(e.g, mkdir build; ../configure
), this means the GNU
make
will build everything locally in the `build'
directory, while BSD make
will build new files locally and
update existing files in the source directory.
% cat Makefile VPATH = .. all: foo.x bar.x foo.x bar.x: newer.x @echo Building $@ % touch ../bar.x % touch ../newer.x % make # GNU make Building foo.x Building bar.x % pmake # BSD make Building foo.x Building ../bar.x |
Another point worth mentioning is that once GNU make
has
decided to ignore a VPATH
filename (e.g., it ignored
`../bar.x' in the above example) it will continue to ignore it when
the target occurs as a prerequisite of another rule.
The following example shows that GNU make
does not look up
`bar.x' in VPATH
before performing the .x.y
rule,
because it ignored the VPATH
result of `bar.x' while running
the bar.x: newer.x
rule.
% cat Makefile VPATH = .. all: bar.y bar.x: newer.x @echo Building $@ .SUFFIXES: .x .y .x.y: cp $< $@ % touch ../bar.x % touch ../newer.x % make # GNU make Building bar.x cp bar.x bar.y cp: cannot stat `bar.x': No such file or directory make: *** [bar.y] Error 1 % pmake # BSD make Building ../bar.x cp ../bar.x bar.y |
Note that if you drop away the command from the bar.x: newer.x
rule, things will magically start to work: GNU
make
knows that bar.x
hasn't been updated, therefore
it doesn't discard the result from VPATH
(`../bar.x') in
succeeding uses.
% cat Makefile VPATH = .. all: bar.y bar.x: newer.x .SUFFIXES: .x .y .x.y: cp $< $@ % touch ../bar.x % touch ../newer.x % make # GNU make cp ../bar.x bar.y % rm bar.y % pmake # BSD make cp ../bar.x bar.y |
Separated dependencies simply refers to listing the prerequisite of a target, without defining a rule. Usually one can list on the one hand side, the rules, and on the other hand side, the dependencies.
Solaris make
does not support separated dependencies for
targets defined by single suffix rules:
$ cat Makefile .SUFFIXES: .in foo: foo.in .in: cp $< $ $ touch foo.in $ make $ ls Makefile foo.in |
while GNU Make does:
$ gmake cp foo.in foo $ ls Makefile foo foo.in |
Note it works without the `foo: foo.in' dependency.
$ cat Makefile .SUFFIXES: .in .in: cp $< $ $ make foo cp foo.in foo |
and it works with double suffix inference rules:
$ cat Makefile foo.out: foo.in .SUFFIXES: .in .out .in.out: cp $< $ $ make cp foo.in foo.out |
As a result, in such a case, you have to write target rules.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |