“ctest”与“make check”:错误的构建时间与破坏的选项传递

时间:2016-06-04 06:24:13

标签: cmake ctest

要在CMake下注册测试,我们需要

enable_testing()

include(CTest)

然后针对每个单一测试(名称fooTest,可执行文件foo

add_executable(foo <foo_sources>)
add_test(fooTest foo)

然后可以使用命令ctest运行测试。

此外,我们可以使用命令make check运行测试,只要我们添加一次

add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND})

并且对于每个测试,我们通过关键字EXCLUDE_FROM_ALL和命令add_dependencies扩展上述内容:

add_executable(foo EXCLUDE_FROM_ALL <foo_sources>)
add_test(fooTest foo)
add_dependencies(check foo)

理想情况下,这会使make check成为ctest的别名。至少有两个原因并非如此:

(1)make check存在缺陷,因为它没有将选项传递给ctest [2]。特别是,ctest -j4将并行运行4个测试,而make -j4 check将在目标check上的一个线程中工作,其他三个线程将保持空闲状态。

(2)ctest有缺陷[3,4],因为所有测试都是在all目标下构建的,即与主应用程序一起构建。在某些情况下,这可能是期望的行为,但在其他情况下,应该可以推迟构建,直到要运行测试。

这是否正确总结了当前的事态?

有没有办法(吃蛋糕并拥有它)?

[1] https://cmake.org/Wiki/CMakeEmulateMakeCheck [2] http://comments.gmane.org/gmane.comp.programming.tools.cmake.user/47300 [3] CMake & CTest : make test doesn't build tests [4] http://public.kitware.com/Bug/view.php?id=8774

2 个答案:

答案 0 :(得分:3)

首先,我要注意ctestmake test只是简单的命令行工具,用于简单的测试任务。如果您需要一个用于严格测试的工具,请使用CDash,Buildbot,Jenkins或其他任何工具。

关于CTest的缺陷:有意识的是,对CTest的调用不构建测试。在几种情况下这是一个坏主意:

  • 编译测试可以占用更多资源,然后运行测试本身。对于内存消耗,对硬盘的读/写或编译时间,这可能是正确的。因此,并行编译和链接可能会很糟糕,但并行执行测试可能会有所帮助。
  • 如何处理编译或链接失败?报告失败了吗?报告是不编译的?继续编译其他测试或立即中止?

Autotools以您想要的方式做到了,人们已经习惯了。但为什么它应该是一个单位呢?为什么不用两个命令?混合两项任务的好处是什么,使有特殊需要的项目更加困难?

我得出结论,创建一个目标build-tests或类似的目标,并遵循CMake开发人员的决定来解耦构建测试和执行测试。然后我可以决定是否需要并行构建,如何处理编译失败(例如,将-k传递给make)等等。
唯一的缺点是,此目标仅存在于顶级目录中,不能在子目录中使用 要获得CMake内置的这样一个目标,这将是一个很好的功能请求。 Ranting on SO并不好。

答案 1 :(得分:1)

CTest根本没有缺陷,但你使用CMake和CTest的方式似乎有缺陷&#34;。命令行界面(CLI)工具ctest的调用通常与CMake构建目标的调用无关(目标test除外)。

在我看来,CMake Wiki中描述的自定义check目标解决方案应该,因为它会更改CMake的默认行为,并且不可配置。

相反,应使用以下使用内置选项BUILD_TESTING的方法:

include(CTest)
if(BUILD_TESTING)
  find_package(GTest MODULE REQUIRED)
  add_executable(example_test example_test.cpp)
  target_link_libraries(
    example_test
    PRIVATE
      GTest::GTest
      GTest::Main
  )
  add_test(NAME example_test COMMAND example_test)
endif()

include(CTest)option BUILD_TESTING中定义,它允许控制是否构建项目的所有测试。

来自official documentation

的引用
  

只有在调用enable_testing()命令时,CMake才会生成测试。当CTest选项为BUILD_TESTING时,ON模块会自动调用该命令。

以上内容可在CLI上使用,如下所示:

  1. 创建测试(默认):

    cmake -Hexample-testing -B_builds/example-testing/release -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=Release
    cmake --build _builds/example-testing/release --config Release
    

    在这种情况下,命令cd _builds/example-testing/releasectest / cmake --build . --target test构建运行测试。

  2. 不要创建测试:

    cmake -Hexample-testing -B_builds/example-testing/release-no-tests -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=OFF
    cmake --build _builds/example-testing/release-no-tests --config Release
    

    在这种情况下,命令cd _builds/example-testing/release-no-testsctest不运行任何测试,因为没有构建测试。 命令cmake --build . --target test 失败,因为在CMake的配置阶段尚未创建。

  3. 我们只是在这里搔痒。请参阅ctest --help,例如有很多--build-<...>选项可以更好地控制测试/构建,但我没有任何经验。

    我强烈建议您阅读以下内容:

    如果您确实想要启用测试的构建,但是通过默认情况下未调用的单独目标并且不是通过CTest运行测试,而是直接执行以下操作:

    include(CTest)
    if(BUILD_TESTING)
      find_package(GTest MODULE REQUIRED)
      option(
        BUILD_TESTING_EXCLUDE_FROM_ALL
        "Do not build the testing tree together with the default build target."
        OFF
      )
    
      if(BUILD_TESTING_EXCLUDE_FROM_ALL)
        set(add_executable_args_for_test EXCLUDE_FROM_ALL)
      endif()
    
      # The "build_test" target is used to build all test executables.
      add_custom_target(
        build_test
        # Workaround for printing the COMMENT, it does not work without a NOOP
        # COMMAND.
        COMMAND ${CMAKE_COMMAND} -E echo
        COMMENT "Building tests..."
        VERBATIM
      )
      add_executable(example_test ${add_executable_args_for_test} example_test.cpp)
      target_link_libraries(
        example_test
        PRIVATE
          GTest::GTest
          GTest::Main
      )
      add_test(NAME example_test COMMAND example_test)
      add_dependencies(build_test example_test)
    
      # The "check" target is used to build AND run all test executables.
      add_custom_target(
        check
        # Either invoke the test(s) indirectly via "CTest" (commented) or directly.
    #   COMMAND ${CMAKE_CTEST_COMMAND}
        COMMAND example_test
        COMMENT "Building and running test..."
        VERBATIM
      )
      # Alternative to the COMMAND in the add_custom_target. Leads to the same
      # behavior as calling "CTest" directly.
    #  add_custom_command(
    #    TARGET check
    #    COMMAND ${CMAKE_COMMAND} ARGS --build ${CMAKE_BINARY_DIR} --target test
    #    VERBATIM
    #  )
       add_dependencies(check build_test)
    endif()
    
    • 请注意,上述代码不会调用CTest或目标test来运行测试,而是直接测试。
    • 请阅读使用CTest的替代方法的评论和评论代码,这些方法与问题中描述的方法类似。
    • 很容易增强上面的代码以支持多个测试可执行文件。

    恕我直言,Kitware应删除整个CMake Wiki ,因为Wiki几乎只包含CMake版本的过时信息&lt; 3.0。其中的大多数信息都不能被视为 Modern CMake