【CMake】Ctest,Cpack
目录
一.Ctest
1.1.示例一——enable_testing()版本
1.1.1.成功的情况
1.1.2.失败的情况
1.2. 开启 CTest 测试支持的两种方式
1.3.示例二——include(Ctest)版本
1.3.1.成功的情况
1.3.2.失败的情况
二.Cpack
一.Ctest
Ctest测试的是一个可执行程序!
CTest 测试的对象就是一个可执行程序,无论这个可执行程序里做了什么,CTest 都只关心 程序退出码(exit code):
-
返回 0 → 测试通过(Passed)
-
返回非 0 → 测试失败(Failed)
1.1.示例一——enable_testing()版本
1.1.1.成功的情况
好 👍 我给你举一个 最简单的 CTest
示例,一步一步说明它是怎么用的。
📂 项目结构
CTestExample/
├── CMakeLists.txt
└── test.cpp
📄 CMakeLists.txt
cmake_minimum_required(VERSION 3.18)
project(CTestExample LANGUAGES CXX)set(CMAKE_CXX_STANDARD 11)# 开启测试功能
enable_testing()# 生成我们需要测试的可执行程序
add_executable(test_example test.cpp)# 注册测试
add_test(NAME RunTest COMMAND test_example)
📄 test.cpp
#include <iostream>
int main() {std::cout << "This is a simple test." << std::endl;// 模拟一个测试:如果条件成立就返回 0(成功),否则返回非 0(失败)if (1 + 1 == 2) {return 0; // 测试通过} else {return 1; // 测试失败}
}
对于上面这个项目,我们可以一键复制下面这个命令来一键构建出
mkdir -p CTestExample && cd CTestExample && \
cat > CMakeLists.txt <<'EOF'
cmake_minimum_required(VERSION 3.18)
project(CTestExample LANGUAGES CXX)set(CMAKE_CXX_STANDARD 11)# 开启测试功能
enable_testing()# 测试程序
add_executable(test_example test.cpp)# 注册测试
add_test(NAME RunTest COMMAND test_example)
EOFcat > test.cpp <<'EOF'
#include <iostream>
int main() {std::cout << "This is a simple test." << std::endl;// 模拟一个测试:如果条件成立就返回 0(成功),否则返回非 0(失败)if (1 + 1 == 2) {return 0; // 测试通过} else {return 1; // 测试失败}
}
EOF
接下来我们就来看看
mkdir build && cd build && cmake .. && make
接下来我们就来进行测试一下
ctest
这是测试成功的情况。我帮你逐行解析一下:
Test project /root/cmake1/CTestExample/build
-
表示 CTest 正在运行这个构建目录下的测试项目。
Start 1: RunTest
-
开始执行第 1 个测试。
-
名称是
RunTest
(在CMakeLists.txt
用add_test(NAME RunTest COMMAND test_example)
注册的)。
1/1 Test #1: RunTest .......................... Passed 0.00 sec
-
1/1 Test #1
→ 总共有 1 个测试,这是第 1 个。 -
RunTest
→ 测试的名称。 -
Passed
→ 测试成功。-
说明运行
./test_example
时 返回值是 0,CTest 判定测试通过。
-
-
0.00 sec
→ 测试运行耗时 0 秒。
100% tests passed, 0 tests failed out of 1
-
总共有 1 个测试
-
100% 通过
-
0 个失败
Total Test time (real) = 0.01 sec
-
所有测试总耗时约 0.01 秒
1.1.2.失败的情况
那失败的情况呢?我们可以去把test.cpp修改成下面这样子
#include <iostream>
int main() {std::cout << "This is a simple test." << std::endl;// 模拟一个测试:如果条件成立就返回 0(成功),否则返回非 0(失败)if (1 + 1 == 3) {return 0; // 测试通过} else {return 1; // 测试失败}
}
然后我们重新构建一下项目来看看
rm -rf build && mkdir build && cd build && cmake .. && make
接下来我们就来进行测试
ctest
我们来详细解释一下你看到的这个 CTest 输出:
Test project /root/cmake1/CTestExample/buildStart 1: RunTest
1/1 Test #1: RunTest ..........................***Failed 0.00 sec
-
Test project /root/cmake1/CTestExample/build
→ 表示 CTest 正在运行build
目录下的测试项目。 -
Start 1: RunTest
→ 第 1 个测试开始执行,它的名字叫RunTest
(你在CMakeLists.txt
用add_test(NAME RunTest ...)
定义的)。 -
Failed
→ 测试失败了。CTest 判定测试是否成功是 根据程序返回值:-
返回
0
→ 通过(Passed) -
返回非
0
→ 失败(Failed)
-
-
0.00 sec
→ 测试耗时 0 秒。
0% tests passed, 1 tests failed out of 1
-
总共 1 个测试
-
0% 通过
-
1 个失败
Total Test time (real) = 0.00 sec
-
所有测试耗时总计 0 秒。
The following tests FAILED:1 - RunTest (Failed)
-
明确列出失败的测试名称和序号。
Errors while running CTest
Output from these tests are in: /root/cmake1/CTestExample/build/Testing/Temporary/LastTest.log
-
出错信息被保存到了
LastTest.log
文件里,你可以打开看程序的标准输出/错误信息。
Use "--rerun-failed --output-on-failure" to re-run the failed cases verbosely.
-
提示你可以用更详细的命令重跑失败的测试:
ctest --rerun-failed --output-on-failure
这样你就能看到测试程序输出的 std::cout
信息,方便调试。
1.2. 开启 CTest 测试支持的两种方式
事实上,开启Ctest测试支持的方式有两种,
- enable_testing()
- include(Ctest)
我们来看看
1️⃣ enable_testing()
enable_testing()
-
官方命令,用于开启 CTest 测试支持
-
作用:
-
设置 CMake 内部变量
BUILD_TESTING=ON
-
允许你用
add_test()
注册测试
-
-
最常用、最直接的方式
2️⃣ include(CTest)
include(CTest)
-
本质上是包含 CTest 模块
-
内部会调用
enable_testing()
,同时提供一些额外功能:-
例如处理
CTEST_CUSTOM_TESTS_IGNORE
-
处理
CDASH
/CTestTestfile.cmake
相关的高级选项
-
-
对于简单项目,
include(CTest)
相当于“带功能的enable_testing()
”
🔑 区别总结
命令 | 是否开启测试 | 额外功能 | 用途 |
---|---|---|---|
| ✅ | 无 | 基础开启测试功能 |
| ✅ | 提供一些 CTest 模块和 CDASH 支持 | 高级项目/官方示例常用 |
⚡ 建议
-
简单项目:
enable_testing()
就够了 -
参考官方示例或 CDash 报告:
include(CTest)
更完整
1.3.示例二——include(Ctest)版本
1.3.1.成功的情况
📂 项目结构
CTestExample/
├── CMakeLists.txt
└── test.cpp
📄 CMakeLists.txt
cmake_minimum_required(VERSION 3.18)
project(CTestExample LANGUAGES CXX)set(CMAKE_CXX_STANDARD 11)# 启用测试支持
include(CTest)# 生成我们需要测试的可执行程序
add_executable(test_example test.cpp)# 注册测试
add_test(NAME RunTest COMMAND test_example)
📄 test.cpp
#include <iostream>
int main() {std::cout << "This is a simple test." << std::endl;// 模拟一个测试:如果条件成立就返回 0(成功),否则返回非 0(失败)if (1 + 1 == 2) {return 0; // 测试通过} else {return 1; // 测试失败}
}
对于上面这个项目,我们可以一键复制下面这个命令来一键构建出
mkdir -p CTestExample && cd CTestExample && \
cat > CMakeLists.txt <<'EOF'
cmake_minimum_required(VERSION 3.18)
project(CTestExample LANGUAGES CXX)set(CMAKE_CXX_STANDARD 11)# 启用测试支持
include(CTest)# 测试程序
add_executable(test_example test.cpp)# 注册测试
add_test(NAME RunTest COMMAND test_example)
EOFcat > test.cpp <<'EOF'
#include <iostream>
int main() {std::cout << "This is a simple test." << std::endl;// 模拟一个测试:如果条件成立就返回 0(成功),否则返回非 0(失败)if (1 + 1 == 2) {return 0; // 测试通过} else {return 1; // 测试失败}
}
EOF
接下来我们就来看看
mkdir build && cd build && cmake .. && make
接下来我们就来进行测试一下
ctest
这是测试成功的情况。我帮你逐行解析一下:
Test project /root/cmake1/CTestExample/build
-
表示 CTest 正在运行这个构建目录下的测试项目。
Start 1: RunTest
-
开始执行第 1 个测试。
-
名称是
RunTest
(在CMakeLists.txt
用add_test(NAME RunTest COMMAND test_example)
注册的)。
1/1 Test #1: RunTest .......................... Passed 0.00 sec
-
1/1 Test #1
→ 总共有 1 个测试,这是第 1 个。 -
RunTest
→ 测试的名称。 -
Passed
→ 测试成功。-
说明运行
./test_example
时 返回值是 0,CTest 判定测试通过。
-
-
0.00 sec
→ 测试运行耗时 0 秒。
100% tests passed, 0 tests failed out of 1
-
总共有 1 个测试
-
100% 通过
-
0 个失败
Total Test time (real) = 0.01 sec
-
所有测试总耗时约 0.01 秒
1.3.2.失败的情况
那失败的情况呢?我们可以去把test.cpp修改成下面这样子
#include <iostream>
int main() {std::cout << "This is a simple test." << std::endl;// 模拟一个测试:如果条件成立就返回 0(成功),否则返回非 0(失败)if (1 + 1 == 3) {return 0; // 测试通过} else {return 1; // 测试失败}
}
然后我们重新构建一下项目来看看
rm -rf build && mkdir build && cd build && cmake .. && make
接下来我们就来进行测试
ctest
我们来详细解释一下你看到的这个 CTest 输出:
Test project /root/cmake1/CTestExample/buildStart 1: RunTest
1/1 Test #1: RunTest ..........................***Failed 0.00 sec
-
Test project /root/cmake1/CTestExample/build
→ 表示 CTest 正在运行build
目录下的测试项目。 -
Start 1: RunTest
→ 第 1 个测试开始执行,它的名字叫RunTest
(你在CMakeLists.txt
用add_test(NAME RunTest ...)
定义的)。 -
Failed
→ 测试失败了。CTest 判定测试是否成功是 根据程序返回值:-
返回
0
→ 通过(Passed) -
返回非
0
→ 失败(Failed)
-
-
0.00 sec
→ 测试耗时 0 秒。
0% tests passed, 1 tests failed out of 1
-
总共 1 个测试
-
0% 通过
-
1 个失败
Total Test time (real) = 0.00 sec
-
所有测试耗时总计 0 秒。
The following tests FAILED:1 - RunTest (Failed)
-
明确列出失败的测试名称和序号。
Errors while running CTest
Output from these tests are in: /root/cmake1/CTestExample/build/Testing/Temporary/LastTest.log
-
出错信息被保存到了
LastTest.log
文件里,你可以打开看程序的标准输出/错误信息。
Use "--rerun-failed --output-on-failure" to re-run the failed cases verbosely.
-
提示你可以用更详细的命令重跑失败的测试:
ctest --rerun-failed --output-on-failure
这样你就能看到测试程序输出的 std::cout
信息,方便调试。
二.Cpack
我们先来看一个最简单的例子
1️⃣ 目录结构
SimpleApp/
├── CMakeLists.txt
└── main.cpp
main.cpp
示例:
#include <iostream>
int main() {std::cout << "Hello CPack!" << std::endl;return 0;
}
2️⃣ CMakeLists.txt 示例
cmake_minimum_required(VERSION 3.10)
project(SimpleApp VERSION 1.0 LANGUAGES CXX)# 添加可执行程序
add_executable(simple_app main.cpp)# --- 最简单的 CPack 配置 ---
include(CPack) # 启用 CPack
set(CPACK_PACKAGE_NAME "SimpleApp")
set(CPACK_PACKAGE_VERSION "1.0.0")
set(CPACK_GENERATOR "ZIP") # 打包成 zip
set(CPACK_ARCHIVE_COMPONENT_INSTALL ON)# 告诉 CPack 打包可执行程序
install(TARGETS simple_app DESTINATION .) # 安装到根目录即可
其实我们可以执行下面这个命令来一键搭建出我们的项目的目录结构和文件内容
mkdir -p SimpleApp && \
cat > SimpleApp/main.cpp <<'EOF'
#include <iostream>
int main() {std::cout << "Hello CPack!" << std::endl;return 0;
}
EOF
cat > SimpleApp/CMakeLists.txt <<'EOF'
cmake_minimum_required(VERSION 3.10)
project(SimpleApp VERSION 1.0 LANGUAGES CXX)# 添加可执行程序
add_executable(simple_app main.cpp)# --- 最简单的 CPack 配置 ---
include(CPack)
set(CPACK_PACKAGE_NAME "SimpleApp")
set(CPACK_PACKAGE_VERSION "1.0.0")
set(CPACK_GENERATOR "ZIP")
set(CPACK_ARCHIVE_COMPONENT_INSTALL ON)# 告诉 CPack 打包可执行程序
install(TARGETS simple_app DESTINATION .)
EOF
3️⃣ 打包流程
mkdir build && cd build && \
cmake .. && \
cmake --build .
现在我们仔细看看我们build目录
接下来我们进行打包操作
cpack
我们可以把它解压一下
怎么样?还行吧!!