我有这个Makefile(和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 $@
但是建筑物(没有任何子目录或对象存在)给我这个:
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
很明显,由于symbol.o
和symbol_test.o
都不存在,因此不需要构建它们。并将它们正确放置在子目录./objs
中。
但是“链接”时,vpath
不会在.o
子目录中拾取新创建的.objs
文件。
这很奇怪吗?再次运行make
会给出:
Linking target: symbol_tests.so, prerequisites: .objs/symbol_tests.o .objs/symbol.o
对我来说,为了触发对子目录中.o
的搜索,当调用make
时,它们必须存在。这种破坏了vpath
的目的,不是吗?
或者我的Makefile
或对vpath
的理解有问题吗?
注意:在vpath指令中包含$(OBJDIR)不起作用。为什么?
看来这不适用于GNU Make或我尝试过的任何其他Make。
我认为vpath
和$(VPATH)
[以及对于BSD Make .PATH:
]仅对原始来源(即调用Make之前存在的文件,而不是任何中间目标)有效。
特别是从GNU Autoconf手册中看到以下警告:
在显式规则中使用$
请参见《 Gnu Autoconf手册》 12.14 VPATH and Make部分的更多警告。
当然,您可以通过对make
进行递归调用来完成最后一个链接步骤,从而蒙蔽了它,但这似乎很浪费,特别是如果您对许多目标执行此操作。
BSD Make通过自动将当前工作目录更改为对象目录,然后通过${.CURDIR}
变量(首次调用make
的位置)显式查找源来管理对象目录的创建。
不幸的是,GNU Make仅设置其$(CURDIR)
之后,它处理-C
选项。似乎首选的GNU Make处理方式(尤其是与其他GNU Autotools结合使用)是为Make进程使用单独的构建目录。即创建一个单独的空构建目录,并从其中运行configure
脚本开始,并带有构建目录的相对路径:
mkdir build
cd build
../configure
这会在构建目录中创建所有必需的Makefiles
,然后您也可以在构建目录中运行Make:
gmake
当然,这是确保在源目录中从未创建任何目标(中间目标或其他目标)的最安全方法。>>
您还可以避免使用vpath
,而是直接将对象目录添加到每个对象目标名称中,如以下答案:https://stackoverflow.com/a/37469528/816536