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

目录

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_TAG ]  # Git仓库的版本标识(必填,否则默认拉取所有历史)
[GIT_SHALLOW ON]  # 浅克隆(仅拉取最新版本,加快下载速度)
[CMAKE_ARGS   ...]  # 传递给外部项目的CMake配置参数
[SOURCE_DIR ]  # 强制使用本地源码目录(替代下载)
# 其他可选参数(如SVN仓库、本地文件等)
)

核心参数说明:

参数作用适用场景
<项目名称>自定义标识,后续通过该名称引用项目(如 googletestfmt)。所有场景,必须唯一。
URL外部项目压缩包的下载地址(如 .zip.tar.gz)。从静态压缩包获取(版本固定,适合稳定依赖)。
GIT_REPOSITORYGit 仓库地址(如 https://github.com/google/googletest.git)。从 Git 仓库获取(支持灵活选择版本)。
GIT_TAGGit 的版本标识(标签 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(  ...)
  • 参数:一个或多个通过 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_PopulateFetchContent_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
#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 $ # 运行测试的命令,这里使用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 "?)
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  value.  Or, use the ... syntax
to tell CMake that the project requires at least  but has been updated
to work with policies introduced by  or earlier.
CMake Deprecation Warning at build/_deps/googletest-src/googlemock/CMakeLists.txt:39 (cmake_minimum_required):
Compatibility with CMake  value.  Or, use the ... syntax
to tell CMake that the project requires at least  but has been updated
to work with policies introduced by  or earlier.
CMake Deprecation Warning at build/_deps/googletest-src/googletest/CMakeLists.txt:49 (cmake_minimum_required):
Compatibility with CMake  value.  Or, use the ... syntax
to tell CMake that the project requires at least  but has been updated
to work with policies introduced by  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 能显著提升构建的便捷性和一致性。

相关链接

posted @ 2025-08-09 10:14  yfceshi  阅读(8)  评论(0)    收藏  举报