如何处理全局变量和变量范围问题?通过加载项目的缓存、配置测试 CMake 文件或通过 -D 命令行选项将其推送到测试中,将全局变量注入测试?
一般来说,所有当前存在的方法(通过缓存、通过环境变量和通过 -D 命令行)在一种或另一种情况下都是一个糟糕的选择,因为它涉及不可预测的行为。
这是我能回忆起的最少问题清单:
- 哪一个变量可以在何时与另一个变量相交/重叠?
- 变量 load 或 set 不能应用到 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
作为一项强制性要求,必须通过configure_environment(...)
宏初始化 cmake 列表:
https ://sourceforge.net/p/tacklelib/tacklelib/HEAD/tree/trunk/CMakeLists.txt
阅读自述文件以了解tacklelib
项目的详细信息:
https ://sourceforge.net/p/tacklelib/tacklelib/HEAD/tree/trunk/README_EN.txt
整个项目目前处于试验阶段。
PS:在 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
文件中使用:
WhereTestLib.cmake
旨在使用测试模块在创建外部 cmake 进程时运行循环 -*.test.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
whereTestModule.cmake
自动包含在*.test.cmake
您必须放置测试代码的所有模块中。
之后,您只需在模块tkl_test_assert_true
内部使用*.test.cmake
将测试标记为成功或失败。
_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 ...
.
缺点:
整个项目目前处于试验阶段。