make: 匹配多个扩展名的模式规则

make: pattern rule matching multiple extensions

我有几个扩展的重复模式规则(例如:cppcc):

$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
    @$(CXX) $(CPPFLAGS) -I. -o $@ -c $?

$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cc
    @$(CXX) $(CPPFLAGS) -I. -o $@ -c $?

有没有办法让一个模式规则在两个扩展上都匹配,而不是必须有两个规则?

不,您不能合并这两个规则。先决条件都必须匹配。

但是您可以避免需要两次指定配方。

通过使用配方定义:

define COMPILE
@$(CXX) $(CPPFLAGS) -I. -o $@ -c $?
endef

$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
        $(COMPILE)

$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cc
        $(COMPILE)

或者通过使用循环和 eval 来定义食谱(未经测试我可能有一些转义错误但我更喜欢定义方法):

$(foreach prereq,cc cpp,$(eval $(OBJ_DIR)/%.o: $(SRC_DIR)/%.$(prereq) ; @$(CXX) $(CPPFLAGS) -I. -o $@ -c $?))

您可以为此使用 .SECONDEXPANSION。这是一个可执行示例:

OBJ_DIR:=obj
SRC_DIR:=src

TARGETS:=obj/foo.o obj/bar.o

all: $(TARGETS)

.SECONDEXPANSION:
$(OBJ_DIR)/%.o: $$(wildcard $(SRC_DIR)/%.cpp) $$(wildcard $(SRC_DIR)/%.cc)
    @$(CXX) $(CPPFLAGS) -I. -o $@ -c $<

创建 src/foo.ccsrc/bar.cpp,然后发出 make -n,您将得到:

g++  -I. -o obj/foo.o -c src/foo.cc
g++  -I. -o obj/bar.o -c src/bar.cpp

如果您同时拥有 foo.ccfoo.cpp,这将与此处所问问题中的版本一样(foo.cpp 将优先于 foo.cc,这将被忽略)。

$$(wildcard...$ 符号加倍,以防止在第一次扩展期间进行计算。您可以 $$(SRC_DIR)$(SRC_DIR) 一样,因为在扩展此变量时(在上面的代码中)无关紧要。