CMake: 如何在ExternalProject中使用INTERFACE_INCLUDE_DIRECTORIES?

16

我正在尝试使用ExternalProject_Add将外部项目作为库添加到我的项目中:

ExternalProject_Add(
        xgboost
        GIT_REPOSITORY https://github.com/dmlc/xgboost.git
        GIT_TAG v0.60
        PREFIX ${CMAKE_CURRENT_BINARY_DIR}
        INSTALL_COMMAND ""
)

另外,我正在定义库目标并将外部项目添加为依赖项:

set(XGBOOST_PREFIX_PATH "${CMAKE_CURRENT_BINARY_DIR}/src")
set(XGBOOST_BINARY_PATH "${XGBOOST_PREFIX_PATH}/xgboost-build")
set(XGBOOST_BINARY_INCLUDE "${XGBOOST_PREFIX_PATH}/xgboost/include;${XGBOOST_PREFIX_PATH}/xgboost/dmlc-core/include;${XGBOOST_PREFIX_PATH}/xgboost/rabit/include")
add_library(libxgboost IMPORTED STATIC GLOBAL)
add_dependencies(libxgboost xgboost)

set_target_properties(libxgboost PROPERTIES
        "IMPORTED_LOCATION" "${XGBOOST_BINARY_PATH}/liblibxgboost.dylib"
        "IMPORTED_LINK_INTERFACE_LIBRARIES" "${CMAKE_THREAD_LIBS_INIT}"
        "INTERFACE_INCLUDE_DIRECTORIES" "${XGBOOST_BINARY_INCLUDE}"
        )

在另一个CMakeLists.txt文件中:

add_library(somelib STATIC SomeLib.cpp)
target_include_directories(somelib PUBLIC libxgboost)
target_link_libraries(somelib libxgboost)

问题在于CMake的INTERFACE_INCLUDE_DIRECTORIES无法导出不存在的包含目录。

是否有其他方法可以使所有依赖于libxgboost的目标自动包含头文件?

更新:

错误消息:

CMake Error in somelib/CMakeLists.txt:
  Imported target "libxgboost" includes non-existent path

    "build/xgboost/src/xgboost/include"

  in its INTERFACE_INCLUDE_DIRECTORIES.  Possible reasons include:

  * The path was deleted, renamed, or moved to another location.

  * An install or uninstall procedure did not complete successfully.

  * The installation package was faulty and references files it does not
  provide.

请调整错误消息的大小。 - Tsyvarev
IMPORTED_LINK_INTERFACE_LIBRARIES已经过时,建议使用INTERFACE_LINK_LIBRARIES。您考虑过使用execute_process()来调用ExternalProject CMakeLists.txt上的cmake(两次),这样您就可以在配置时使用依赖项了吗?或者,您可以在CMakeLists.txt配置期间模拟创建仅依赖关系目录的方式。 - utopia
这是我的备选方案,但我仍在思考是否有更好的做法。 - Stanislav Levental
我遇到了完全相同的问题。有什么好运吗? - mchiasson
1
@mchiasson 我已经添加了完整的CMakeLists.txt,希望它能帮到你。 - Stanislav Levental
2个回答

14

我将发布最终的CMakeLists.txt,以便将xgboost包含到您的项目中,这可能对某些人有用。上面问题的解决方法是在cmake配置阶段创建目录(注意:我使用OSX进行构建,因此您需要使用liblibxgboost.so代替GNU / Linux中的liblibxgboost.dylib):

include(ExternalProject)

ExternalProject_Add(
        xgboost
        GIT_REPOSITORY https://github.com/dmlc/xgboost.git
        GIT_TAG v0.60
        PREFIX ${CMAKE_CURRENT_BINARY_DIR}
        INSTALL_COMMAND ""
)

set(XGBOOST_PREFIX_PATH "${CMAKE_CURRENT_BINARY_DIR}/src")
set(XGBOOST_BINARY_PATH "${XGBOOST_PREFIX_PATH}/xgboost-build")

