Как мне справиться с проблемами глобальных переменных и областей видимости переменных? Внедрить глобальные переменные в тест, загрузив кеш проекта, настроив тестовый файл 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
Прочтите файл readme, чтобы получить подробную информацию о проекте 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-скрипта runner, так и из *.include.cmake
файла:
Где TestLib.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
Где TestModule.cmake
автоматически включается во все *.test.cmake
модули, в которые вы должны поместить свой тестовый код.
После этого вы просто используете tkl_test_assert_true
внутри модуля *.test.cmake
, чтобы пометить тест как успешный или неудачный.
Кроме того, вы можете использовать параметры фильтра в скриптах runner в подкаталоге _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 ...
.
Минусы:
- Практически все тестовые функции реализованы с помощью ключевого слова
function
, что немного снижает функциональность некоторых функций. Например, tkl_test_assert_true
может только отметить, что тест завершился успешно или не прошел. Чтобы явно прервать тест, нужно выполнить переход через вызов макроса tkl_return_if_failed
.
- Все файлы в каталоге с тестами должны иметь суффикс,
.test.cmake
- для теста, а .include.cmake
- для команд включения. От этого зависит вся встроенная логика поиска.
- Вы должны написать собственный бегунок для вызова сценария
RunTestLib.cmake
. Пример run all
в оболочке unix можно найти здесь: https://sourceforge.net/p/tacklelib/tacklelib/HEAD/tree/trunk/cmake_tests/_scripts/test_all.sh
В настоящее время весь проект является экспериментальным.
person
Andry
schedule
06.05.2019