CMake добавляет пользовательскую цель в зависимости от всего строящегося проекта

Я хочу добавить тестовую цель, которая зависит от всего успешно строящегося проекта, без повторного указания зависимостей от всех библиотек или исполняемых файлов.

Я бы написал это в Сделать:

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
)

однако это не работает, поскольку нет цели all.

Is есть способ уточнить это? Или есть переменная, которая расширяется до всех целей, которые я пытаюсь построить?

3 ответов


начиная с версии 2.8 CMake не предоставляет переменную, которая содержит список всех целей. Лучшее, что вы можете сделать, это переопределить встроенные команды add_library и add_executable с пользовательскими макросами, которые вызывают встроенные и отслеживают все определенные цели в переменной.

вы даже можете использовать те же имена для пользовательских макросов. Таким образом, вам не нужно вносить изменения во все существующие add_library и add_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 может ссылаться только на существующие файлы или файлы, созданные с помощью add_custom_command(...) в том же каталоге. Чтобы добавить целевую зависимость, используйте .


У меня недостаточно репутации, чтобы прокомментировать ответ Сакры...

одна проблема, которую я вижу с этим решением, заключается в том, что если вы используете любой подкаталог, изменения, которые вы делаете с переменной _allTargets внутри подкаталога, не будут распространяться на родительскую область.

глубже список(добавить ...) нельзя использовать в этом случае:

подобно команде SET, команда LIST создает новую переменную значения в текущей области, даже если сам список на самом деле определяется в родительской области. Для распространения результатов этих операции вверх, использовать SET с PARENT_SCOPE, SET с кэшем Внутренний, или некоторые другие средства распространения значений.

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

если PARENT_SCOPE присутствует, переменная будет установлена в области выше текущего объема. каждый новый каталог или функция создает новая область. Эта команда установит значение переменной в родительский каталог или вызывающая функция (в зависимости от того, что применимо к дело под рукой).

(примечание для себя: макрос не функция)

Я не вижу общего решения (например, независимого от использования add_subdirectory) при использовании PARENT_SCOPE. Однако здесь, похоже,есть решение с использованием внутреннего кэша.

цитирование: 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)

Вы можете использовать CTest:

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

Cmake будет генерировать Makefile с новой целью тест Смотрите также: документация add_test команда.

но вам нужно скомпилировать свой проект перед запуском тестов:

make
make test

кроме того, вы можете использовать элемент экспериментальные, ночной или постоянный. Эти цели будут компилировать проект и запускать все тесты, но они также пытаются отправить результаты теста (вы можете настроить его с помощью CTestConfig.с CMake).