Previous: OSF/Tru64 Directory Magic, Up: VPATH and Make


11.13.5 Make Target Lookup

GNU make uses a complex algorithm to decide when it should use files found via a VPATH search. See How Directory Searches are Performed.

If a target needs to be rebuilt, GNU make discards the file name found during the VPATH search for this target, and builds the file locally using the file name given in the makefile. If a target does not need to be rebuilt, GNU make uses the file name found during the VPATH search.

Other make implementations, like NetBSD make, are easier to describe: the file name found during the VPATH search is 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.

OpenBSD and FreeBSD make, however, never perform a VPATH search for a dependency that has an explicit rule. This is extremely annoying.

When attempting a VPATH build for an autoconfiscated package (e.g., mkdir build && cd build && ../configure), this means GNU make builds everything locally in the build directory, while BSD make builds new files locally and updates 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       # NetBSD make
     Building foo.x
     Building ../bar.x
     $ fmake       # FreeBSD make, OpenBSD make
     Building foo.x
     Building bar.x
     $ tmake       # Tru64 make
     Building foo.x
     Building bar.x
     $ touch ../bar.x
     $ make        # GNU make
     Building foo.x
     $ pmake       # NetBSD make
     Building foo.x
     $ fmake       # FreeBSD make, OpenBSD make
     Building foo.x
     Building bar.x
     $ tmake       # Tru64 make
     Building foo.x
     Building bar.x

Note how NetBSD make updates ../bar.x in its VPATH location, and how FreeBSD, OpenBSD, and Tru64 make always update bar.x, even when ../bar.x is up to date.

Another point worth mentioning is that once GNU make has decided to ignore a VPATH file name (e.g., it ignored ../bar.x in the above example) it continues 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       # NetBSD make
     Building ../bar.x
     cp ../bar.x bar.y
     $ rm bar.y
     $ fmake       # FreeBSD make, OpenBSD make
     echo Building bar.x
     cp bar.x bar.y
     cp: cannot stat `bar.x': No such file or directory
     *** Error code 1
     $ tmake       # Tru64 make
     Building bar.x
     cp: bar.x: No such file or directory
     *** Exit 1

Note that if you drop away the command from the bar.x: newer.x rule, GNU make magically starts to work: it knows that bar.x hasn't been updated, therefore it doesn't discard the result from VPATH (../bar.x) in succeeding uses. Tru64 also works, but FreeBSD and OpenBSD still don't.

     $ 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       # NetBSD make
     cp ../bar.x bar.y
     $ rm bar.y
     $ fmake       # FreeBSD make, OpenBSD make
     cp bar.x bar.y
     cp: cannot stat `bar.x': No such file or directory
     *** Error code 1
     $ tmake       # Tru64 make
     cp ../bar.x bar.y

It seems the sole solution that would please every make implementation is to never rely on VPATH searches for targets. In other words, VPATH should be reserved to unbuilt sources.