vpath not picking up newly built objects

413 views Asked by At

I have this Makefile (and GNU Make):

vpath %.o .objs

OBJDIR=.objs

all: symbol_tests.so

symbol_tests.so: symbol_tests.o symbol.o   # simulate linking
    @echo Linking target: $@, prerequisites: $^

%.o: %.c | $(OBJDIR)/
    gcc -o $(OBJDIR)/$@ -c $<

$(OBJDIR)/:
    -mkdir $@

but building (without any subdir or objects existing) give me this:

mkdir .objs/
gcc -o .objs/symbol_tests.o -c symbol_tests.c
gcc -o .objs/symbol.o -c symbol.c
Linking target: symbol_tests.so, prerequisites: symbol_tests.o symbol.o

It is obvious that since neither symbol.o nor symbol_test.o exists they need to be built. And they are correctly placed in the subdir ./objs.

But when "linking" the vpath does not pick up the newly created .o-files in the .objs subdir.

Isn't this strange? Running make again gives:

Linking target: symbol_tests.so, prerequisites: .objs/symbol_tests.o .objs/symbol.o

To me that looks like that in order to trigger the search for the .o in the subdir they have to exist when make is invoked. That kind of defeats the purpose of vpath, doesn't it?

Or is there something wrong with my Makefile or understanding of vpath?

NOTE: having $(OBJDIR) in the vpath directive does not work. Why?

1

There are 1 answers

1
Greg A. Woods On BEST ANSWER

It doesn't look like this will work for GNU Make nor any other Make I've tried.

I think vpath and $(VPATH) [and for BSD Make .PATH:] are only really effective for original sources (i.e. files that exist before Make is invoked, not for any intermediate targets.

In particular see the following caveat from the GNU Autoconf manual:

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.

See more caveats in the Gnu Autoconf manual section 12.14 VPATH and Make.

You could of course fool it by doing your final link step in a recursive call to make, but that seems wasteful, especially if you do it for lots of targets.

BSD Make manages creation of object directories by automatically changing the current working directory to the object directory and then explicitly finding sources via the ${.CURDIR} variable -- the location where make was first invoked.

GNU Make unfortunately only sets its $(CURDIR) after it processes -C options. It seems the preferred GNU Make way of doing things (especially in conjunction with the other GNU Autotools) is to use a separate build directory for the Make process. I.e. create a separate empty build directory and start by running the configure script in there, with a relative path to the build directory:

mkdir build
cd build
../configure

This creates all the necessary Makefiles in the build directory and you can then just run the Make in the build directory as well:

gmake

That is of course the safest way to ensure no targets (intermediate or otherwise) ever get created in the source directories.

You could also avoid vpath and directly add the object directory to each object target name, as in this answer: https://stackoverflow.com/a/37469528/816536