我目前正在将当前的构建环境从MSBuild迁移到CMake。我有一种情况,我需要更新PATH
变量以便运行单元测试可执行文件。对于gtest_add_tests
,这不是问题,因为它使用源识别测试。但是,使用gtest_discover_tests
标志执行单元测试的--gtest_list_tests
无法识别任何测试,因为在构建过程中遇到了STATUS_DLL_NOT_FOUND
错误。
例如:
add_executable(gTestExe ...)
target_include_directories(gTestExe ...)
target_compile_definitions(gTestExe ...)
target_link_libraries(gTestExe ...)
set (NEWPATH "/path/to/bin;$ENV{PATH}")
STRING(REPLACE ";" "\\;" NEWPATH "${NEWPATH}")
此作品:
gtest_add_tests(TARGET gTestExe TEST_LIST allTests)
set_tests_properties(${all_tests} PROPERTIES ENVIRONMENT "PATH=${NEWPATH}")
但这不是:
#set_target_properties(gTestExe PROPERTIES ENVIRONMENT "PATH=${NEWPATH}")
#set_property(DIRECTORY PROPERTY ENVIRONMENT "PATH=${NEWPATH}")
gtest_discover_tests(gTestExe PROPERTIES ENVIRONMENT "PATH=${NEWPATH}")
编辑:使用gtest_add_tests
添加时,测试本身可以工作。问题是在gtest_discover_tests
注册的构建后步骤期间,发现测试的调用失败,因为所需的库不在PATH
中。
今天早上我遇到了同样的问题,我发现了一个(肮脏的?)解决方法。它不起作用的原因有点复杂,但是解决方法非常简单。
gtest_discover_tests(gTestExe PROPERTIES ENVIRONMENT "PATH=${NEWPATH}")
将不起作用是因为PATH内容之间用分号分隔,因此被CMake视为列表值。
[如果您查看GoogleTestAddTests.cmake
文件(位于C:\Program Files\CMake\share\cmake-3.17\Modules
中),它将使用PROPERTIES
处理foreach参数。
脚本中[CM0]的PROPERTIES
值现在看起来像这样:ENVIRONMENT;PATH=mypath;mypath2
,并将mypath2
视为第三个参数,而不是PATH环境变量的值。
CMake然后将生成以下行:
set_tests_properties( mytest PROPERTIES ENVIRONMENT PATH=mypath mypath2)
转义;
将不起作用,因为列表在add_custom_command()
中的GoogleTest.cmake
中自动扩展了((cmake 3.17.1中的l。420)忽略任何转义形式。
为了防止cmake foreach将路径中的每个值都视为列表,您可以使用bracket argument像:
gtest_discover_tests(gTestExe PROPERTIES ENVIRONMENT "[==[PATH=${NEWPATH}]==]")
cmake foreach将把您的论点视为一个实体。不幸的是,CMake还会在生成的代码中放置一个括号,因为它包含[
=
以及空格:
# This line
if(_arg MATCHES "[^-./:a-zA-Z0-9_]")
set(_args "${_args} [==[${_arg}]==]")
else()
set(_args "${_args} ${_arg}")
endif()
产生以下生成的脚本:
set_tests_properties( mytest PROPERTIES ENVIRONMENT [==[ [==[PATH=mypath;mypath2] ]==])
并且在执行测试时,cmake将尝试读取值,仅删除第一个bracket argument,因为它们不嵌套。
因此,我们需要CMake不要在我们自己的方括号参数上使用方括号参数。
首先在您自己的存储库(位于GoogleTestAddTests.cmake
中)制作C:\Program Files\CMake\share\cmake-3.17\Modules
文件的本地副本。
在GoogleTestAddTests.cmake
的本地副本的开头(l。12)以此替换函数add_command
:
function(add_command NAME)
set(_args "")
foreach(_arg ${ARGN})
# Patch : allow us to pass a bracket arguments and escape the containing list.
if (_arg MATCHES "^\\[==\\[.*\\]==\\]$")
string(REPLACE ";" "\;" _arg "${_arg}")
set(_args "${_args} ${_arg}")
# end of patch
elseif(_arg MATCHES "[^-./:a-zA-Z0-9_]")
set(_args "${_args} [==[${_arg}]==]")
else()
set(_args "${_args} ${_arg}")
endif()
endforeach()
set(script "${script}${NAME}(${_args})\n" PARENT_SCOPE)
endfunction()
[这将使cmake不在括号列表中使用括号列表,并自动将;
转义为set_tests_properties
,也将;
视为列表。
最后,我们需要CMake才能使用自定义GoogleTestAddTests.cmake
,而不是CMake中的那个。
在调用include(GoogleTest)
之后,将变量_GOOGLETEST_DISCOVER_TESTS_SCRIPT
设置为本地GoogleTestAddTests.cmake
的路径:
# Need google test
include(GoogleTest)
# Use our own version of GoogleTestAddTests.cmake
set(_GOOGLETEST_DISCOVER_TESTS_SCRIPT
${CMAKE_CURRENT_LIST_DIR}/GoogleTestAddTests.cmake
)
注意:在我的示例中,GoogleTestAddTests.cmake就在处理cmake文件的旁边。
然后简单调用
gtest_discover_tests(my_target
PROPERTIES ENVIRONMENT "[==[PATH=${my_path};\%PATH\%]==]"
)
应该工作。