CI/CD中分离测试构建与应用构建,避免重复构建的最佳实践
C++项目分离主应用与测试的CMake+GitLab CI/CD最佳实践
一、CMake配置:核心逻辑库化+条件编译测试
把项目拆分为核心逻辑库、主应用、测试应用三个独立目标,通过CMake的条件编译控制测试目标的构建,从根源上实现主应用与测试的分离。
示例CMakeLists.txt
cmake_minimum_required(VERSION 3.14) project(MyProject) # 1. 构建核心逻辑库:包含sum.h/sum.cpp的业务逻辑 add_library(core STATIC sum.cpp) # 暴露头文件路径,让依赖该库的目标能找到sum.h target_include_directories(core PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) # 2. 构建主应用:仅依赖核心库,不包含测试代码 add_executable(main_app main.cpp) target_link_libraries(main_app PRIVATE core) # 3. 可选构建测试目标:通过开关控制是否编译测试 option(BUILD_TESTS "Enable test targets compilation" ON) if(BUILD_TESTS) add_executable(tester tester.cpp) target_link_libraries(tester PRIVATE core) # 注册测试到CTest框架 enable_testing() add_test(NAME UnitTest COMMAND tester) endif()
关键优势
- 核心逻辑只需编译一次,主应用和测试都复用这个库,避免重复编译
- 通过
BUILD_TESTS选项,生产环境构建时可关闭测试目标,减少构建产物体积 - 主应用与测试完全解耦,测试代码的修改不会影响主应用构建
二、GitLab CI/CD流水线:阶段拆分+Artifact复用
利用GitLab CI的阶段划分和Artifact传递,让构建阶段只编译主应用和核心库,测试阶段仅编译测试目标并执行测试,避免全量重复编译。
示例.gitlab-ci.yml
stages: - build_main - build_test - run_test # 构建核心库+主应用,不编译测试 build_main: stage: build_main script: - mkdir -p build && cd build - cmake .. -DBUILD_TESTS=OFF - make -j$(nproc) artifacts: paths: - build/ # 传递构建目录,包含核心库和CMake缓存 - sum.h expire_in: 1h # 设置过期时间,避免存储冗余 # 基于已构建的核心库,单独编译测试目标 build_test: stage: build_test needs: [build_main] # 依赖build_main阶段的产物 script: - cd build - cmake .. -DBUILD_TESTS=ON - make tester -j$(nproc) artifacts: paths: - build/tester expire_in: 30m # 执行测试 run_test: stage: run_test needs: [build_test] script: - cd build - ctest -V # 详细输出测试结果
优化点
- 使用
needs关键字确保阶段依赖顺序,避免并行执行导致的资源冲突 - 传递build目录作为Artifact,复用CMake缓存和已编译的核心库,大幅缩短测试阶段的编译时间
- 按需设置Artifact过期时间,节省GitLab存储资源
三、额外实践建议
- 测试代码单独归档:把tester.cpp放到单独的
tests/目录,CMake中通过add_subdirectory(tests)引入,让项目结构更清晰 - 使用测试框架:比如Google Test或Catch2,配合CMake的
FetchContent自动拉取依赖,提升测试的规范性 - 生产构建优化:在CI的生产分支构建时,添加
-DCMAKE_BUILD_TYPE=Release参数,关闭调试信息并开启优化,同时设置-DBUILD_TESTS=OFF避免编译测试代码
内容的提问来源于stack exchange,提问作者amplifier
相关产品推荐
相关产品推荐

