目录
2.3.FetchContent_MakeAvailable
3.FetchContent_MakeAvailable和FetchContent_Populate的区别
1.前言
在现代C++项目开发中,单元测试是确保代码质量和可维护性的关键环节。Google Test(GTest)作为一款功能强大、广受欢迎的C++测试框架,提供了丰富的断言、测试夹具和测试发现机制。本文演示如何利用CMake的FetchContent
模块,优雅地集成和使用Google Test进行单元测试。不仅会展示具体步骤,还会深入探讨FetchContent
的工作原理,帮助更好地理解其在项目管理中的优势。
前面讲了gTest的安装与配置方法:
这种方法是先安装好gTest,再利用CMake的find_package查找它,然后链接它,其实也比较简单,如有不理解的地方,可参考:
下面来讲讲另外一种方法,用FetchContent引入gTest。
2.FetchContent详解
2.1.FetchContent简介
FetchContent是定义在FetchContent.cmake当中的,FetchContent.cmake
是 CMake 3.11 及以上版本提供的一个内置模块,用于在配置阶段下载、配置和集成外部项目(如第三方库),无需用户手动安装依赖。它解决了传统依赖管理(如手动下载、ExternalProject
)的繁琐问题,让外部项目的集成更简洁、高效。
FetchContent
的核心是在 CMake 配置阶段(执行 cmake
命令时)自动完成以下操作:
- 下载外部项目(从 URL、Git 仓库等);
- 配置外部项目(生成其构建文件);
- 构建外部项目(可选,默认会构建);
- 将外部项目的目标(库、可执行文件)暴露给当前项目,方便直接链接使用。
相比传统的 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仓库、本地文件等)
)
核心参数说明:
参数 | 作用 | 适用场景 |
---|---|---|
<项目名称> |
自定义标识,后续通过该名称引用项目(如 googletest 、fmt )。 |
所有场景,必须唯一。 |
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.关键特性
- 仅声明不执行:
FetchContent_Declare
只记录项目信息,不会实际下载或构建,需配合FetchContent_MakeAvailable(<项目名称>)
才会执行后续操作。 - 顺序要求:必须在
FetchContent_MakeAvailable
之前声明,否则会报No content details recorded
错误(如你之前遇到的问题)。 - 变量暴露:声明后,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
声明过的项目名称(如googletest
、fmt
)。 - 作用:对每个指定的项目,依次执行以下操作:
- 下载项目(从
FetchContent_Declare
声明的来源,如 Git 仓库、压缩包); - 配置项目(生成其构建文件,如 Makefile 或 Visual Studio 项目);
- 构建项目(编译生成库或可执行文件);
- 将项目的目标(如库目标
GTest::gtest
)暴露给当前项目,允许直接链接使用。
- 下载项目(从
2.3.2.核心功能与工作流程
FetchContent_MakeAvailable
是一个 “一站式” 命令,自动处理外部项目从获取到集成的全流程,无需手动调用其他命令(如旧版本的 FetchContent_Populate
)。其内部流程可拆解为:
- 检查缓存:先检查项目是否已下载(在构建目录的
_deps
文件夹中,如build/_deps/googletest-src
)。若已存在且版本匹配,直接复用,避免重复下载。 - 下载项目:若未缓存或版本不匹配,根据
FetchContent_Declare
声明的来源(Git 仓库、URL 等)下载源码。 - 配置与构建:进入外部项目的构建目录(如
build/_deps/googletest-build
),生成构建文件并编译,默认构建静态库(可通过CMAKE_ARGS
调整)。 - 暴露目标:将外部项目的 CMake 目标(如
GTest::gtest
、fmt::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
的流程(手动为主)
- 需先通过
FetchContent_Declare
声明项目信息(如下载地址); - 调用
FetchContent_Populate(<项目名>)
下载并解压源码到本地(仅完成 “获取源码”); - 需手动配置和构建外部项目:
- 通常需要调用
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
的流程(全自动)
- 同样需先通过
FetchContent_Declare
声明项目信息; - 调用
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
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):一次可生成多种配置(同时支持
Debug
、Release
等),测试程序会分别编译到build/Debug
、build/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 兼容”。
解决方法可参考:
整个示例代码,本人在麒麟操作系统下亲测也有效:
5.5.完整代码下载
通过网盘分享的文件:myUnitTestEx.zip 链接: https://pan.baidu.com/s/1stIRyqhUSDG4e3zcoAqudg?pwd=1234 提取码: 1234
6.优势与适用场景
- 简化依赖管理:无需用户手动下载、安装外部库,CMake 自动处理,提升项目可移植性。
- 配置阶段完成:依赖在
cmake
配置时准备就绪,避免ExternalProject
在构建阶段才下载导致的并行构建问题。 - 无缝集成目标:外部项目的目标(如
GTest::gtest
、fmt::fmt
)可直接通过target_link_libraries
链接,与本地目标用法一致。 - 适合第三方库:尤其适合集成开源库(如 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
能显著提升构建的便捷性和一致性。
相关链接
- CMake 官网 CMake - Upgrade Your Software Build System
- CMake 官方文档:CMake Tutorial — CMake 4.1.0-rc4 Documentation
- CMake 源码:https://github.com/Kitware/CMake
- CMake 源码:CMake · GitLab
- 中文版基础介绍: CMake 入门实战 | HaHack
- wiki: Home · Wiki · CMake / Community · GitLab
- Modern CMake 简体中文版: Introduction · Modern CMake