目錄
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
?命令時)自動完成以下操作:
- 下載外部項目(從 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(fmtURL https://github.com/fmtlib/fmt/archive/refs/tags/10.2.1.zip # 壓縮包地址URL_HASH SHA256=7a34cc45393a7ae957b29106dc2184411376d2b4ca289b1d64591481ca8e7 # 哈希值
)
示例 3:使用本地源碼目錄
FetchContent_Declare(googletestSOURCE_DIR "C:/Users/Administrator/Desktop/googletest" #或 /usr/local/googletest
)
示例 4:傳遞自定義配置參數
# 聲明 spdlog 并禁用其測試模塊
FetchContent_Declare(spdlogGIT_REPOSITORY https://github.com/gabime/spdlog.gitGIT_TAG v1.14.1CMAKE_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(googletestGIT_REPOSITORY https://github.com/google/googletest.gitGIT_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(fmtGIT_REPOSITORY https://github.com/fmtlib/fmt.gitGIT_TAG 10.2.1
)# 聲明第二個項目(spdlog,依賴 fmt)
FetchContent_Declare(spdlogGIT_REPOSITORY https://github.com/gabime/spdlog.gitGIT_TAG v1.14.1CMAKE_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(fmtGIT_REPOSITORY https://github.com/fmtlib/fmt.gitGIT_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(fmtGIT_REPOSITORY https://github.com/fmtlib/fmt.gitGIT_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_testPRIVATEcalculator # 主程序的靜態庫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/buildStart 1: calculator_test
Test not available without configuration. (Missing "-C <config>"?)
1/1 Test #1: calculator_test ..................***Not Run 0.00 sec0% tests passed, 1 tests failed out of 1Total Test time (real) = 0.01 secThe 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 ofCMake.Update the VERSION argument <min> value. Or, use the <min>...<max> syntaxto tell CMake that the project requires at least <min> but has been updatedto 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 ofCMake.Update the VERSION argument <min> value. Or, use the <min>...<max> syntaxto tell CMake that the project requires at least <min> but has been updatedto 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 ofCMake.Update the VERSION argument <min> value. Or, use the <min>...<max> syntaxto tell CMake that the project requires at least <min> but has been updatedto 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.優勢與適用場景
- 簡化依賴管理:無需用戶手動下載、安裝外部庫,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