Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Install EXPORT requires target from subproject

Tags:

cmake

I'm trying to write a cmake script for installing a project I'm working on. Part of this is the necessary install(EXPORT LIB_EXPORTS ...) where LIB_EXPORTS is what I've been using for the EXPORT property in my various install(TARGETS ...).

I have a superbuild structure that uses add_subdirectory to build some projects (SDL2, CivetWeb) that my project depends on.

My problem is that when I use target_link_libraries to add a link from a subproject (SDL2-static from SDL2, c-library from CivetWeb) cmake complains that these dependencies aren't in the export set.

CMake Error: install(EXPORT "LIB_EXPORTS" ...) includes target "sc2api" which requires target "c-library" that is not in the export set.
CMake Error: install(EXPORT "LIB_EXPORTS" ...) includes target "sc2renderer" which requires target "SDL2-static" that is not in the export set.

The only way I know to add targets to an export set is by using install(TARGETS ... EXPORT LIB_EXPORTS) but we can't install a target that this subdirectory hasn't created. I could install(FILES ... EXPORT LIB_EXPORTS) if I could find for sure where that library file's been generated but I have a feeling that this would install it twice (once by the CMakeLists.txt in the project subdirectory, once here). Frankly, I'm not sure why including these are necessary, since the libraries should be statically linked into the targets in my project.

My questions:

  1. How should I include these external targets in the export set?
  2. If I shouldn't, what is the correct way to install the export set?
  3. Bonus question: These subprojects automatically add their install targets to my project's install target. Is this necessary? If it isn't, how do I disable this?
like image 502
Braaedy Avatar asked Aug 20 '17 01:08

Braaedy


1 Answers

we can't install a target that this subdirectory hasn't created

First off, this isn't quite true. Since you're adding your dependencies with add_subdirectory, they are not IMPORTED; this means they are globally visible and it doesn't matter where in the project they were created. It just matters that they have been created in time for the call to install(TARGETS).

One convenient approach is to put all your packaging commands in packaging/CMakeLists.txt and then call add_subdirectory(packaging) at the end of your top-level CMakeLists.txt so that every target has been created before the first install() call.

You would then add the targets to your normal export set:

install(TARGETS sc2api sc2renderer c-library SDL2-static
        EXPORT LIB_EXPORTS
        ...)

install(EXPORT LIB_EXPORTS ...)

This is the preferred way of doing things.


Frankly, I'm not sure why including these are necessary, since the libraries should be statically linked into the targets in my project.

They might carry their own usage requirements, like other libraries they depend on. So when exporting, CMake needs to recreate everything that's relevant to using your library, including all transitive dependencies. If you're absolutely certain that this will never be a concern, you can use $<BUILD_INTERFACE:...> to block the dependency from exporting.

add_library(sc2api SHARED)
target_link_libraries(sc2api PRIVATE $<BUILD_INTERFACE:c-library>)

This is occasionally useful for INTERFACE libraries that collect warning flags or the like, and would export as empty targets.

like image 77
Alex Reinking Avatar answered Sep 23 '22 16:09

Alex Reinking