CMake объявляет зависимость функции от ExternalProject_Add

TLDR:

Моя проблема в том, что CMake начинает выполнять эту функцию перед загрузкой репозитория. Я хотел бы объявить зависимость для этой функции от ExternalProject_Add, чтобы CMake понимал, что он должен загрузить, построить и затем запустить функцию.

Контекст:

У меня есть модуль cmake SomeModule.cmake который должен добавить flatbuffers как внешний проект из своего репозитория и собрать его. Сборка создаст исполняемый файл компилятора flatbuffers, который я собираюсь использовать в some/directory/CMakeLists.txt файл для генерации заголовочных файлов C++ из схемы flatbuffers. Так что в том же модуле CMake, который я использую ExternalProject_AddЯ объявил функцию CMake, которая генерирует заголовочные файлы из заданного набора файлов схемы и где-то в some/directory/CMakeLists.txt Я называю эту функцию.

Моя проблема в том, что CMake начинает выполнять эту функцию перед загрузкой репозитория. Я хотел бы объявить зависимость для этой функции от ExternalProject_Add, чтобы CMake понимал, что он должен загрузить, построить и затем запустить функцию.

Хватит разговоров. Вот соответствующие части кода:

SomeModule.cmake:

include(ExternalProject)

set(flatbuffers_CMAKE_ARGS
    "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
    "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}"
    "-DFLATBUFFERS_BUILD_TESTS=OFF"
    "-DFLATBUFFERS_BUILD_FLATC=ON"
    "-DFLATBUFFERS_BUILD_FLATHASH=OFF"
    "-DCMAKE_INSTALL_PREFIX=${OTS_DEPENDENCIES}"
)

ExternalProject_Add(
    flatbuffers
    GIT_REPOSITORY  "https://github.com/google/flatbuffers.git"
    GIT_TAG         "v1.9.0"
    SOURCE_DIR      "${OTS_DEPDENDENCIES_DIR}/flatbuffers"
    BINARY_DIR      "${OTS_DEPDENDENCIES_DIR}/flatbuffers"
    CMAKE_ARGS      "${flatbuffers_CMAKE_ARGS}"
    INSTALL_COMMAND ""
)

ExternalProject_Get_Property(flatbuffers SOURCE_DIR)
ExternalProject_Get_Property(flatbuffers BINARY_DIR)
set(flatbuffers_SOURCE_DIR ${SOURCE_DIR})
set(flatbuffers_BINARY_DIR ${BINARY_DIR})
set(flatbuffers_INCLUDE_DIR ${flatbuffers_SOURCE_DIR}/include)
set(flatbuffers_FLATC_EXECUTABLE ${flatbuffers_BINARY_DIR}/flatc)
# please assume that the variables above are all set to appropriate values

function(FlatbuffersGenerateCpp SCHEMA_FILES GENERATED_DIR GENERATED_CXX)
    foreach(SCHEMA_FILE ${SCHEMA_FILES})
        get_filename_component(NAME ${SCHEMA_FILE} NAME_WE)
        set(GENERATED_HEADER_FILE_PATH ${GENERATED_DIR}/${NAME}_generated.h)
        message(STATUS "attempting to generate: ${GENERATED_HEADER_FILE_PATH}")
        add_custom_command(
            DEPENDS ${flatbuffers_FLATC_EXECUTABLE}
            OUTPUT ${GENERATED_HEADER_FILE_PATH}
            COMMAND ${flatbuffers_FLATC_EXECUTABLE} -o ${GENERATED_DIR} -c ${SCHEMA_FILE}
            COMMENT "generating flatbuffers c++ header file: ${GENERATED_HEADER_FILE_PATH}"
        )
        list(APPEND GENERATED_FILES ${GENERATED_HEADER_FILE_PATH})
    endforeach()
    message(STATUS "generated c++ header files: ${GENERATED_FILES}")
    set(${GENERATED_CXX} ${GENERATED_FILES} PARENT_SCOPE)
endfunction()

А также some/directory/CMakeLists.txt:

# cmake module path is properly set so the following works:
include(SomeModule)

set(flatbuffers_GENERATED_INCLUDES_DIR
    ${CMAKE_BINARY_DIR}/generated/config/flatbuffers
)

FlatbuffersGenerateCpp(
    "${flatbuffers_SCHEMAS}"
    "${flatbuffers_GENERATED_INCLUDES_DIR}"
    flatbuffers_GENERATED_CXX
)

add_library(
    my_framework
SHARED
    ${THE_PUBLIC_HEADER_FILES}
    ${THE_IMPL_SOURCE_FILES}
    ${THE_IMPL_HEADER_FILES}
    ${flatbuffers_GENERATED_CXX}
)

add_dependencies(my_framework flatbuffers ${flatbuffers_GENERATED_CXX})

target_include_directories(my_framework PRIVATE ${flatbuffers_INCLUDE_DIR})
target_include_directories(my_framework PRIVATE ${CMAKE_SOURCE_DIR})
target_include_directories(my_framework PRIVATE ${CMAKE_BINARY_DIR}/generated)
set_source_files_properties(${flatbuffers_GENERATED_CXX} PROPERTIES GENERATED TRUE)

1 ответ

Решение

Я начал изменять свой код, основываясь на комментариях, опубликованных Цываревым:

Функции CMake выполняются на этапе настройки, поэтому вам также необходимо собрать внешний проект на этапе настройки.

Хотя я верил, что предложенное им решение будет работать, мне было немного не по себе и я думал, что должно быть более элегантное решение. Я проконсультировался с коллегой и нашел лучшее решение, которое так же просто, как следующий diff (который удаляет ${flatbuffers_GENERATED_CXX}).

- add_dependencies(my_framework flatbuffers ${flatbuffers_GENERATED_CXX})
+ add_dependencies(my_framework flatbuffers)

мы рассмотрели, что проблема с данным кодом заключается в том, что, как есть, CMake читает add_dependencies(my_framework flatbuffers ${flatbuffers_GENERATED_CXX}) и понимает, что ему нужно ${flatbuffers_GENERATED_CXX} как цель для строительства my_framework так что продолжается с запуском функции. Но у него нет возможности понять, что функция зависит от внешнего проекта. Теперь, если мы удалим явное объявление зависимости ${flatbuffers_GENERATED_CXX}CMake откладывает запуск функции после разрешения других зависимостей (целевой объект flatbuffers), которые эффективно загрузят и соберут внешний проект до запуска проекта.

Другие вопросы по тегам