【问题标题】:CMake declare dependency of function on ExternalProject_AddCMake 声明函数对 ExternalProject_Add 的依赖
【发布时间】:2018-12-20 22:08:09
【问题描述】:

TLDR

我的问题是 CMake 之前开始执行这个函数 下载存储库。我想声明一个依赖 ExternalProject_Add 上的那个函数,以便 CMake 理解它 应该下载、构建然后运行函数。

上下文

我有一个 cmake 模块 SomeModule.cmake,它应该将 flatbuffers 作为其存储库中的外部项目添加并构建它。该构建将生成 flatbuffers 编译器可执行文件,我打算在 some/directory/CMakeLists.txt 文件中使用它来从 flatbuffers 模式生成 c++ 头文件。因此,在我使用ExternalProject_Add 的同一个 CMake 模块中,我声明了一个 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)

【问题讨论】:

  • CMake 函数在 configure 阶段执行,因此您也需要在 configure 阶段构建外部项目。 (在此阶段没有“依赖关系” - CMake 脚本是逐行按顺序处理的)。有关在配置阶段构建外部项目的信息,请参阅that question
  • 感谢您的评论。你总是乐于助人。 :) 老实说,我不知道 CMake 中配置和构建阶段之间的区别。我将开始研究上述问题。

标签: c++ cmake flatbuffers external-project


【解决方案1】:

我确实开始根据Tsyvarev 发表的评论修改我的代码:

CMake函数在configure阶段执行,所以你也需要在configure阶段构建外部项目。

虽然我相信他提出的解决方案会奏效,但我有点不舒服,并一直认为必须有一个更优雅的解决方案。我咨询了一位同事并提出了一个更好的解决方案,它与以下差异一样简单(删除了${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 目标)之后运行该函数,这将在运行项目之前有效地下载和构建外部项目。

【讨论】:

  • 这个解决方案有一个小缺点,我们正在删除显式依赖声明,这(我认为)总是有助于提高可读性。
  • 嗯,“CMake 在下载存储库之前开始执行此函数”的问题似乎不是您实际遇到的问题:运行该函数是可以的,它会创建 rules (add_custom_command) 用于创建文件,无需下载 flatbuffers 项目。你需要的是让flatbuffers 被下载之前 add_custom_command 将实际生成文件。这是构建阶段,而不是配置阶段。代码总体上是正确的:您创建了一个既依赖于flatbuffers 又依赖于命令生成的文件的目标。
  • 注意,add_dependencies 仅适用于 CMake targets;它不适用于常规文件。所以无论如何在这个 CMake 命令中使用${flatbuffers_GENERATED_CXX} 是错误的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-17
  • 1970-01-01
  • 2013-07-01
  • 1970-01-01
  • 2011-10-15
相关资源
最近更新 更多