CMake进阶: 使用FetchContent方法基于gTest的C++单元测试

发布于:2025-08-05 ⋅ 阅读:(12) ⋅ 点赞:(0)

目录

1.前言

2.FetchContent详解

2.1.FetchContent简介

2.2.FetchContent_Declare

2.2.1.简介

2.2.2.关键特性

2.2.3.常见示例

2.3.FetchContent_MakeAvailable

2.3.1.简介

2.3.2.核心功能与工作流程

2.3.3.示例用法

2.3.4.关键特性

2.3.5.常见问题与解决方案

3.FetchContent_MakeAvailable和FetchContent_Populate的区别

4.add_test

5.完整示例

5.1.项目结构

5.2.代码实现

5.3.运行项目

5.4.遇到的问题

5.5.完整代码下载

6.优势与适用场景

7.注意事项

8.总结

相关链接


1.前言

        在现代C++项目开发中,单元测试是确保代码质量和可维护性的关键环节。Google Test(GTest)作为一款功能强大、广受欢迎的C++测试框架,提供了丰富的断言、测试夹具和测试发现机制。本文演示如何利用CMake的FetchContent模块,优雅地集成和使用Google Test进行单元测试。不仅会展示具体步骤,还会深入探讨FetchContent的工作原理,帮助更好地理解其在项目管理中的优势。

        前面讲了gTest的安装与配置方法:

gTest测试框架的安装与配置_安装gtest-CSDN博客

这种方法是先安装好gTest,再利用CMake的find_package查找它,然后链接它,其实也比较简单,如有不理解的地方,可参考:

CMake指令:find_package_cmake find package-CSDN博客

下面来讲讲另外一种方法,用FetchContent引入gTest。

2.FetchContent详解

2.1.FetchContent简介

        FetchContent是定义在FetchContent.cmake当中的,FetchContent.cmake 是 CMake 3.11 及以上版本提供的一个内置模块,用于在配置阶段下载、配置和集成外部项目(如第三方库),无需用户手动安装依赖。它解决了传统依赖管理(如手动下载、ExternalProject)的繁琐问题,让外部项目的集成更简洁、高效。

      FetchContent 的核心是在 CMake 配置阶段(执行 cmake 命令时)自动完成以下操作:

  1. 下载外部项目(从 URL、Git 仓库等);
  2. 配置外部项目(生成其构建文件);
  3. 构建外部项目(可选,默认会构建);
  4. 将外部项目的目标(库、可执行文件)暴露给当前项目,方便直接链接使用。

相比传统的 ExternalProject(在构建阶段处理依赖),FetchContent 在配置阶段完成依赖准备,能更早地将外部项目的目标和变量融入当前项目,使用更灵活。

        基本用法:

1) FetchContent_Declare():声明外部项目的信息(名称、下载地址、版本等);

2) FetchContent_MakeAvailable():实际执行下载、配置、构建,并将项目纳入当前构建系统。

2.2.FetchContent_Declare

2.2.1.简介

  FetchContent_Declare 是 CMake 中 FetchContent 模块的核心命令之一,用于声明外部项目的元信息(如下载地址、版本、配置选项等)。它本身不会实际下载或构建项目,只是定义 “如何要获取什么、从哪里获取”,后续通过 FetchContent_MakeAvailable 才会执行实际的下载、配置和构建流程。

        基本语法:

FetchContent_Declare(
  <项目名称>  # 自定义名称(用于后续引用,如声明为"googletest",后续用该名称操作)
  [URL <下载地址>]  # 从压缩包下载(.zip/.tar.gz等)
  [URL_HASH <算法>=<哈希值>]  # 验证下载文件完整性(如SHA256=xxx)
  [GIT_REPOSITORY <Git仓库地址>]  # 从Git仓库克隆
  [GIT_TAG <标签/分支/commit哈希>]  # Git仓库的版本标识(必填,否则默认拉取所有历史)
  [GIT_SHALLOW ON]  # 浅克隆(仅拉取最新版本,加快下载速度)
  [CMAKE_ARGS <参数1> <参数2> ...]  # 传递给外部项目的CMake配置参数
  [SOURCE_DIR <本地目录>]  # 强制使用本地源码目录(替代下载)
  # 其他可选参数(如SVN仓库、本地文件等)
)

核心参数说明:

