0

我有这个 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存在,因此需要构建它们。并且它们正确放置在 subdir 中./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) 不起作用。为什么?

4

1 回答 1

1

看起来这不适用于 GNU Make 或我尝试过的任何其他 Make。

我认为vpathand $(VPATH)[and for BSD Make .PATH:] 仅对原始源(即在调用 Make 之前存在的文件,而不是任何中间目标)真正有效。

特别是请参阅 GNU Autoconf 手册中的以下警告:

在显式规则中使用 $< 是不可移植的。必备文件必须在规则中明确命名。如果您想通过 VPATH 搜索找到先决条件,则必须手动编写整个代码。

请参阅 Gnu Autoconf 手册第12.14 VPATH 和 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

于 2020-03-13T22:35:37.170 回答