根据正在构建的整个项目,CMake add_custom_target

时间:2011-06-16 12:52:08

标签: cmake

我想添加一个测试目标,该目标依赖于正在成功构建的整个项目,而无需重新指定所有库或可执行文件的依赖项。

我会在make中写这个:

all: foo bar

foo: ...
bar: ...

test: all
    test.sh

test.sh隐式使用foo和bar,并希望它们是最新的。

我希望在cmake中指定它。

add_library(foo ...)
add_executable(bar ...)

add_custom_target(test test.sh
              DEPENDS all
)

然而,这不起作用,因为没有所有目标。

有没有办法指定这个?或者是否有一个变量扩展到我想要构建的所有目标?

3 个答案:

答案 0 :(得分:9)

从版本2.8开始,CMake不提供包含所有目标列表的变量。您可以做的最好的事情是使用调用内置宏的自定义宏覆盖内置命令add_libraryadd_executable,并跟踪变量中所有已定义的目标。

您甚至可以为自定义宏使用相同的名称。这样您就不必对所有现有的add_libraryadd_executable来电进行更改。如果您覆盖其中任何一个,原始内置命令都以下划线为前缀:

set (_allTargets "")

macro(add_library _target)
    _add_library (${_target} ${ARGN})
    list (APPEND _allTargets ${_target})
endmacro()

macro(add_executable _target)
    _add_executable (${_target} ${ARGN})
    list (APPEND _allTargets ${_target})
endmacro()

add_library(liba STATIC liba.cpp)
add_executable(main liba main.cpp)

add_custom_target(test "${CMAKE_CURRENT_SOURCE_DIR}/test.sh")

add_dependencies(test ${_allTargets})

另请注意,您无法使用DEPENDS选项将目标依赖项添加到自定义目标。 DEPENDS只能引用同一目录中使用add_custom_command(...)生成的现有文件或文件。要添加目标依赖项,请改用add_dependencies命令。

答案 1 :(得分:4)

我没有足够的声誉评论Sakra的答案......

我在该解决方案中看到的一个问题是,如果使用任何子目录,则对子目录中的变量_allTargets所做的更改将不会传播到父作用域。

在这种情况下,不能再使用list(append ...)

  

与SET命令类似,LIST命令创建新变量   当前范围中的值,即使列表本身实际上也是如此   在父范围中定义。传播这些结果   操作向上,使用SET与PARENT_SCOPE,SET与CACHE   内部,或其他一些价值传播方式。

http://www.cmake.org/cmake/help/v2.8.11/cmake.html#command:set

  

如果存在PARENT_SCOPE,则将在范围中设置变量   超出当前范围。 每个新目录或函数都会创建一个   新范围。此命令将变量的值设置为   父目录或调用函数(以适用者为准)   手头的情况)。

(请注意我自己:宏不是一个函数)

使用PARENT_SCOPE时,我没有看到一般解决方案(例如,独立于使用add_subdirectory)。但是,这里似乎有一个使用CACHE INTERNAL的解决方案。

引自:http://www.cmake.org/pipermail/cmake/2007-November/018109.html

# A macro for passing lists between different directories
# through an internal cache variable.
MACRO (APPEND_INTERNAL_LIST  LIST_NAME  VALUE)

   # If the list in not in the cache, create it.
   IF (${LIST_NAME})
      SET (${LIST_NAME} "${${LIST_NAME}};${VALUE}" CACHE INTERNAL "Internal
variable")
   ELSE (${LIST_NAME})
      SET (${LIST_NAME} "${VALUE}" CACHE INTERNAL "Internal variable")
   ENDIF (${LIST_NAME})

ENDMACRO (APPEND_INTERNAL_LIST)

# A macro for passing lists between different directories
# through an internal cache variable.
# This function empties the variable (usually because of older runs)
MACRO (INITIALIZE_INTERNAL_LIST  LIST_NAME)
   SET (${LIST_NAME} "" CACHE INTERNAL "Internal variable")
ENDMACRO (INITIALIZE_INTERNAL_LIST)

答案 2 :(得分:0)

您可以使用CTest:

include(CTest)
if (BUILD_TESTING)
    add_test(MyTestName test.sh param1 param2)
endif(BUILD_TESTING)

Cmake将使用新目标测试生成Makefile,另请参阅:Documentation for add_test command

但是你需要在运行测试之前编译你的项目:

make
make test

此外,您可以使用目标实验每晚连续。这些目标将编译项目并运行所有测试,但他们也尝试提交测试结果(您可以使用 CTestConfig.cmake 对其进行配置。)