编写构建源码与对应单元测试的Makefile及架构合理性咨询
嗨,我来帮你搞定这个Makefile的问题,顺便聊聊分不分开的事儿~
首先,先修正你原来主程序Makefile里的一个小错误:你写的objs = $(src:.c=.o)是把.c后缀改成.o,但你的源文件都是.cpp,所以应该改成$(src:.cpp=.o),不然编译的时候会找不到正确的目标文件。
接下来是整合主程序和测试的完整Makefile,既能构建主程序stuff,又能自动生成每个单独的测试程序,还能处理test_all:
# 主程序相关配置 src = $(shell find src -name "*.cpp") objs = $(src:.cpp=.o) bin = stuff # 测试程序相关配置 test_src = $(shell find tests -name "test_*.cpp") test_bins = $(test_src:.cpp=) # 把tests/a/test_foo.cpp转成tests/a/test_foo # 默认目标:构建主程序+所有测试 all: $(bin) $(test_bins) # 主程序构建规则 $(bin): $(objs) $(CXX) -o $@ $^ $(LDFLAGS) # 单个测试的通用规则:自动匹配test_*.cpp和对应的src文件 # 比如tests/a/test_foo.cpp会自动关联src/a/foo.cpp $(test_bins): %: %.cpp $(subst test_,,$(subst tests/,src/,$@)).cpp $(CXX) -o $@ $^ $(CXXFLAGS) $(LDFLAGS) # test_all单独处理:复用主程序的所有目标文件,避免重复编译src代码 tests/test_all: tests/test_all.cpp $(objs) $(CXX) -o $@ $^ $(CXXFLAGS) $(LDFLAGS) # 通用编译规则:把.cpp编译成.o %.o: %.cpp $(CXX) -c $< -o $@ $(CXXFLAGS) # 清理所有生成文件 clean: rm -f $(bin) $(objs) $(test_bins)
这个Makefile的好处是:
- 自动发现所有src和tests里的cpp文件,不用手动添加
- 单个测试只会编译自己和对应的src文件,比如
make tests/a/test_foo就只编译test_foo.cpp和src/a/foo.cpp - test_all会复用主程序已经编译好的目标文件,节省编译时间
- 支持标准的
make all、make clean,还有单独构建某个测试或主程序
然后来说说分开Makefile是否合理:
这完全取决于你的项目规模和复杂度:
- 如果是像现在这样的小型项目,把主程序和测试放在同一个Makefile里更方便,不用切换文件,一条命令就能搞定所有构建。
- 如果项目后续变大,比如src目录结构越来越复杂,测试需要引入额外的依赖(比如gtest、gmock),或者测试的编译配置和主程序差异很大,那分开成两个Makefile(比如根目录的
Makefile负责主程序,tests/Makefile负责测试)会更清晰,职责分离,维护起来更简单。
如果选择分开的话,根目录的Makefile可以通过make -C tests来调用测试目录的构建,还能传递编译参数(比如CXX、CXXFLAGS),甚至共享主程序的目标文件(比如把主程序的目标文件放到统一的build/src目录,测试Makefile直接引用),避免重复编译。
内容的提问来源于stack exchange,提问作者solidak
相关产品推荐
相关产品推荐

