如何处理全局变量和变量范围问题?
通过加载项目的注入全局变量到测试中
缓存,配置测试 CMake 文件或通过 -D 命令行推送它
选项?
一般来说,所有当前存在的方法(通过缓存、通过环境变量和通过 -D 命令行)在一种或另一种情况下都是不好的选择,因为它涉及不可预测的行为。
这是我能回忆起的最少问题清单:
- 哪个变量可以与另一个变量相交/重叠?
- 无法在 cmake 检测阶段之外应用变量加载或设置(例如,在 cmake 脚本模式下)。
- 同一个唯一变量不能为不同的操作系统/编译器/配置/架构等保存不同的值。
- 不能将变量附加到由
Find* 或add_subdirectory 等系统函数表示的包(不是范围)术语。
我在 cmake 列表中使用了很长时间的变量,并决定编写自己的解决方案来一次性将它们全部从 cmake 列表中删除。
这个想法是通过 cmake 脚本编写一个独立的解析器,以从一个文件或一组文件加载变量,并定义一组规则以启用以预定义或严格顺序设置的变量,并检查冲突和重叠。
这里列出了几个功能:
-
bool A=ON 等于 bool A=TRUE 等于 bool A=1
-
path B="c:\abc" 在 Windows 上等于 path B="C:\ABC"(显式 path 变量而不是默认的字符串)
-
B_ROOT="c:\abc" 在 Windows 上等于 B_ROOT="C:\ABC"(通过变量名的结尾来检测变量的类型)
-
LIB1:WIN="c:\lib1" 仅在 Windows 中设置,而 LIB1:UNIX="/lib/lib1" 仅在 Unix 中设置(变量特化)。
-
LIB1:WIN=c:\lib1、LIB1:WIN:MSVC:RELEASE=$/{LIB1}\msvc_release - 通过扩展和特化重用变量
这里我不能一概而论,但是您可以以tacklelib库(https://sourceforge.net/p/tacklelib/tacklelib/HEAD/tree/trunk/)为例,自行研究实现。
所描述的配置文件的示例存储在这里:https://sourceforge.net/p/tacklelib/tacklelib/HEAD/tree/trunk/_config/
实施:
https://sourceforge.net/p/tacklelib/tacklelib/HEAD/tree/trunk/cmake/tacklelib/SetVarsFromFiles.cmake
cmake 列表必须通过configure_environment(...) 宏进行初始化:
https://sourceforge.net/p/tacklelib/tacklelib/HEAD/tree/trunk/CMakeLists.txt
阅读自述文件以了解有关 tacklelib 项目的详细信息:
https://sourceforge.net/p/tacklelib/tacklelib/HEAD/tree/trunk/README_EN.txt
整个项目目前处于试验阶段。
附言:
在 cmake 上编写解析器脚本是一项艰巨的任务,请至少阅读以下这些问题:
是否有一些“官方”方法可以对您自己的 CMake 脚本代码进行单元测试?
类似于运行 CMake 的特殊模式?我的目标是“白盒测试”(尽可能)。
我做了自己的“白盒”或测试自己的脚本的方法。我编写了一组模块(它本身依赖于库)在单独的 cmake 进程中运行测试:
https://sourceforge.net/p/tacklelib/tacklelib/HEAD/tree/trunk/cmake/tacklelib/testlib/
我的测试建立在它之上:
https://sourceforge.net/p/tacklelib/tacklelib/HEAD/tree/trunk/cmake_tests/
我们的想法是在测试目录中放入带有测试的目录和文件的层次结构,运行程序代码将按预定义的顺序搜索测试,以在单独的 cmake 进程中执行每个测试:
function(tkl_testlib_enter_dir test_dir)
# Algorithm:
# 1. Iterate not recursively over all `*.include.cmake` files and
# call to `tkl_testlib_include` function on each file, then
# if at least one is iterated then
# exit the algorithm.
# 2. Iterate non recursively over all subdirectories and
# call to the algorithm recursively on each subdirectory, then
# continue.
# 3. Iterate not recursively over all `*.test.cmake` files and
# call to `tkl_testlib_test` function on each file, then
# exit the algorithm.
#
,其中一组函数可以从运行器 cmake 脚本或*.include.cmake 文件中使用:
其中TestLib.cmake 旨在使用测试模块 - *.test.cmake 运行循环创建外部 cmake 进程,并且应从运行程序脚本或包含模块(组其他包含模块 - *.include.cmake 或测试模块 - *.test.cmake):
tkl_testlib_enter_dir test_dir
tkl_testlib_include test_dir test_file_name
tkl_testlib_test test_dir test_file_name
TestModule.cmake 自动包含在您必须放置测试代码的所有 *.test.cmake 模块中。
之后,您只需在 *.test.cmake 模块中使用 tkl_test_assert_true 将测试标记为成功或失败。
此外,您可以在 _scripts 子目录中的运行器脚本中使用过滤器参数来过滤掉测试:
--path_match_filter <[+]regex_include_match_expression> | <-regex_exclude_match_expression>[;...]
--test_case_match_filter <[+]regex_include_match_expression> | <-regex_exclude_match_expression>[;...]
优点:
-
TestModule.cmake 确实通过预定义规则的测试遍历整个目录,您只需要确保正确的层次结构和命名即可对测试进行排序。
- 使用基于每个目录的单独包含文件
*.include.cmake 来排除包含或重新排序目录及其后代中的测试。
-
*.test.cmake 文件的存在是默认运行测试的唯一要求。要专门包含或排除测试,您可以开始使用命令行标志 --path_match_filter ... 和 --test_case_match_filter ...。
缺点:
整个项目目前处于试验阶段。