Hi, This is an update of the "Limitations of Make" node of the Autoconf manual with some issues raised on the Automake lists recently.
I'm submiting the formated text here to get comments and corrections I could integrate before submitting the patch to Autoconf. Thanks for any help. ---- Limitations of Make =================== Make itself suffers a great number of limitations, only a few of which being 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 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 variable=value' and sub-`make's. An command argument definition such as `foo=bar' overrides any foo definition in the Makefile. Some Make implementations (such as GNU Make) will propagate this override to sub-invocations of `make', but POSIX conformant implementations won't. % 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 cause all environment variables to have precedence over the `Makefile' 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' variable will be overriden in sub-`make's as expected. Using `-e' could have unexpected side-effects if your environment contains some other variables 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 variables that a user might want to override if you do that. The `SHELL' variable POSIX Makes internally use the `$(SHELL)' variable to spawn shell processes and execute `Makefile' rules. This is a built-in variable supplied by Make, but it can be modified from the Makefile or a command line argument. Not all Makes will define this `SHELL' variable. 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 makes 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. specially. 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 `VPATH' There is no `VPATH' support specified in POSIX. Many Makes have a form of `VPATH' support, but its implementation is not coherent amongst Makes. Maybe the best suggestion to do to people who needs the `VPATH' feature is to chose a Make implementation an stick to it. Since the resulting `Makefile's are not portable anyway, better chose 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 comments is here since 1994 and the context has been lost. It's probably about SunOS 4. If you can reproduce this, please send us a testcase for illustration.) `$<' in inference rules: An implementation a make would not adjust prefix `$<' this prerequisite have 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 follow. 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. You have to make a `VPATH' search 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 occurences 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 appear 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 variable. 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 sun-proof because `for i in $(HEADERS);' will 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' adjustements. 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 fails. Consider the `foo.h' installation, for instance: install -m 644 `test -f ../src/foo.h || echo ../src/`../src/foo.\ h \ /usr/local/inclue/../src/foo.h; reduces to: install -m 644 ../src/foo.h /usr/local/include/../src/foo.h; Note that the manual `VPATH' search did not cause any problem here, however this command fails to install `foo.h' in the correct directory. Deciding to quote `$(HEADERS)' in some way, like we did for `foo.c' a few `Makefile's ago, do 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 this 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. % cat Makefile VPATH = .. all : foo/bar % make -p foo/bar build % cd build % 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 created in the current directory. -- Alexandre Duret-Lutz