Gcc Makefile:将具有相同前缀的多个目标合并为一个目标

Gcc Makefile:将具有相同前缀的多个目标合并为一个目标,gcc,makefile,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:

我有一个
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_*
STR\u COMPRESS\u SRCS:=string\u COMPRESS.cpp
UTEST_UTIL_SRCS:=字符串_parser.cpp
UTEST_COM_SRCS:=UTEST_main.cpp\
$(UTEST\U UTIL\U SRCS)\
$(STR\u COMPRESS\u SRCS)
UTEST_COM_OBJS=$(UTEST_COM_SRCS:.cpp=.o)
UTEST_FLAGS=-DUNIT_TEST-DGTEST_USE_OWN_TR1_TUPLE=0
UTEST_服务器_查询器_SRCS:=serverqueryer.cpp\
ServerQuerierTest.cpp
UTEST\u服务器\u查询器\u对象:=$(UTEST\u服务器\u查询器\u SRCS:.cpp=.o)
UTEST_服务器\u查询器\u名称:=UTEST_服务器查询器
UTEST_服务器\u协议\u SRCS:=ServerProtocol.cpp\
ServerProtocolTest.cpp
UTEST_服务器\u协议\u对象:=$(UTEST_服务器\u协议\u SRCS:.cpp=.o)
UTEST_服务器\u协议名称:=UTEST_服务器协议
%.o:%.cpp
$(CXX)-std=c++0x-c$<-o$@$(INC)$(UTEST_标志)
utest\U all:utest\U服务器查询器utest\U服务器协议
utest_服务器查询器:$(utest_COM_OBJS)$(utest_服务器查询器_OBJS)
$(CXX)-std=c++0x$(CXXFLAGS)$(UTEST_COM_OBJS)$(UTEST_服务器_查询器_OBJS)-o$(UTEST_服务器_查询器_名称)-pthread-lgtest-lgmock-L.$(LIB)
utest\u服务器协议:$(utest\u COM\u OBJS)$(utest\u服务器\u协议\u OBJS)
$(CXX)-std=c++0x$(CXXFLAGS)$(UTEST_COM_OBJS)$(UTEST_服务器_协议_OBJS)-o$(UTEST_服务器_协议_名称)-pthread-lgtest-lgmock-L.$(LIB)
清洁:
-@rm*.o OUTEST_*
现在我想创建一个名为
utest\u all
的单一目标,这样当我键入
make utest\u all
时,所有目标
utest\u*
都将生成多个与目标同名的输出文件

注意:可以有许多
utest.*

更新:

  • 添加了
    utest\u all
  • 添加了
    UTEST\u XXX\u名称
当我键入
makeutest\u all
时,
make
将帮助构建指定为
utest\u all
依赖项的所有目标。但问题是,如果我为一个新类添加单元测试(例如,
querymanagertest.cpp
),那么我必须做以下三件事:

  • 定义指定的变量:源文件(例如
    UTEST\u queryer\u MANAGER\u SRCS
    ),对象(例如
    UTEST\u queryer\u MANAGER\u OBJS
    ),输出(
    UTEST\u queryer\u MANAGER\u NAME
  • 为目标添加目标和规则,例如,
    utest\u queryermanager:#诸如此类…
  • 将目标
    utest\u queryermanager
    添加为
    utest\u all
    的依赖项

通过重新定义
utest\u all
。我想忽略后面的两个步骤,这样,如果我为一个新类添加单元测试,我只需要执行第一步。简言之,我想自动化第二步和第三步(如果不需要,甚至删除它们).

首先,我们必须删除此生成文件中的一些冗余

步骤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:使用一些,就像我们在
%.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
)来构建名称为小写的可执行文件(如
utest\u serverquerier
)。我们可以自动执行此操作,但我会在可执行文件的名称中保留大小写(例如
utest\u serverqueryer
),以获得更简单的解决方案

UTEST_SERVER_QUERIER_NAME := utest_ServerQuerier

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

CLASSES := ServerQuerier ServerProtocol

UTESTS := $(addprefix utest_, $(CLASSES))
第6步:现在看看规则

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步:这里似乎有一个简单的模式:类
Foo
应该在列表中,当且仅当文件
Foo.cpp
FooTest.cpp
存在时。我们可以假设
FooTest.cpp
没有
Foo.cpp
就不存在。因此,如果这是正确的,我们可以消除所有三个manual通过让Make推断测试列表,逐步完成并自动化所有操作

TESTFILES := $(wildcard *Test.cpp)
CLASSES := $(patsubst %Test.cpp, %, $(TESTFILES))

首先,我们必须从这个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:使用一些,就像我们在
%.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
)来构建名称为小写的可执行文件(如
utest\u serverquerier
)。我们可以自动执行此操作,但我会在可执行文件的名称中保留大小写(例如
utest\u serverqueryer
),以获得更简单的解决方案

UTEST_SERVER_QUERIER_NAME := utest_ServerQuerier

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

CLASSES := ServerQuerier ServerProtocol

UTESTS := $(addprefix utest_, $(CLASSES))
第6步:现在看看规则

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:这里似乎有一个简单的模式:类
Foo
应该在列表中,当且仅当文件
Foo.cpp
FooTest.cpp