set(XGBOOST_LIB_INCLUDE "${XGBOOST_PREFIX_PATH}/xgboost/include")
set(DMLC_LIB_INCLUDE "${XGBOOST_PREFIX_PATH}/xgboost/dmlc-core/include")
set(RABIT_LIB_INCLUDE "${XGBOOST_PREFIX_PATH}/xgboost/rabit/include")
set(XGBOOST_BINARY_INCLUDE "${XGBOOST_LIB_INCLUDE};${DMLC_LIB_INCLUDE};${RABIT_LIB_INCLUDE}")

# Hack to make it work, otherwise INTERFACE_INCLUDE_DIRECTORIES will not be propagated
file(MAKE_DIRECTORY ${XGBOOST_LIB_INCLUDE})
file(MAKE_DIRECTORY ${DMLC_LIB_INCLUDE})
file(MAKE_DIRECTORY ${RABIT_LIB_INCLUDE})

add_library(libxgboost IMPORTED STATIC GLOBAL)
add_dependencies(libxgboost xgboost)

set_target_properties(libxgboost PROPERTIES
        "IMPORTED_LOCATION" "${XGBOOST_BINARY_PATH}/liblibxgboost.dylib"
        "INTERFACE_INCLUDE_DIRECTORIES" "${XGBOOST_BINARY_INCLUDE}"
)

5
我希望CMake能更好地支持这一点;目前似乎有些hack。难道没有办法通过依赖项来处理吗?例如,您可以设置库的IMPORTED_LOCATION而无需该库存在。INTERFACE_INCLUDE_DIRECTORIES不同似乎是不一致的。 - Jeff Trull
3
@JeffTrull 我希望它能够以更好的方式支持它。但这是我找到的唯一途径,然而并不意味着这是唯一存在的途径。我对cmake还很新,可能有些地方理解不全。 - Stanislav Levental
2
顺便说一句,file(MAKE_DIRECTORY ...)也是CMake错误跟踪器上的人们想出来的解决方法:https://gitlab.kitware.com/cmake/cmake/issues/15052 - HunterZ

1
请注意,可以结合使用FetchContentExternalProject_Add来实现以下目的:
  • FetchContent会在配置时间使源代码可用,从而绕过INTERFACE_INCLUDE_DIRECTORIES不存在的问题。
  • ExternalProject_Add将使用FetchContent下载的源代码在构建时间进行构建。
这里是一个构建libpqxx的示例:
include(FetchContent)
include(ExternalProject)

find_package(PostgreSQL)

# Using FetchContent means we will download libpqxx at configure-time

FetchContent_Declare(libpqxx_ext
    GIT_REPOSITORY
        https://github.com/jtv/libpqxx
    GIT_TAG
        tags/7.4.1
    )

FetchContent_GetProperties(libpqxx_ext)

if(NOT libpqxx_ext_POPULATED)
  FetchContent_Populate(libpqxx_ext)
endif()

set(LIB_PQXX_SRC_DIR ${CMAKE_BINARY_DIR}/_deps/libpqxx_ext-src)

# Build libpqxx

ExternalProject_Add(libpqxx_ext
    SOURCE_DIR
        ${libpqxx_ext_SOURCE_DIR}
    PREFIX
        ext
    BINARY_DIR
        build
    CMAKE_ARGS
        -DSKIP_BUILD_TEST=on
    INSTALL_COMMAND
        ""
    BUILD_ALWAYS
        OFF
    )

set(LIB_PQXX_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/build/src)

# Make the libpxqq artifacts available to our project

add_library(libpqxx STATIC IMPORTED GLOBAL)

set_target_properties(libpqxx
    PROPERTIES

    INTERFACE_INCLUDE_DIRECTORIES
        ${LIB_PQXX_SRC_DIR}/include
    IMPORTED_LOCATION
        ${LIB_PQXX_BUILD_DIR}/libpqxx.a
    INTERFACE_LINK_LIBRARIES
        ${PostgreSQL_LIBRARIES})

add_dependencies(libpqxx libpqxx_ext)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接