Makefile用于多种模式的单一配方

时间:2016-12-14 17:33:56

标签: makefile

是否有一种简单的方法可以将单个配方应用于多个模式规则?

考虑这个目录结构

|- src
|  - file1.cpp
|- test
|  - file2.cpp
|  - file3.cpp
|  - metrics
|    - file4.cpp
|    - file5.cpp

我想编写一个模式规则来编译测试目录中的所有.cpp文件。这就是我现在所拥有的:

$(OBJS)/%.o: test/%.cpp
    @mkdir -p $(OBJS)
    g++ $(FLAGS) $(CPPFLAGS) -c $< -o $@

$(OBJS)/%.o: test/metrics/%.cpp
    @mkdir -p $(OBJS)
    g++ $(FLAGS) $(CPPFLAGS) -I test -c $< -o $@

TEST_CPP := $(wildcard test/*.cpp) $(wildcard test/**/*.cpp)
TEST_OBJ :=  $(addprefix $(OBJS)/,$(notdir $(TEST_CPP:.cpp=.o)))

$(BIN)/testRunner: $(TEST_OBJ)
    @mkdir -p $(BIN)
    g++ $(FLAGS) $(CPPFLAGS) $^ $(LIBS) -o $@

我想避免重复目标文件的配方。我想解决方案看起来像这样:

$(OBJS)/%.o: test/%.cpp
$(OBJS)/%.o: test/metrics/%.cpp 
    @mkdir -p $(OBJS)
    g++ $(FLAGS) $(CPPFLAGS) -c $< -o $@

(目前,objs目录是平的;但是,如果简化了makefile,我就不会有重复源目录结构的问题。)

1 个答案:

答案 0 :(得分:3)

没有办法做你想做的事。最接近的是将配方放入变量并在每个配方中使用相同的变量,如下所示:

define BUILD_O
        @mkdir -p $(OBJS)
        g++ $(FLAGS) $(CPPFLAGS) -c $< -o $@
endef

$(OBJS)/%.o : test/%.cpp
        $(BUILD_O)
$(OBJS)/%.o : test/metrics/%.cpp
        $(BUILD_O)

作为替代方案,因为您希望所有对象都进入同一目录但从不同目录中查找源,您可以使用VPATH而只编写单个模式规则,如下所示:

VPATH = test test/metrics

$(OBJS)/%.o : %.cpp
        @mkdir -p $(@D)
        g++ $(FLAGS) $(CPPFLAGS) -c $< -o $@

我强烈建议您重新编写makefile以使用标准变量名称;对于C ++编译器选项,使用$(CXX),而不是g++,而$(CXXFLAGS),而不是$(FLAGS)

修改

如果您需要自定义标记,那么通常的方法是通过target-specific variables或通过constructed macro names

特定于目标的变量如下所示:

test: $(test_targets)
test: FLAGS += -Dtest

production: $(production_targets)
production: FLAGS += -Dproduction

然后当您运行make test时,您会添加-Dtest;当您运行make production时,您将获得-Dproduction。但是这里有一些问题:如果你运行make myfoo.o,那么你就不会添加这些(参见文档)。

构造的宏名称如下所示:

test_FLAGS = -Dtest
production_FLAGS = -Dproduction

rootdir = $(firstword $(subst /, ,$1))

VPATH = test test/metrics production production/widgets

$(OBJS)/%.o : %.cpp
        @mkdir -p $(@D)
        g++ $(FLAGS) $(CPPFLAGS) $($(call rootdir,$(<D))_FLAGS) -c $< -o $@