使用 CMake,如何在 gtest_discover_tests --gtest_list_tests 调用上设置环境属性?

tra*_*vis 7 cmake googletest

我目前正在将我们当前的构建环境从 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}")
Run Code Online (Sandbox Code Playgroud)

这有效:

gtest_add_tests(TARGET gTestExe TEST_LIST allTests)
set_tests_properties(${all_tests} PROPERTIES ENVIRONMENT "PATH=${NEWPATH}")
Run Code Online (Sandbox Code Playgroud)

但这不会:

#set_target_properties(gTestExe  PROPERTIES ENVIRONMENT "PATH=${NEWPATH}")
#set_property(DIRECTORY PROPERTY ENVIRONMENT "PATH=${NEWPATH}")
gtest_discover_tests(gTestExe  PROPERTIES ENVIRONMENT "PATH=${NEWPATH}")
Run Code Online (Sandbox Code Playgroud)

编辑:使用gtest_add_tests. 问题是在gtest_discover_tests注册的后期构建步骤中发现测试的调用失败,因为所需的库不在PATH.

Bla*_*uze -1

今天早上我遇到了同样的问题,我找到了一个(肮脏的?)解决方法。不起作用的原因有点复杂,但解决方法很简单。

为什么它不起作用

gtest_discover_tests(gTestExe  PROPERTIES ENVIRONMENT "PATH=${NEWPATH}")
Run Code Online (Sandbox Code Playgroud)

不起作用是因为 PATH 内容由分号分隔,因此被 CMake 视为列表值。

如果您查看该GoogleTestAddTests.cmake文件(位于C:\Program Files\CMake\share\cmake-3.17\Modules),它会使用foreachPROPERTIES处理参数。

PROPERTIES对于 CMake 在脚本中的此时,该值看起来像这样:ENVIRONMENT;PATH=mypath;mypath2并且将被视为mypath2第三个参数,而不是 PATH 环境变量的值。

然后 CMake 将生成以下行:

set_tests_properties( mytest PROPERTIES ENVIRONMENT PATH=mypath mypath2)
Run Code Online (Sandbox Code Playgroud)

转义将;不起作用,因为列表会自动扩展 in add_custom_command()( GoogleTest.cmake cmake 3.17.1 中的 l. 420),忽略任何形式的转义。

为了防止 cmake foreach 将路径中的每个值视为列表,您可以使用括号参数,例如:

gtest_discover_tests(gTestExe PROPERTIES ENVIRONMENT "[==[PATH=${NEWPATH}]==]")
Run Code Online (Sandbox Code Playgroud)

然后,cmake foreach 会将您的参数视为一个实体。不幸的是,CMake 还会在生成的代码中放置一个括号,因为它包含[ =可能还有空格:

# This line 
if(_arg MATCHES "[^-./:a-zA-Z0-9_]")
  set(_args "${_args} [==[${_arg}]==]")
else()
  set(_args "${_args} ${_arg}")
endif()  
Run Code Online (Sandbox Code Playgroud)

生成以下脚本:

set_tests_properties( mytest PROPERTIES ENVIRONMENT [==[ [==[PATH=mypath;mypath2] ]==])
Run Code Online (Sandbox Code Playgroud)

当执行测试时,cmake 将尝试读取仅删除第一个括号参数的值,因为它们不嵌套。

可能的解决方法

因此,要做到这一点,我们需要 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()
Run Code Online (Sandbox Code Playgroud)

这将使 cmake 不在我们的括号列表上使用括号列表,并自动转义;asset_tests_properties并将 as 视为;列表。

最后,我们需要 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
)
Run Code Online (Sandbox Code Playgroud)

注意:在我的示例中,GoogleTestAddTests.cmake 位于处理 cmake 文件旁边。

然后一个简单的调用

 gtest_discover_tests(my_target
   PROPERTIES ENVIRONMENT "[==[PATH=${my_path};$ENV{PATH}]==]"
 )
Run Code Online (Sandbox Code Playgroud)

应该管用。