Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CMake: how to use INTERFACE_INCLUDE_DIRECTORIES with ExternalProject?

Tags:

cmake

I'm trying to add external project as a library to my project using ExternalProject_Add:

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

Also, I'm defining library target and adding external project as a dependency:

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

in another CMakeLists.txt:

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

The problem is that cmake INTERFACE_INCLUDE_DIRECTORIES doesn't allow to export include dir which does not exist.

Is there any other way to make header files being included automatically for all targets which depend on libxgboost ?

UPDATE:

Error message:

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.
like image 639
Stanislav Levental Avatar asked Aug 04 '17 22:08

Stanislav Levental


2 Answers

Note that it is possible to combine FetchContent and ExternalProject_Add to achieve the following:

  • FetchContent will make the source available at configure time, thereby bypassing the issue that the INTERFACE_INCLUDE_DIRECTORIES doesn't exist.
  • ExternalProject_Add will use the source downloaded by FetchContent to build at build time

Here is an example building 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)
like image 112
Steve Lorimer Avatar answered Nov 12 '22 08:11

Steve Lorimer


I'll post the final CMakeLists.txt to include xgboost into your project, it might be useful for someone, the solution to the problem above is to create directories during cmake configure phase (NOTE: I'm using OSX to build that, so you would need to use liblibxgboost.so for GNU/Linux instead of 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}"
)
like image 21
Stanislav Levental Avatar answered Nov 12 '22 08:11

Stanislav Levental