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.
|