我有一个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
。我想忽略后两个步骤,这样如果我为一个新类添加单元测试,我只需要做第一步。简而言之,我希望自动化第二步和第三步(如果不需要,甚至可以删除它们。)
答案 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