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?
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:
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 wheremake
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 theconfigure
script in there, with a relative path to the build directory:This creates all the necessary
Makefiles
in the build directory and you can then just run the Make in the build directory as well: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