Makefile:将具有相同前缀的多个目标组合到一个目标中

时间:2017-07-15 09:51:05

标签: gcc makefile

我有一个makefile,其中多个目标使用相同的前缀命名,如下所示:

STR_COMPRESS_SRCS:=string_compress.cpp
UTEST_UTIL_SRCS:=string_parser.cpp

UTEST_COM_SRCS:=utest_main.cpp \
                $(UTEST_UTIL_SRCS) \
                $(STR_COMPRESS_SRCS)
UTEST_COM_OBJS=$(UTEST_COM_SRCS:.cpp=.o)

UTEST_FLAGS=-DUNIT_TEST -DGTEST_USE_OWN_TR1_TUPLE=0

UTEST_SERVER_QUERIER_SRCS:=ServerQuerier.cpp \
                           ServerQuerierTest.cpp
UTEST_SERVER_QUERIER_OBJS:=$(UTEST_SERVER_QUERIER_SRCS:.cpp=.o)
UTEST_SERVER_QUERIER_NAME:=utest_serverquerier

UTEST_SERVER_PROTO_SRCS:=ServerProtocol.cpp \
                         ServerProtocolTest.cpp
UTEST_SERVER_PROTO_OBJS:=$(UTEST_SERVER_PROTO_SRCS:.cpp=.o)
UTEST_SERVER_PROTO_NAME:=utest_serverprotocol


%.o: %.cpp
    $(CXX) -std=c++0x -c $< -o $@ $(INC) $(UTEST_FLAGS)

utest_all: utest_serverquerier utest_serverprotocol

utest_serverquerier: $(UTEST_COM_OBJS) $(UTEST_SERVER_QUERIER_OBJS)
    $(CXX) -std=c++0x $(CXXFLAGS) $(UTEST_COM_OBJS) $(UTEST_SERVER_QUERIER_OBJS) -o $(UTEST_SERVER_QUERIER_NAME) -pthread -lgtest -lgmock -L. $(LIB)

utest_serverprotocol: $(UTEST_COM_OBJS) $(UTEST_SERVER_PROTO_OBJS)
    $(CXX) -std=c++0x $(CXXFLAGS) $(UTEST_COM_OBJS) $(UTEST_SERVER_PROTO_OBJS) -o $(UTEST_SERVER_PROTO_NAME) -pthread -lgtest -lgmock -L. $(LIB)

clean:
    -@rm *.o utest_*

现在我想创建一个名为utest_all的目标,这样当我键入make utest_all时,将构建所有目标utest_*,生成多个与目标名称相同的输出文件。

注意:可以有很多utest_*

更新

  • 已添加utest_all
  • 已添加UTEST_XXX_NAME

当我输入make utest_all时,make将帮助构建指定为utest_all的依赖关系的所有目标。但问题是,如果我为一个新类添加单元测试(例如QuerierManagerTest.cpp,那么我将不得不做以下三件事:

  • 定义指定的变量:源文件(例如UTEST_QUERIER_MANAGER_SRCS),对象(例如,UTEST_QUERIER_MANAGER_OBJS,输出(UTEST_QUERIER_MANAGER_NAME)。
  • 为目标添加目标和规则,例如utest_queriermanager: # blah blah...
  • 将目标utest_queriermanager添加为utest_all的依赖项。

通过某种方式重新定义utest_all。我想忽略后两个步骤,这样如果我为一个新类添加单元测试,我只需要做第一步。简而言之,我希望自动化第二步和第三步(如果不需要,甚至可以删除它们。)

1 个答案:

答案 0 :(得分:2)

首先,我们必须从此makefile中删除一些冗余。

第1步:使用我们已为目标名称定义的变量。

$(UTEST_SERVER_QUERIER_NAME): $(UTEST_COM_OBJS) $(UTEST_SERVER_QUERIER_OBJS)
    $(CXX) -std=c++0x $(CXXFLAGS) $(UTEST_COM_OBJS) $(UTEST_SERVER_QUERIER_OBJS) -o $(UTEST_SERVER_QUERIER_NAME) -pthread -lgtest -lgmock -L. $(LIB)

$(UTEST_SERVER_PROTO_NAME): $(UTEST_COM_OBJS) $(UTEST_SERVER_PROTO_OBJS)
    $(CXX) -std=c++0x $(CXXFLAGS) $(UTEST_COM_OBJS) $(UTEST_SERVER_PROTO_OBJS) -o $(UTEST_SERVER_PROTO_NAME) -pthread -lgtest -lgmock -L. $(LIB)

第2步:使用一些automatic variables,就像我们在%.o规则中使用的那些一样。

$(UTEST_SERVER_QUERIER_NAME): $(UTEST_COM_OBJS) $(UTEST_SERVER_QUERIER_OBJS)
    $(CXX) -std=c++0x $(CXXFLAGS) $^ -o $@ -pthread -lgtest -lgmock -L. $(LIB)

$(UTEST_SERVER_PROTO_NAME): $(UTEST_COM_OBJS) $(UTEST_SERVER_PROTO_OBJS)
    $(CXX) -std=c++0x $(CXXFLAGS) $^ -o $@ -pthread -lgtest -lgmock -L. $(LIB)

第3步:注意这两个规则具有完全相同的命令,并合并它们。

UTESTS := $(UTEST_SERVER_QUERIER_NAME) $(UTEST_SERVER_PROTO_NAME)

$(UTEST_SERVER_QUERIER_NAME): $(UTEST_SERVER_QUERIER_OBJS)

$(UTEST_SERVER_PROTO_NAME): $(UTEST_SERVER_PROTO_OBJS)

$(UTESTS): $(UTEST_COM_OBJS)
    $(CXX) -std=c++0x $(CXXFLAGS) $^ -o $@ -pthread -lgtest -lgmock -L. $(LIB)

现在来看看我们如何构建这些变量。

步骤4:现有的makefile使用名称中包含大写字母的源文件(例如ServerQuerierTest.cpp)来构建名称小写的可执行文件(例如{{1} })。我们可以自动执行此操作,但我将冒昧地保留可执行文件中的案例。名称(例如utest_serverquerier),用于更简单的解决方案。

utest_ServerQuerier

第5步:现在我们可以将每个名称简化为其本质:

UTEST_SERVER_QUERIER_NAME := utest_ServerQuerier

UTEST_SERVER_PROTO_NAME := utest_ServerProtocol

第6步:现在查看规则。

CLASSES := ServerQuerier ServerProtocol

UTESTS := $(addprefix utest_, $(CLASSES))

模式很明显,因此我们可以将这些规则折叠到模式规则中:

utest_ServerQuerier: ServerQuerier.o ServerQuerierTest.o   

utest_ServerProtocol: ServerProtocol.o ServerProtocolTest.o

所以我们不再需要为新课程编写新规则,我们所要做的就是将他们的名字添加到$(UTESTS): utest_%: %.o %Test.o $(UTEST_COM_OBJS) $(CXX) -std=c++0x $(CXXFLAGS) $^ -o $@ -pthread -lgtest -lgmock -L. $(LIB)

但也许我们甚至不必这样做。

第7步:此处似乎有一个简单的模式:当且仅当文件CLASSES和{{1}时,类Foo应该在列表中存在。如果没有Foo.cpp,我们可以假设FooTest.cpp不存在。因此,如果这是正确的,我们可以消除所有三个手动步骤,并通过减去测试列表来自动化所有

FooTest.cpp