YoavKlein
YoavKlein

Reputation: 2715

CMake: Install an export file in Debug/Release alternatively?

Take the following example as a start:

...
add_library(Foo ...)
install(TARGETS Foo EXPORT FooTargets
  LIBRARY DESTINATION lib
  ARCHIVE DESTINATION lib
...
)

install(EXPORT FooTargets
 FILE lib/cmake/Foo
...
)

Running this with

$ mkdir build; cd build
$ cmake -DCMAKE_BUILD_TYPE=Release .. (or in Debug)
$ cmake --build .
$ cmake --install . --prefix my/custom/prefix

This will create the files:

my/custom/prefix/lib/cmake/Foo/FooTargets.cmake
my/custom/prefix/lib/cmake/Foo/FooTargets-release.cmake (Or debug, respectively)
my/custom/prefix/lib/libFoo.a

And from what I managed to understand from the FooTargets.cmake file, it globs for all FooTargets-*.cmake files and includes() them all.

In turn, the FooTargets-release.cmake file is the one that references the libFoo.a file.

In the docs about the install command, it says that you can add the CONFIGURATIONS option to the install TARGETS command, so that if we change the above:

install(TARGETS Foo EXPORT FooTargets
   CONFIGURATIONS Debug
   LIBRARY DESTINATION lib/Debug
   ARCHIVE DESTINATION lib/Debug

This will install the libFoo.a file in my/custom/path/lib/Debug/libFoo.a. Now let's say I want the Release library to be installed in lib/Release and the Debug library be installed in lib/Debug, and that when the downstream project will consume my package, it will have the right library depending on its configuration - i.e. - debug build will link against the Debug library, same for release.

What I thought I can do is:

install(TARGETS Foo EXPORT FooTargets
   CONFIGURATIONS Debug
   LIBRARY DESTINATION lib/Debug
   ARCHIVE DESTINATION lib/Debug
)

install(TARGETS Foo EXPORT FooTargets 
  CONFIGURATIONS Release
  LIBRARY DESTINATION lib/Release
  ARCHIVE DESTINATION lib/Release
)

install(EXPORT FooTargets 
  DESTINATION lib/cmake/Foo
  ...
)

And what will happen is that when building in Debug, the FooTargets-debug.cmake will be generated, pointing to the lib/Debug/libFoo.a, and when building in Release, the FooTargets-release.cmake will be generated, pointing to the lib/Release/libFoo.a. The FooTargets.cmake will then check what configuration is the consuming project is building with, and include the right configuration.

When I try doing the above, I get:

-- Configuring done
CMake Error: install(EXPORT "FooTargets" ...) includes target "Foo" more than once in the export set.
-- Generating done
CMake Generate step failed.  Build files cannot be regenerated correctly.

How is this should be done??

EDIT

I found out, in a not-very-straightforward way, that when I build the consuming project as such:

$ cmake -DCMAKE_BUILD_TYPE=Debug ..

and like this:

$ cmake -DCMAKE_BUILD_TYPE=Release ..

I am linking against only the relevant library. Basically how this works is that the FooTargets.cmake file is included by the FooConfig.cmake file, which is called by find_package. The FooTargets.cmake file is the one that defines the imported target:

add_library(Foo IMPORTED)

This file then calls all the FooTargets-*.cmake, which adds the relevant library to some list called _IMPORT_CHECK_FILES_FOR_FOO. What this file also does, is:

set_property(TARGET Foo::Foo APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)

Apparently there is some property IMPORTED_CONFIGURATIONS that holds the imported configurations.

I suppose that somewhere down the road, find_package takes this list and filters it according to the CMAKE_BUILD_TYPE variable, and this way links only the relevant library.

What I still don't understand, is how to make it so that upon Release builds (of Foo), the FooTargets-release.cmake will be created, pointing to lib/Release/Foo.a, and the same for debug builds.

It seems that CMake went half-way with this, unless I'm seriously missing something.

Upvotes: 0

Views: 1065

Answers (1)

Tsyvarev
Tsyvarev

Reputation: 66118

It seems per-CONFIGURATIONS installs are not easily fit to EXPORT semantic.

However, in simple cases per-configuration's specific can be achieved by using generator expressions in DESTINATION:

install(TARGETS Foo EXPORT FooTargets
   LIBRARY DESTINATION lib/$<CONFIG>
   ARCHIVE DESTINATION lib/$<CONFIG>
)

install(EXPORT FooTargets 
  DESTINATION lib/cmake/Foo
  ...
)

The code above will install libraries into lib/Debug for Debug configuration, and into lib/Release for Release configuration.

Upvotes: 2

Related Questions