【问题标题】:Skipping a CTest if the target was not built如果未构建目标,则跳过 CTest
【发布时间】:2019-02-07 04:01:24
【问题描述】:

在 CMake 中,可以使用add_subdirectory(foo EXCLUDE_FROM_ALL)foo 下定义的目标排除在默认构建之外除非其他目标需要它们,如下所示:

add_subdirectory(foo EXCLUDE_FROM_ALL)
add_custom_target(wanted_foo_targets ALL DEPENDS
  bar_tool  # only build bar_tool from foo
)

假设 foo 定义了两个目标,bar_toolfoo_tool,并对每个目标进行测试:

add_test(NAME test_foo_tool COMMAND foo_tool) 
add_test(NAME test_bar_tool COMMAND bar_tool) 

当你构建整个项目时,foo_tool 没有被构建,因为它不是任何东西的依赖,但bar_tool 被构建是因为它是wanted_foo_targets 的依赖。

但是 CTest 仍然注册了 test_foo_tool 工具,现在该工具失败了,因为 foo_tool 不存在。

我可以删除/隐藏/跳过引用未构建目标的测试吗?我知道我可以使测试命令类似于[ -f foo_tool ] && foo_tool,但这会错误地表明测试通过了。

如果我可以从父目录执行此操作,而无需修改 foo 中的测试设置方式,则可以获得奖励积分。就我而言,foo 是第三方提供的项目,我不想在他们编写新测试时维护他们的代码补丁。

【问题讨论】:

    标签: cmake


    【解决方案1】:

    这可以通过结合使用SKIP_RETURN_CODE 测试属性和一个小的测试驱动脚本(您已经考虑使用)来完成。

    在源代码目录中添加一个名为test_driver.sh的测试驱动脚本,内容如下:

    #!/bin/sh
    if [ -x "$1" ] ; then exec "$1" ; else exit 127 ; fi
    

    脚本检查是否存在作为第一个参数传递的测试可执行文件,如果不存在则退出并返回错误代码 127(也称为“找不到命令”)。

    在您的 CMakeLists.txt 中按以下方式添加测试:

    add_test(NAME test_foo_tool COMMAND "${CMAKE_SOURCE_DIR}/test_driver.sh" $<TARGET_FILE:foo_tool>)
    set_tests_properties(test_foo_tool PROPERTIES SKIP_RETURN_CODE 127)
    

    当您在缺少可执行文件foo_tool 的情况下运行测试时,ctest 会将test_foo_tool 报告为跳过的测试,而不是失败的测试。

    $ ctest 
    ...
        Start 1: test_foo_tool
    1/2 Test #1: test_foo_tool ....................***Skipped   0.01 sec
        Start 2: test_bar_tool
    2/2 Test #2: test_bar_tool ....................   Passed    0.01 sec
    
    100% tests passed, 0 tests failed out of 2
    
    Total Test time (real) =   0.03 sec
    
    The following tests did not run:
          1 - test_foo_tool (Skipped)
    

    【讨论】:

    【解决方案2】:

    可以通过设置相关测试的DISABLED 属性来禁用测试。 您还可以通过检查TESTS 属性来获取在子目录中定义的测试列表。

    因此,您应该能够使用get_property 获取该特定目录的所有测试列表,然后禁用所有测试。如果只需要禁用测试的子集,则过滤所有测试的列表,使用list(FILTER) 只筛选需要禁用的测试。这只有在遵循命名约定时才方便。

    很遗憾set_property 只能修改同一目录中的测试属性,不能修改子目录。这意味着需要更新 CMakeLists.txt 文件。

    或者,如果修改 CMakeLists.txt 问题太大,请不要运行这些测试。这可以通过使用ctest -E regex 选项排除这些测试来完成。

    【讨论】:

    • 我想我没有办法在事后得到测试命令,是吗?我不想禁用每个测试,只是那些测试我不链接的部分的测试。
    • add_subdirectory 命令之后尝试使用get_property(foo_tests DIRECTORY foo PROPERTY TESTS)。这应该会为您提供在该目录中使用 add_test 添加的所有测试。至少文档是这么说的。
    • 是的,我明白了,但是假设子目录定义了目标 TgtA 和 TgtB,而我只构建 TgtB。我想获得 TgtB 的测试,但跳过 TgtA 的测试。我认为到目前为止,您的解决方案会禁用 TgtA 和 TgtB 的测试。
    • @rgov 这并不是适用于所有情况的完美解决方案。但是,如问题中所述,如果对 foo 使用 EXCLUDE_ALL ,则不会构建 foo 中的 TgtA 或 TgtB 。所以排除两个目标的测试应该是可以接受的。如果这不是您在问题中的意思,请使用您需要的确切详细信息更新问题,以便您获得足够的答案。
    • 好的,我试着解释更多。不一定因为我使用了EXCLUDE_FROM_ALL而跳过了TgtA和TgtB,因为另一个目标可以依赖于一个,这将强制它被构建。
    猜你喜欢
    • 2018-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-02
    相关资源
    最近更新 更多