【问题标题】:Global custom target in CMakeCMake 中的全局自定义目标
【发布时间】:2015-04-05 11:49:32
【问题描述】:

我想用 CMake 编写一个小单元测试系统,我可以轻松地复制和粘贴到我的所有项目中,所以我想出了这个:

include(CMakeParseArguments)
set(UNIT_TEST "unit_tests")
add_custom_target(${UNIT_TEST} ALL VERBATIM)

function(add_unit_test dependency)
    cmake_parse_arguments(UT_ "" "NAME" "" ${ARGN})
    if(NOT ${UT_NAME})
        set(${UT_NAME} ${ARG0})
    endif()

    add_test(${ARGN})
    add_dependencies(${UNIT_TEST} ${dependency})
    add_custom_command(TARGET ${UNIT_TEST}
                   COMMENT "Run tests"
                   POST_BUILD COMMAND ctest
                   ARGS -R ${UT_NAME} --output-on-failures
                   WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
                   VERBATIM)
endfunction(add_unit_test)

我希望它能够像这样正常工作并运行我将通过调用 add_unit_test(dep ...) 来添加到我的项目中的所有单元测试,并在之前编译依赖项,然后使用与 add_test(...) 相同的参数。实际上会出现此错误:

CMake Warning (dev) at cmake/testing.cmake:13 (add_custom_command):
  Policy CMP0040 is not set: The target in the TARGET signature of
  add_custom_command() must exist.  Run "cmake --help-policy CMP0040" for
  policy details.  Use the cmake_policy command to set the policy and
  suppress this warning.

  The target name "unit_tests" is unknown in this context.
Call Stack (most recent call first):
  source/test/CMakeLists.txt:10 (add_unit_test)
This warning is for project developers.  Use -Wno-dev to suppress it.

为什么此时目标是未知的? include(cmake/testing.cmake) 是我在项目构建脚本中在cmake_minimum_required 之后调用的第一件事,所以不可能是因为尚未调用add_custom_target(${UNIT_TEST} ALL VERBATIM)

有没有办法可以将自定义命令添加到 UNIT_TEST 目标?

【问题讨论】:

    标签: unit-testing cmake target


    【解决方案1】:

    刚刚遇到您的问题并试图重现您的问题。

    我的第一个建议是:如果您调用enable_testing(),您将直接获得由 CMake 生成的“运行测试”目标。见CMake: Testing with CTest

    构建项目后,您可以通过

    执行所有测试
    make test
    

    使用 Makefile 生成器,或通过重建 RUN_TESTS 目标 你骑。这在内部运行 CTest 以实际执行测试; 你也可以执行

    ctest
    

    在您构建的二进制目录中。

    调试给定的代码

    如果我将有效目标命名为add_unit_test() 的第一个参数,我不会收到CMP0040 错误。因此,只需再次检查您提供的目标是否有效。

    但是您的脚本中有一些错误。这是一个工作版本:

    include(CMakeParseArguments)
    
    enable_testing()
    
    set(UNIT_TEST "unit_tests")
    add_custom_target(${UNIT_TEST} ALL)
    
    function(add_unit_test dependency)
        cmake_parse_arguments(UT "" "NAME" "COMMAND" ${ARGN} )
        if("${UT_NAME}" STREQUAL "")
            set(${UT_NAME} "${ARGV1}")
        endif()
        add_test(${ARGN})
        add_dependencies(${UNIT_TEST} ${dependency})
        add_custom_command(TARGET ${UNIT_TEST}
                       COMMENT "Run tests"
                       POST_BUILD COMMAND ctest
                       ARGS -C $<CONFIGURATION> -R "^${UT_NAME}$" --output-on-failures)
    endfunction(add_unit_test)
    
    • 已添加enable_testing()
    • 删除了cmake_parse_arguments(UT ...)UT 的尾随_
    • 比较空字符串和STREQUAL ""
    • V 添加到ARGV1 并用于第二个参数(索引0 是dependency
    • 删除不需要VERBATIM
    • 添加了需要的-C $&lt;CONFIGURATION&gt;参数(见How to run ctest after building my project with cmake
    • 将 RegEx 更改为 "^${UT_NAME}$" 以实现完全匹配的名称

    将上面的代码移动到一个名为UnitTest.cmake的文件中我已经成功测试了以下主要CMakeLists.txt

    cmake_minimum_required(VERSION 2.8)
    project(Example CXX)
    
    include(${CMAKE_CURRENT_LIST_DIR}/UnitTest.cmake)
    
    file(WRITE foo.cc "#include <windows.h>\nint main() {\nreturn 0;\n}")
    
    add_executable(MyTest foo.cc)
    add_unit_test(MyTest NAME SomeTest COMMAND $<TARGET_FILE:MyTest>)
    
    add_executable(MyTest2 foo.cc)
    add_unit_test(MyTest2 NAME SomeTest2 COMMAND $<TARGET_FILE:MyTest2>)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多