You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何编写可同时生成主程序与doctest测试程序两个可执行文件的Makefile

Makefile适配doctest测试目录及编译问题解决方案

需求背景

原始项目结构如下:

  • src 目录:内含 file.cpp、main.cpp
  • include 目录:内含 file.h
  • Makefile 文件

原始Makefile代码:

TARGET_EXEC := main
CC := g++

BUILD_DIR := .
SRC_DIR := src
OBJ_DIR := obj

SRC := $(shell find $(SRC_DIR) -name '*.cpp')
OBJ := $(SRC:%=$(OBJ_DIR)/%.o)
DEPS := $(OBJ:.o=.d)

INC_DIR := $(shell find $(SRC_DIR) -type d)
INC_FLAGS := $(addprefix -I,$(INC_DIR))

CPPFLAGS := $(INC_FLAGS) -MMD -MP

$(BUILD_DIR)/$(TARGET_EXEC): $(OBJ)
    $(CC) $(OBJ) -o $@ $(LDFLAGS)

$(OBJ_DIR)/%.cpp.o: %.cpp
    @ mkdir -p $(dir $@)
    $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@

.PHONY: clean
clean:
    rm -r $(OBJ_DIR) main
    
-include $(DEPS)

需新增 test 目录存放基于doctest框架的 tests.cpp 代码,最终生成main(主程序)和tests(测试程序)两个可执行文件。


历史修改问题分析

第一次修改后问题:两个可执行文件功能完全一致

你怀疑的编译规则段没有错误,问题出在链接逻辑:

  1. 测试程序的依赖没有包含test目录下的源文件对应目标文件,编译阶段根本没有处理tests.cpp
  2. 测试程序链接时错误引入了src下所有目标文件,包含src/main.o,导致两个可执行文件的链接内容完全一致,运行效果自然相同

第二次修改后问题:测试程序链接报undefined reference to 'main'

编译逻辑已经正确,问题出在两处:

  1. 测试程序链接仅引入了测试代码的目标文件,没有引入业务代码的目标文件,测试用例无法调用业务逻辑
  2. doctest的入口宏配置错误,无法自动生成测试程序的main入口函数

最终正确配置

1. Makefile修改

核心是拆分业务代码和主程序入口的目标文件,测试程序不引入src/main.o,同时补充业务代码依赖:

TARGET_EXEC := main
TEST_EXEC := tests
CC := g++

BUILD_DIR := .
SRC_DIR := src
OBJ_DIR := obj
TEST_DIR := test

# 拆分src文件:排除主入口的业务代码、主程序入口代码、测试代码
SRC_MAIN := $(SRC_DIR)/main.cpp
SRC_BUSINESS := $(filter-out $(SRC_MAIN), $(shell find $(SRC_DIR) -name '*.cpp'))
SRC_TEST := $(shell find $(TEST_DIR) -name '*.cpp')

# 各部分对应的目标文件
OBJ_BUSINESS := $(SRC_BUSINESS:%=$(OBJ_DIR)/%.o)
OBJ_MAIN := $(SRC_MAIN:%=$(OBJ_DIR)/%.o)
OBJ_TEST := $(SRC_TEST:%=$(OBJ_DIR)/%.o)

DEPS := $(OBJ_BUSINESS:.o=.d) $(OBJ_MAIN:.o=.d) $(OBJ_TEST:.o=.d)

# 头文件路径新增test目录,适配doctest引入
INC_DIR := $(shell find $(SRC_DIR) -type d) $(TEST_DIR)
INC_FLAGS := $(addprefix -I,$(INC_DIR))

CPPFLAGS := $(INC_FLAGS) -MMD -MP

.PHONY: clean all

all: $(BUILD_DIR)/$(TARGET_EXEC) $(BUILD_DIR)/$(TEST_EXEC)

# 主程序链接:业务代码+主程序入口
$(BUILD_DIR)/$(TARGET_EXEC): $(OBJ_BUSINESS) $(OBJ_MAIN)
	$(CC) $^ -o $@ $(LDFLAGS)

# 测试程序链接:业务代码+测试代码,不引入src/main.o
$(BUILD_DIR)/$(TEST_EXEC): $(OBJ_BUSINESS) $(OBJ_TEST)
	$(CC) $^ -o $@ $(LDFLAGS)

$(OBJ_DIR)/%.cpp.o: %.cpp
	@mkdir -p $(dir $@)
	$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@

clean:
	rm -rf $(OBJ_DIR) $(TARGET_EXEC) $(TEST_EXEC)
    
-include $(DEPS)

2. doctest测试文件修改

要让doctest自动生成测试程序的main入口,需使用DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN宏,而非DOCTEST_CONFIG_IMPLEMENT,后者需要手动编写main函数调用测试逻辑。

正确的tests.cpp示例:

#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include "doctest/doctest.h"
// 引入业务头文件编写测试用例
#include "file.h"

TEST_CASE("示例测试用例") {
    CHECK(your_function(1) == 2);
    // 补充其他测试逻辑
}

内容的提问来源于stack exchange,提问作者Gianluca Bianco

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 14:06:06