Search code examples
c++cmakeguideline-support-library

propagate dependencies to header-only ExternalProject with cmake


I'm trying to build a header-only library using CMake (Microsoft/GSL), in such a way that I can use variables like GSL_INCLUDE_DIRS and GSL_LIBRARIES to link to the target and propagate the appropriate dependencies.

The project I'm working on has a TON of sub-directories, and all the external projects are built in their own sub-directories, hence why the variables are important.

I'm using CMake 3.2.3

Typically (for a library with an actual .lib or .a) I'd do something like:

SET(TARGET_NAME gsl)

include(ExternalProject)
ExternalProject_Add(
    ${TARGET_NAME}-ext
    URL "http://target/url"
    CONFIGURE_COMMAND ""
    BUILD_COMMAND ""
    INSTALL_COMMAND ""
)   # download/unzip the header-only project

# Specify include dir
SET(${TARGET_NAME}_INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR}/include CACHE STRING "${TARGET_NAME} include directory")

# Library
add_library(${TARGET_NAME} SHARED IMPORTED GLOBAL)
SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES 
    IMPORTED_LOCATION "some/path/to/some/lib"
)
add_dependencies(${TARGET_NAME} ${TARGET_NAME}-ext)
SET(${TARGET_NAME}_LIBRARIES ${TARGET_NAME} CACHE STRING "${TARGET_NAME} library location")

MARK_AS_ADVANCED(${TARGET_NAME_UPPER}_DIR ${TARGET_NAME_UPPER}_INCLUDE_DIRS ${TARGET_NAME_UPPER}_LIBRARIES)

The problem here is that the header-only library has no lib to set the imported path for, so I can't use an IMPORTED library. If I don't use a library at all, then I can't set the dependencies in other modules on GSL without building (i.e. downloading/unzipping) every single time, which I don't want to do. a custom_target would have the same problem, so that's a no-go.

I think what I want is an interface library, something like

add_library(${TARGET_NAME} INTERFACE)
add_dependencies(${TARGET_NAME} ${TARGET_NAME}-ext)

but then cmake complains that

CMake Error at 3rdParty/gsl/CMakeLists.txt:33 (add_dependencies): add_dependencies Cannot add target-level dependencies to INTERFACE library target "gsl".

Is there someway I can use the interface library (or something) to propagate the dependency on the external project?


Solution

  • Disallowing dependencies on INTERFACE libraries was an oversight that was corrected in CMake version 3.3. After upgrading to the latest-stable release, I was able to use the methodology described in the question, and it worked exactly as desired.