CMake 中的全局自定义目标
Global custom target in CMake
我想用 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 目标?
刚刚遇到您的问题并尝试重现您的问题。
我的第一个建议是:如果你调用 enable_testing()
你直接得到一个由 CMake 生成的 "Run Tests" 目标。见 CMake: Testing with CTest:
Once you have built the project, you can execute all tests via
make test
with Makefile generators, or by rebuilding the RUN_TESTS target in
your IDE. Internally this runs CTest to actually perform the testing;
you could just as well execute
ctest
in the binary directory of your build.
正在调试您给定的代码
如果我将有效目标命名为您的 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 ""
- 向
ARGV1
添加了一个 V
并用于第二个参数(索引 0 是 dependency
)
- 删除不需要
VERBATIM
- 添加了所需的
-C $<CONFIGURATION>
参数(参见 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>)
我想用 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 目标?
刚刚遇到您的问题并尝试重现您的问题。
我的第一个建议是:如果你调用 enable_testing()
你直接得到一个由 CMake 生成的 "Run Tests" 目标。见 CMake: Testing with CTest:
Once you have built the project, you can execute all tests via
make test
with Makefile generators, or by rebuilding the RUN_TESTS target in your IDE. Internally this runs CTest to actually perform the testing; you could just as well execute
ctest
in the binary directory of your build.
正在调试您给定的代码
如果我将有效目标命名为您的 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 ...)
中 - 比较空字符串与
STREQUAL ""
- 向
ARGV1
添加了一个V
并用于第二个参数(索引 0 是dependency
) - 删除不需要
VERBATIM
- 添加了所需的
-C $<CONFIGURATION>
参数(参见 How to run ctest after building my project with cmake) - 将 RegEx 更改为
"^${UT_NAME}$"
以实现精确名称匹配
UT
的尾随 _
将上面的代码移动到一个名为 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>)