DOC HOME SITE MAP MAN PAGES GNU INFO SEARCH
 

(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