首页 > 解决方案 > 是否可以在 Makefile 的同一目标中具有多个先决条件模式?

问题描述

我有两个这样的目标

$(OBJ1): $(BUILDDIR)/%.o: $(BUILDROOT)/proto/a/%.pb.cc

$(OBJ2): $(BUILDDIR)/%.o: $(BUILDROOT)/proto/a/b/%.pb.cc

是否有可能以某种方式将这两者结合到同一个目标中?

标签: makefile

解决方案


这是可能的,但您将需要高级制作功能(宏):

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   

请查看GNU make 手册中关于 eval 函数的部分以获得完整的解释。

延迟更新:关于您的其他(现已删除)类似问题的一条评论建议使用该vpath指令。这也很棘手,并增加了一个重要的约束,即所有源文件必须具有不同的基本名称。为了完整起见,并假设满足约束,这是另一个vpath基于 - 的解决方案:

vpath <pattern> dira dirb dirc:...

告诉 make 在搜索匹配的文件时<pattern>,它必须探索列出的目录。所以,让我们:

  1. 计算所有源文件和相应目标文件的基本名称:

    SRC := $(notdir $(shell find $(BUILDROOT)/proto -type f -name '*.cc'))
    OBJ := $(addprefix $(BUILDDIR)/,$(patsubst %.cc,%.o,$(SRC)))
    
  2. 获取所有目录的列表$(BUILDROOT)/proto

    DIR := $(shell find $(BUILDROOT)/proto -type d)
    
  3. 现在,我们准备好使用该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 $@ $<

推荐阅读