【问题标题】:With CMake, how can I set environment properties on the gtest_discover_tests --gtest_list_tests call?使用 CMake,如何在 gtest_discover_tests --gtest_list_tests 调用上设置环境属性?
【发布时间】:2019-12-23 18:54:47
【问题描述】:

我目前正在将我们当前的构建环境从 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 中。

【问题讨论】:

  • 测试本身是否因为缺少 DLL 依赖关系而无法构建?如果是这样的话,你见过这个answer吗?
  • @squareskittles 我编辑以试图解决我看到的问题。测试正在构建中,失败的是测试发现步骤。虽然,我相信该链接中描述的一些解决方案可以工作(例如复制 dll)。
  • 好的,如果您找到适合您的解决方案或解决方法,请发布答案。

标签: cmake googletest


【解决方案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 值在脚本中此时对于 CMake 如下所示:ENVIRONMENT;PATH=mypath;mypath2 并将 mypath2 视为第三个参数,而不是 PATH 环境变量的值。

CMake 然后将生成以下行:

set_tests_properties( mytest PROPERTIES ENVIRONMENT PATH=mypath mypath2)

转义 ; 将不起作用,因为该列表会自动在 GoogleTest.cmake 中的 add_custom_command() 中扩展(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 不在我们自己的括号参数上使用括号参数。

首先在您自己的存储库(位于C:\Program Files\CMake\share\cmake-3.17\Modules)中制作GoogleTestAddTests.cmake 文件的本地副本。

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}]==]"
 )

应该可以。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-26
    相关资源
    最近更新 更多