我目前正在将当前的构建环境从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
中。
答案 0 :(得分:-1)
今天早上,我遇到了同样的问题,并且发现了(肮脏的?)解决方法。它不起作用的原因有些复杂,但是解决方法非常简单。
gtest_discover_tests(gTestExe PROPERTIES ENVIRONMENT "PATH=${NEWPATH}")
不起作用是因为PATH内容用分号分隔,因此被CMake视为列表值。
如果您查看GoogleTestAddTests.cmake
文件(位于C:\Program Files\CMake\share\cmake-3.17\Modules
中),它将使用foreach处理PROPERTIES
参数。
在脚本PROPERTIES
中,此时的ENVIRONMENT;PATH=mypath;mypath2
值对于CMake如下所示,并将mypath2
视为第三个参数,而不是PATH环境变量的值。 / p>
CMake然后将生成以下行:
set_tests_properties( mytest PROPERTIES ENVIRONMENT PATH=mypath mypath2)
转义;
无效,因为列表在add_custom_command()
中的GoogleTest.cmake
中自动扩展了(cmake 3.17.1中的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};$ENV{PATH}]==]"
)
应该工作。