参数 作用 适用场景
<项目名称> 自定义标识,后续通过该名称引用项目(如 googletestfmt)。 所有场景,必须唯一。
URL 外部项目压缩包的下载地址(如 .zip.tar.gz)。 从静态压缩包获取(版本固定,适合稳定依赖)。
GIT_REPOSITORY Git 仓库地址(如 https://github.com/google/googletest.git)。 从 Git 仓库获取(支持灵活选择版本)。
GIT_TAG Git 的版本标识(标签 tag、分支 branch 或 commit 哈希)。 与 GIT_REPOSITORY 配合,固定依赖版本。
GIT_SHALLOW 设为 ON 时,仅克隆最新版本(不包含完整历史),加快下载。 从 Git 仓库获取时推荐使用,节省时间和空间。
URL_HASH 验证下载文件的完整性(格式:<算法>=<哈希值>,如 SHA256=xxx)。 从 URL 下载时,防止文件损坏或篡改。
SOURCE_DIR  强制使用本地源码目录 使用URL下载不了源码的时候,强制使用本地源码目录特别好用
CMAKE_ARGS 传递给外部项目的 CMake 配置参数(如 -DBUILD_TESTING=OFF)。 需要自定义外部项目构建选项时。

2.2.2.关键特性

  1. 仅声明不执行FetchContent_Declare 只记录项目信息,不会实际下载或构建,需配合 FetchContent_MakeAvailable(<项目名称>) 才会执行后续操作。
  2. 顺序要求:必须在 FetchContent_MakeAvailable 之前声明,否则会报 No content details recorded 错误(如你之前遇到的问题)。
  3. 变量暴露:声明后,CMake 会自动创建 <项目名称>_SOURCE_DIR(源码目录)和 <项目名称>_BINARY_DIR(构建目录)变量,方便后续引用。

2.2.3.常见示例

示例 1:从 Git 仓库获取(推荐)

# 声明 googletest(从Git仓库获取release-1.12.1版本)
FetchContent_Declare(
    googletest# 外部项目的名称,后续会用到这个名称来引用它。
    GIT_REPOSITORY https://github.com/google/googletest.git# Git仓库URL。
    GIT_TAG  release-1.12.1# 指定要下载的Git标签或提交哈希,确保版本一致性。
    GIT_SHALLOW    ON       #可选:进行浅克隆,减少下载时间。
)

示例 2:从压缩包获取(带完整性验证)

# 声明 fmt 库(从压缩包获取10.2.1版本,带SHA256验证)
FetchContent_Declare(
  fmt
  URL           https://github.com/fmtlib/fmt/archive/refs/tags/10.2.1.zip  # 压缩包地址
  URL_HASH      SHA256=7a34cc45393a7ae957b29106dc2184411376d2b4ca289b1d64591481ca8e7  # 哈希值
)

示例 3:使用本地源码目录

FetchContent_Declare(
    googletest
    SOURCE_DIR  "C:/Users/Administrator/Desktop/googletest" #或 /usr/local/googletest
)

示例 4:传递自定义配置参数

# 声明 spdlog 并禁用其测试模块
FetchContent_Declare(
  spdlog
  GIT_REPOSITORY https://github.com/gabime/spdlog.git
  GIT_TAG        v1.14.1
  CMAKE_ARGS     -DSPDLOG_BUILD_TESTING=OFF  # 传递给spdlog的CMake参数(禁用测试)
)

2.3.FetchContent_MakeAvailable

2.3.1.简介

        FetchContent_MakeAvailable 是 CMake 中 FetchContent 模块的核心执行命令,用于将通过 FetchContent_Declare 声明的外部项目实际下载、配置、构建并集成到当前项目中。它是连接 “声明依赖信息” 和 “实际使用依赖” 的关键步骤,简化了外部项目的引入流程。

        基本语法:

FetchContent_MakeAvailable(<项目名称1> <项目名称2> ...)
  • 参数:一个或多个通过 FetchContent_Declare 声明过的项目名称(如 googletestfmt)。
  • 作用:对每个指定的项目,依次执行以下操作:
    1. 下载项目(从 FetchContent_Declare 声明的来源,如 Git 仓库、压缩包);
    2. 配置项目(生成其构建文件,如 Makefile 或 Visual Studio 项目);
    3. 构建项目(编译生成库或可执行文件);
    4. 将项目的目标(如库目标 GTest::gtest)暴露给当前项目,允许直接链接使用。

2.3.2.核心功能与工作流程

FetchContent_MakeAvailable 是一个 “一站式” 命令,自动处理外部项目从获取到集成的全流程,无需手动调用其他命令(如旧版本的 FetchContent_Populate)。其内部流程可拆解为:

  1. 检查缓存:先检查项目是否已下载(在构建目录的 _deps 文件夹中,如 build/_deps/googletest-src)。若已存在且版本匹配,直接复用,避免重复下载。
  2. 下载项目:若未缓存或版本不匹配,根据 FetchContent_Declare 声明的来源(Git 仓库、URL 等)下载源码。
  3. 配置与构建:进入外部项目的构建目录(如 build/_deps/googletest-build),生成构建文件并编译,默认构建静态库(可通过 CMAKE_ARGS 调整)。
  4. 暴露目标:将外部项目的 CMake 目标(如 GTest::gtestfmt::fmt)注册到当前项目的构建系统,允许通过 target_link_libraries 直接链接。

2.3.3.示例用法

 示例 1:集成单个项目(Google Test)

# 1. 引入 FetchContent 模块
include(FetchContent)

# 2. 声明项目(必须在 MakeAvailable 之前)
FetchContent_Declare(
  googletest
  GIT_REPOSITORY https://github.com/google/googletest.git
  GIT_TAG        v1.14.0  # 固定版本
  GIT_SHALLOW    ON       # 浅克隆
)

# 3. 执行下载、配置、构建(核心步骤)
FetchContent_MakeAvailable(googletest)

# 4. 使用外部项目的目标(直接链接)
add_executable(my_test test.cpp)
target_link_libraries(my_test PRIVATE GTest::gtest_main)  # GTest 目标已暴露

示例 2:集成多个项目(fmt + spdlog)

include(FetchContent)

# 声明第一个项目(fmt)
FetchContent_Declare(
  fmt
  GIT_REPOSITORY https://github.com/fmtlib/fmt.git
  GIT_TAG        10.2.1
)

# 声明第二个项目(spdlog,依赖 fmt)
FetchContent_Declare(
  spdlog
  GIT_REPOSITORY https://github.com/gabime/spdlog.git
  GIT_TAG        v1.14.1
  CMAKE_ARGS     -DSPDLOG_FMT_EXTERNAL=ON  # 告诉 spdlog 使用外部 fmt
)

# 同时处理多个项目(自动处理依赖顺序:先构建 fmt,再构建 spdlog)
FetchContent_MakeAvailable(fmt spdlog)

# 使用目标
add_executable(myapp main.cpp)
target_link_libraries(myapp PRIVATE spdlog::spdlog)  # spdlog 自动链接 fmt

2.3.4.关键特性

1.自动处理依赖顺序:若多个项目存在依赖关系(如 spdlog 依赖 fmt),FetchContent_MakeAvailable 会自动按依赖顺序构建,无需手动指定。

2.与当前项目集成:外部项目的构建会融入当前项目的构建系统(如并行编译、构建类型同步),例如当前项目用 Release 模式,外部项目也会默认用 Release 模式构建。

3.暴露项目路径变量:执行后会自动定义变量:

  • <项目名>_SOURCE_DIR:外部项目的源码目录(如 fmt_SOURCE_DIR);
  • <项目名>_BINARY_DIR:外部项目的构建目录(如 fmt_BINARY_DIR)。
message("fmt 源码路径: ${fmt_SOURCE_DIR}")  # 输出外部项目源码位置

4.缓存机制:下载的源码会缓存到构建目录的 _deps 文件夹,删除构建目录会清除缓存,重新构建时会重新下载。

2.3.5.常见问题与解决方案

1.错误:No content details recorded for <项目名>

  • 原因:FetchContent_MakeAvailable 引用的项目未通过 FetchContent_Declare 声明,或声明在 MakeAvailable 之后。
  • 解决:确保先调用 FetchContent_Declare 声明项目,再调用 MakeAvailable

2.网络问题导致下载失败

解决:通过命令行指定本地源码目录,跳过下载(需提前手动下载源码):

# 例如指定本地 fmt 源码目录
cmake .. -DFETCHCONTENT_SOURCE_DIR_FMT=/path/to/local/fmt

3.需要自定义外部项目的构建选项

解决:在 FetchContent_Declare 中通过 CMAKE_ARGS 传递参数,例如禁用外部项目的测试:

FetchContent_Declare(
  spdlog
  # ... 其他参数 ...
  CMAKE_ARGS -DSPDLOG_BUILD_TESTING=OFF  # 禁用 spdlog 自身的测试
)

3.FetchContent_MakeAvailable和FetchContent_Populate的区别

        在 CMake 中,FetchContent_MakeAvailable 和 FetchContent_Populate 都是 FetchContent 模块中用于处理外部项目的命令,但它们的设计目标、功能流程和使用方式有显著区别,核心差异在于自动化程度推荐用法

1.历史与状态       

  • FetchContent_Populate
    是早期 FetchContent 模块的核心命令,在 CMake 3.11 引入,用于 “填充”(下载、解压)外部项目的源码,但不自动处理配置和构建,需要手动后续步骤。
    从 CMake 3.24 开始被标记为 ** deprecated(弃用)**,官方推荐使用 FetchContent_MakeAvailable 替代(对应政策 CMP0169)。

  • FetchContent_MakeAvailable
    在 CMake 3.14 引入,是对 FetchContent_Populate 的升级,一站式自动化处理外部项目的下载、配置、构建和集成,无需手动干预后续步骤,是当前推荐的用法。

2.功能与流程差异

两者的核心目标都是获取外部项目,但流程复杂度不同:

FetchContent_Populate 的流程(手动为主)

  1. 需先通过 FetchContent_Declare 声明项目信息(如下载地址);
  2. 调用 FetchContent_Populate(<项目名>) 下载并解压源码到本地(仅完成 “获取源码”);
  3. 需手动配置和构建外部项目
    • 通常需要调用 add_subdirectory(${<项目名>_SOURCE_DIR} ${<项目名>_BINARY_DIR}) 将外部项目添加到构建系统;
    • 可能需要手动传递配置参数(如编译选项)。

示例:

include(FetchContent)
# 1. 声明
FetchContent_Declare(
  fmt
  GIT_REPOSITORY https://github.com/fmtlib/fmt.git
  GIT_TAG 10.2.1
)
# 2. 下载源码(仅这一步)
FetchContent_Populate(fmt)
# 3. 手动配置构建(必须手动添加子目录)
add_subdirectory(${fmt_SOURCE_DIR} ${fmt_BINARY_DIR})

FetchContent_MakeAvailable 的流程(全自动)

  1. 同样需先通过 FetchContent_Declare 声明项目信息;
  2. 调用 FetchContent_MakeAvailable(<项目名>) 后,自动完成:
    • 下载源码(若未缓存);
    • 配置外部项目(生成构建文件);
    • 构建外部项目(编译生成库);
    • 自动将外部项目的目标(如 fmt::fmt)暴露给当前项目,无需手动 add_subdirectory

示例:

include(FetchContent)
# 1. 声明
FetchContent_Declare(
  fmt
  GIT_REPOSITORY https://github.com/fmtlib/fmt.git
  GIT_TAG 10.2.1
)
# 2. 全自动处理(下载+配置+构建+集成)
FetchContent_MakeAvailable(fmt)
# 直接使用目标,无需手动 add_subdirectory
add_executable(myapp main.cpp)
target_link_libraries(myapp PRIVATE fmt::fmt)

3.核心差异对比

维度 FetchContent_Populate FetchContent_MakeAvailable
自动化程度 仅下载源码,配置 / 构建需手动(add_subdirectory 全自动:下载→配置→构建→集成,无需手动步骤
依赖处理 需手动管理多项目依赖顺序 自动处理依赖顺序(如 A 依赖 B,则先构建 B)
目标暴露 需外部项目自身支持 CMake 目标,且需手动链接 自动暴露目标(如 GTest::gtest),直接链接
当前状态 弃用(CMake 3.24+),不推荐新项目使用 推荐使用,是 FetchContent 的主流命令
使用复杂度 较高(多步骤,易出错) 较低(单步命令,简化流程)

4.为什么 FetchContent_Populate 被弃用?

FetchContent_Populate 仅完成 “下载源码” 这一步,后续的配置、构建、目标集成需要手动处理,存在以下问题:

  • 流程繁琐,易遗漏步骤(如忘记 add_subdirectory);
  • 多项目依赖时,需手动维护构建顺序,容易出错;
  • 与现代 CMake 的 “目标驱动” 理念不符(需要显式处理路径和配置)。

而 FetchContent_MakeAvailable 通过自动化这些步骤,解决了上述问题,更符合 CMake 简化构建流程的设计目标。

4.add_test

CMake指令:add_test-CSDN博客

5.完整示例

以下是一个完整的 CMake 项目示例,展示如何结合 CTest 和 Google Test (GTest) 进行单元测试。示例包含项目结构、核心代码和使用方法。

5.1.项目结构

5.2.代码实现

1.根目录 CMakeLists.txt

cmake_minimum_required(VERSION 3.14)
project(CalculatorDemo)

# 启用 CTest(必须放在测试目标定义前)
enable_testing()

# 添加主程序和测试子目录
add_subdirectory(src)
add_subdirectory(tests)

2.主程序 src/calculator.h

#ifndef CALCULATOR_H
#define CALCULATOR_H

// 待测试的简单计算器函数
int add(int a, int b);
int multiply(int a, int b);
bool is_even(int n);

#endif // CALCULATOR_H

3.主程序 src/calculator.cpp

#include "calculator.h"

int add(int a, int b) {
    return a + b;
}

int multiply(int a, int b) {
    return a * b;
}

bool is_even(int n) {
    return n % 2 == 0;
}

4.主程序 src/CMakeLists.txt

# 生成静态库(方便测试代码链接)
add_library(calculator STATIC calculator.cpp calculator.h)

# 暴露头文件路径(测试代码需要包含 calculator.h)
target_include_directories(calculator PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

5.测试用例 tests/calculator_test.cpp

#include <gtest/gtest.h>
#include "calculator.h"  // 包含待测试的头文件

// 测试 add 函数
TEST(CalculatorTest, Add) {
    EXPECT_EQ(add(2, 3), 5);       // 正常情况
    EXPECT_EQ(add(-1, 1), 0);      // 正负混合
    EXPECT_EQ(add(0, 0), 0);       // 零值
}

// 测试 multiply 函数
TEST(CalculatorTest, Multiply) {
    EXPECT_EQ(multiply(3, 4), 12); // 正常情况
    EXPECT_EQ(multiply(-2, 5), -10); // 负数乘法
    EXPECT_EQ(multiply(0, 100), 0); // 乘以零
}

// 测试 is_even 函数
TEST(CalculatorTest, IsEven) {
    EXPECT_TRUE(is_even(4));       // 偶数
    EXPECT_FALSE(is_even(7));      // 奇数
    EXPECT_TRUE(is_even(0));       // 零(视为偶数)
    EXPECT_TRUE(is_even(-6));      // 负偶数
}

// GTest 提供默认 main 函数,无需手动实现

6.测试配置 tests/CMakeLists.txt

cmake_minimum_required(VERSION 3.14)

# 引入 FetchContent 模块,自动下载 GTest
include(FetchContent)

# 配置 GTest 下载(使用 v1.14.0 版本)
#FetchContent_Declare(
 #   googletest
  #  URL https://github.com/google/googletest/archive/refs/tags/v1.14.0.zip
  #  URL_HASH SHA256=8ad598c73ad796e0d82c9be7c307668eaf10519ce3287a0161b7a8006cf3d
#)
FetchContent_Declare(
    googletest# 外部项目的名称,后续会用到这个名称来引用它。
    GIT_REPOSITORY https://github.com/google/googletest.git# Git仓库URL。
    GIT_TAG  release-1.12.1# 指定要下载的Git标签或提交哈希,确保版本一致性。
    GIT_SHALLOW    ON       #可选:进行浅克隆,减少下载时间。
)
#FetchContent_Declare(
#    googletest
#    SOURCE_DIR  "C:/Users/Administrator/Desktop/googletest"
#)

if (MSVC)
    # 针对Visual Studio的特定配置:
    # 强制Google Test使用共享运行时库(CRT),以避免与主项目不一致。
    set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
    # 禁用Google Test使用PThreads,避免潜在的冲突或不必要的依赖。
    set(gtest_disable_pthreads ON CACHE BOOL "" FORCE)
endif()

# 完成 GTest 下载和配置
FetchContent_MakeAvailable(googletest)

# 生成测试可执行文件
add_executable(calculator_test calculator_test.cpp)

# 链接依赖:待测试的库 + GTest 框架
target_link_libraries(
    calculator_test
    PRIVATE
    calculator          # 主程序的静态库
    GTest::gtest_main   # GTest 主程序(提供默认 main 函数)
)

# 将测试注册到 CTest(名称为 calculator_test)
add_test(
    NAME calculator_test
#    COMMAND $<TARGET_FILE:calculator_test> # 运行测试的命令,这里使用CMake生成的可执行文件路径。
    COMMAND calculator_test
)

5.3.运行项目

1.构建项目

# 创建构建目录
mkdir build && cd build

# 生成构建文件(自动下载 GTest)
cmake ..

当前CMakeLists.txt中配置是从网络上下载googletest,如果不出什么差错,会输出:

在./build/_deps就会有googletest的源码目录:

2.编译项目

可以用CMake命令直接构建(这个命令是跨平台的,Linux也可以):

cmake --build .  --config Release

如果是在windows的vs环境中,直接用vs打开编译即可。

3.运行测试

# 方法 1:使用 ctest 命令
ctest                  # 简洁输出
ctest -V               # 详细输出(推荐调试)
ctest -R calculator    # 仅运行名称包含 "calculator" 的测试
ctest -C Release -V    # 实际测试用的这个命令

# 方法 2:使用 make 命令(等价于 ctest)
make test

 实际效果运行如下:

5.4.遇到的问题

1.FetchContent_MakeAvailable报错

PS D:\OpenProject\myUnitTestEx\build> cmake ..
-- Building for: Visual Studio 17 2022
-- The C compiler identification is MSVC 19.43.34810.0
-- The CXX compiler identification is MSVC 19.43.34810.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: C:/Program Files/Microsoft Visual Studio/2022/Professional/VC/Tools/MSVC/14.43.34808/bin/Hostx64/x64/cl.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: C:/Program Files/Microsoft Visual Studio/2022/Professional/VC/Tools/MSVC/14.43.34808/bin/Hostx64/x64/cl.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
CMake Error at C:/Program Files/CMake/share/cmake-4.0/Modules/FetchContent.cmake:1263 (message):
  No content details recorded for googletest
Call Stack (most recent call first):
  C:/Program Files/CMake/share/cmake-4.0/Modules/FetchContent.cmake:2034 (__FetchContent_getSavedDetails)
  C:/Program Files/CMake/share/cmake-4.0/Modules/FetchContent.cmake:2384 (__FetchContent_Populate)
  tests/CMakeLists.txt:21 (FetchContent_MakeAvailable)


-- Configuring incomplete, errors occurred!

当时调试的时候就一直报这个错误,也不知道是网络原因还是什么其它原因,于是我手动下载googletest。

https://github.com/google/googletest.git

在CMakeLists.txt中直接用本地的googletest,修改CMakeLists.txt

用同样的方法构建编译即可。

2.没有找到pthread_create

-- Check for working CXX compiler: C:/Program Files/Microsoft Visual Studio/2022/Professional/VC/Tools/MSVC/14.43.34808/bin/Hostx64/x64/cl.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Failed
-- Looking for pthread_create in pthreads
-- Looking for pthread_create in pthreads - not found
-- Looking for pthread_create in pthread
-- Looking for pthread_create in pthread - not found
-- Found Threads: TRUE
-- Configuring done (7.9s)
-- Generating done (0.2s)
-- Build files have been written to: D:/OpenProject/myUnitTestEx/build

因为当前是Windows环境,默认是没有安装pthreads,于是在CMakeLists.txt配置不使用pthreads,在linux环境可以直接用pthreads,调整如下:

3.运行ctest报错

PS D:\OpenProject\myUnitTestEx\build> ctest
Test project D:/OpenProject/myUnitTestEx/build
    Start 1: calculator_test
Test not available without configuration.  (Missing "-C <config>"?)
1/1 Test #1: calculator_test ..................***Not Run   0.00 sec

0% tests passed, 1 tests failed out of 1

Total Test time (real) =   0.01 sec

The following tests FAILED:
          1 - calculator_test (Not Run)
Errors while running CTest
Output from these tests are in: D:/OpenProject/myUnitTestEx/build/Testing/Temporary/LastTest.log
Use "--rerun-failed --output-on-failure" to re-run the failed cases verbosely.

原因是使用的是多配置生成器(如 Visual Studio),这类生成器需要明确指定构建配置(如 Debug 或 Release)才能运行测试,否则 CTest 不知道要执行哪个版本的测试程序。

解决方法:运行 CTest 时指定配置

在多配置生成器(如 Visual Studio、Xcode)中,必须通过 -C <配置名> 参数指定测试的配置(与构建时的配置一致)。例如:

# 运行 Debug 配置的测试(最常用,默认构建通常是 Debug)
ctest -C Debug

# 若构建了 Release 配置,运行 Release 版本的测试
ctest -C Release

如果需要查看详细的测试输出(方便调试),可以加上 -V 参数:

ctest -C Debug -V  # 详细输出 Debug 配置的测试过程

为什么会出现这个错误?

CMake 生成器分为两类:

  • 单配置生成器(如 Makefile、Ninja):一次只能生成一种配置(如默认 Debug 或 Release),运行 ctest 时无需指定配置。
  • 多配置生成器(如 Visual Studio、Xcode):一次可生成多种配置(同时支持 DebugRelease 等),测试程序会分别编译到 build/Debugbuild/Release 等目录。因此,运行 ctest 时必须用 -C 指定具体配置,否则 CTest 找不到对应的测试可执行文件。

4.CMake版本警告

CMake Deprecation Warning at build/_deps/googletest-src/CMakeLists.txt:4 (cmake_minimum_required):
  Compatibility with CMake < 3.10 will be removed from a future version of
  CMake.

  Update the VERSION argument <min> value.  Or, use the <min>...<max> syntax
  to tell CMake that the project requires at least <min> but has been updated
  to work with policies introduced by <max> or earlier.


CMake Deprecation Warning at build/_deps/googletest-src/googlemock/CMakeLists.txt:39 (cmake_minimum_required):
  Compatibility with CMake < 3.10 will be removed from a future version of
  CMake.

  Update the VERSION argument <min> value.  Or, use the <min>...<max> syntax
  to tell CMake that the project requires at least <min> but has been updated
  to work with policies introduced by <max> or earlier.


CMake Deprecation Warning at build/_deps/googletest-src/googletest/CMakeLists.txt:49 (cmake_minimum_required):
  Compatibility with CMake < 3.10 will be removed from a future version of
  CMake.

  Update the VERSION argument <min> value.  Or, use the <min>...<max> syntax
  to tell CMake that the project requires at least <min> but has been updated
  to work with policies introduced by <max> or earlier.

        这些警告是由于你使用的 Google Test (GTest) 版本中,其内部 CMakeLists.txt 指定的最低 CMake 版本过低(低于 3.10),而你当前使用的 CMake 版本较新,提前提示 “未来版本将不再支持低版本 CMake 兼容”。

        解决方法可参考:

CMake进阶: CMake的策略和向后兼容-CSDN博客

整个示例代码,本人在麒麟操作系统下亲测也有效:

5.5.完整代码下载

通过网盘分享的文件:myUnitTestEx.zip 链接: https://pan.baidu.com/s/1stIRyqhUSDG4e3zcoAqudg?pwd=1234 提取码: 1234 

6.优势与适用场景

  1. 简化依赖管理:无需用户手动下载、安装外部库,CMake 自动处理,提升项目可移植性。
  2. 配置阶段完成:依赖在 cmake 配置时准备就绪,避免 ExternalProject 在构建阶段才下载导致的并行构建问题。
  3. 无缝集成目标:外部项目的目标(如 GTest::gtestfmt::fmt)可直接通过 target_link_libraries 链接,与本地目标用法一致。
  4. 适合第三方库:尤其适合集成开源库(如 GTest、spdlog、fmt 等),无需修改库源码即可使用。

7.注意事项

1.CMake 版本要求:需 CMake 3.11 及以上,部分高级特性(如 GIT_SHALLOW)需要更高版本(3.14+)。

2.网络依赖:构建项目时需要网络连接(首次下载),可通过 FETCHCONTENT_SOURCE_DIR_<项目名称> 变量指定本地目录,避免重复下载:

# 命令行指定本地目录(已提前下载的源码)
cmake .. -DFETCHCONTENT_SOURCE_DIR_GOOGLETEST=/path/to/local/gtest

3.缓存机制:下载的源码会缓存到构建目录的 _deps 文件夹(如 build/_deps/googletest-src),删除构建目录会触发重新下载。

8.总结

        FetchContent是现代 CMake 项目管理外部依赖的首选工具,通过简洁的配置即可自动下载、集成第三方库,大幅简化了跨平台项目的依赖管理流程。对于需要依赖多个开源库的项目,使用 FetchContent 能显著提升构建的便捷性和一致性。

相关链接


网站公告

今日签到

点亮在社区的每一天
去签到