开发者

CMake add_custom_target depending on whole project being built

I want to add a test target that is dependant on the whole of a project being built successfully, without re-specifying dependencies on all the libraries or executables.

I would write this in make as:

all: foo bar

foo: ...
bar: ...

test: all
    test.sh

test.sh implicitly uses foo and bar and wants them to be up to date.

This is how I would expect to specify this in cmake.

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

add_custom_target(test test.sh
              DEPENDS all
)

However this does not work as there is no all target.

Is there a way to specify this? Or is there a variable that expands to al开发者_StackOverflowl the targets I am trying to build?


As of version 2.8 CMake does not provide a variable that holds a list of all targets. The best you can do is to override the built-in commands add_library and add_executable with custom macros that call the built-in ones and keep track of all defined targets in a variable.

You can even use the same names for your custom macros. That way you do not have to make changes to all the existing add_library and add_executable calls. The original built-in commands are prefixed with an underscore if you override any of them:

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})

Also note that you cannot add a target dependency to a custom target with the DEPENDS option. DEPENDS may only reference existing files or files generated with add_custom_command(...) in the same directory. To add a target dependency use the add_dependencies command instead.


I have not enough reputation to comment on Sakra answer...

One problem I see with that solution is that if you use any subdirectory the changes you do to the variable _allTargets inside the subdirectory will not be propagated to the parent scope.

Digging more, list(append ...) cannot be used in this case:

Similar to the SET command, the LIST command creates new variable values in the current scope, even if the list itself is actually defined in a parent scope. To propagate the results of these operations upwards, use SET with PARENT_SCOPE, SET with CACHE INTERNAL, or some other means of value propagation.

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

If PARENT_SCOPE is present, the variable will be set in the scope above the current scope. Each new directory or function creates a new scope. This command will set the value of a variable into the parent directory or calling function (whichever is applicable to the case at hand).

(note for myself: a macro is not a function)

I don't see a general solution (e.g. independent from using add_subdirectory) when using PARENT_SCOPE. However, here there seem to be a solution using CACHE INTERNAL.

Quoting from: 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)


You may use CTest:

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

Cmake will generate Makefile with new target test, see also: Documentation for add_test command.

But you need to compile your project, before running tests:

make
make test

Also, you can use target Experimental, Nightly, or Continuous. These targets will compile project and run all tests, but they also tries to submit test results (you may configure it with CTestConfig.cmake).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