我想编译一些C ++文件,我绝对必须将所有目标文件放在一个单独的构建目录中,但是存储完全平坦,即没有任何其他子目录。我知道使用VPATH的常见解决方案,如下所示:
SOURCES = foo/one.cpp \
foo/bar/two.cpp \
foo/bar/sub/three.cpp
OBJDIR = obj
VPATH=$(dir $(SOURCES))
OBJECTS = $(addprefix $(OBJDIR)/, $(notdir $(SOURCES:%.cpp=%.o)))
$(OBJDIR)/%.o : %.cpp
@echo Should compile: $(filter %/$*.cpp, $(SOURCES))
@echo Compiling $<
all: $(OBJECTS)
这个例子非常有效:我在'obj'子目录中得到三个目标文件one.o,two.o,three.o(你可以认为它只是存在)。
现在这里是使用VPATH时的问题:如果恰好有一个文件'foo / three.cpp',那么这个将被编译而不是'foo / bar / sub / 3。在SOURCES变量中命名的cpp'。不,我不能重命名任何一个文件;这个名字冲突只是存在,我对此无能为力。
所以我的问题是:我如何告诉Make to only 使用出现在SOURCES变量中的'.cpp'文件?我认为最好的解决方案是在目标的先决条件中使用'filter'语句。我认为这应该可以使用二次扩展,但我不知道如何处理'%'。例如,我试过
.SECONDEXPANSION:
$(OBJDIR)/%.o : $$(filter %/$$*.cpp, $(SOURCES))
但这不起作用。
更新:在tripleee的帮助下,我设法使用以下方法解决了这个问题:
define make-deps
$(OBJDIR)/$(notdir $(1:%.cpp=%.o)): $1
endef
$(foreach d, $(SOURCES), $(eval $(call make-deps,$d)))
%.o :
@echo Should compile $^ into $@
@echo Compiling $^
答案 0 :(得分:3)
我怀疑对您的问题最简单的解决方案是摆脱VPATH
并明确记录每个依赖项。这可以从您的SOURCES
定义中轻松获得;也许你想要定义一个函数,但它真的归结为:
obj/one.o: foo/one.cpp
obj/two.o: foo/bar/two.cpp
obj/three.o: foo/bar/sub/three.cpp
实际规则可以保留,只有它不再包含内联依赖项,并且您可以跳过obj/
子目录,因为它在每个依赖项中显式声明:
%.o : # Dependencies declared above
@echo Should compile $^ into $@
@echo Compiling $^
我将规则更改为使用$^
而不是$<
,以防您拥有多个依赖项。这对你的情况可能是对的,也可能是错的;如果它不是您需要的,请恢复更改。
为了不需要手动维护依赖项,您可能希望为每个%.d
文件生成%.cpp
。见the GNU Make manual。 (我尝试使用define
执行此操作,但似乎您无法使用foreach
循环声明依赖项。)
在回应评论中的问题时,这不应以任何方式影响并行构建;它只是消除了当VPATH
中有多个具有相同名称的biuld候选者时,原始Makefile不明确的依赖关系。没有新的依赖关系,也没有新的规则。