(autoconf.info.gz) Limitations of Make
Info Catalog
(autoconf.info.gz) Limitations of Usual Tools
(autoconf.info.gz) Portable Shell
Limitations of Make
===================
`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....
`$<'
POSIX says that the `$<' construct in makefiles can be used only
in inference rules and in the `.DEFAULT' rule; its meaning in
ordinary rules is unspecified. Solaris 8's `make' for instance
will replace it with the argument.
Leading underscore in macro names
Some `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
Trailing backslash in macro
On some versions of HP-UX, `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.
Escaped newline in comments
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.
The `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
Comments in rules
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
The `obj/' subdirectory.
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:
One implementation of `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
Automatic rule rewriting
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
`cc -c `test -f ../src/foo.c || echo ../src/`foo.c -o foo.o'
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;
It reduces to:
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
OSF/Tru64 `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.
target lookup
GNU `make' uses a rather complex algorithm to decide when it
should use files found via a `VPATH' search. How
Directory Searches are Performed (make)Search Algorithm.
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
Info Catalog
(autoconf.info.gz) Limitations of Usual Tools
(autoconf.info.gz) Portable Shell
automatically generated byinfo2html