我有两个这样的目标
$(OBJ1): $(BUILDDIR)/%.o: $(BUILDROOT)/proto/a/%.pb.cc
$(OBJ2): $(BUILDDIR)/%.o: $(BUILDROOT)/proto/a/b/%.pb.cc
是否可以将这两者以某种方式组合到同一个目标中?
答案 0 :(得分:2)
可能,但是您需要高级制作功能(宏):
SRC := $(shell find $(BUILDROOT)/proto -type f -name '*.cc')
OBJ := $(addprefix $(BUILDDIR)/,$(patsubst %.cc,%.o,$(notdir $(SRC))))
compile: $(OBJ)
# $(1) is the cc source file
define MY_rule
$$(BUILDDIR)/$$(patsubst %.cc,%.o,$$(notdir $(1))): $(1)
$$(CXX) -c $$(CXXFLAGS) -o $$@ $$<
endef
$(foreach f,$(SRC),$(eval $(call MY_rule,$(f))))
演示:
$ ls -R proto
proto:
dira
proto/dira:
a.cc dirb
proto/dira/dirb:
b.cc
$ make BUILDROOT=. BUILDDIR=build compile
g++ -c -o build/a.o proto/dira/a.cc
g++ -c -o build/b.o proto/dira/dirb/b.cc
请查看section about the eval function中的GNU make manual,以获取完整说明。
最新更新:建议您对另一个(现已删除)类似问题的一条评论建议使用vpath
指令。这也很棘手,并增加了一个重要的约束,即所有源文件必须具有不同的基名。为了完整起见,并假设满足约束条件,这是另一个基于vpath
的解决方案:
vpath <pattern> dira dirb dirc:...
告诉我们,在搜索与<pattern>
匹配的文件时,必须浏览列出的目录。因此,让我们:
计算所有源文件和相应目标文件的基本名称:
SRC := $(notdir $(shell find $(BUILDROOT)/proto -type f -name '*.cc'))
OBJ := $(addprefix $(BUILDDIR)/,$(patsubst %.cc,%.o,$(SRC)))
获取$(BUILDROOT)/proto
中所有目录的列表:
DIR := $(shell find $(BUILDROOT)/proto -type d)
现在,我们准备使用vpath
指令:
vpath %.cc $(DIR)
就是这样。总而言之,以下应该起作用:
SRC := $(notdir $(shell find $(BUILDROOT)/proto -type f -name '*.cc'))
DIR := $(shell find $(BUILDROOT)/proto -type d)
OBJ := $(addprefix $(BUILDDIR)/,$(patsubst %.cc,%.o,$(SRC)))
vpath %.cc $(DIR)
compile: $(OBJ)
$(BUILDDIR)/%.o: %.cc
$(CXX) -c $(CXXFLAGS) -o $@ $<