1

I am trying to export a library from a CMake project. Internally, I've broken this library up into multiple sub-targets. I would now like to export just the full public library, without needing my private library binaries. The following doesn't work.

cmake_minimum_required(VERSION 3.2)

project(export-mwe)

add_library(priv priv.cpp)

add_library(exp-lib exp-lib.cpp)
target_link_libraries(exp-lib PRIVATE priv)

install(TARGETS exp-lib EXPORT export-mwe DESTINATION lib)

install(EXPORT export-mwe DESTINATION .)

When I try generating this project I get an error.

CMake Error: install(EXPORT "export-mwe" ...) includes target "exp-lib" which requires target "priv" that is not in the export set.

How can I export only exp-lib in this example, without having to export priv with it?

John
  • 7,301
  • 2
  • 16
  • 23
  • You cannot export a library interface with insufficient dependencies. You will have to write a package config file. See cmake-buildsystem(7) and cmake-packages(7). –  Nov 28 '17 at 18:54

1 Answers1

1

The library exp-lib is static (this is default on Linux), so it is NOT "physically" linked with priv: creation of a static library doesn't calls a linker at all.

When applied to a static library, CMake interprets target_link_libraries in a specific manner: the actual linkage with the priv library file is moved to the every target, which links with exp-lib.

That is, further

target_link_libraries(shared-lib exp-lib)

will be translated to the linker's command line

ld -o shared-lib.so <...> exp-lib.a deps.a

When a static library is exported, CMake exposes the same behavior: Any target, which links with IMPORTED target exp-lib via target_link_libraries, automatically gets linkage with deps.a. For implement such behavior, CMake needs to know where deps.a is installed.

While installation location of deps.a can be obtained from install(TARGETS deps) command, CMake still requires that installation to be exported: install(TARGETS deps EXPORT export-mwe).

Tsyvarev
  • 60,011
  • 17
  • 110
  • 153
  • 2
    Isn't STATIC the default? – John Nov 28 '17 at 21:48
  • Hmm, most likely libraries are *STATIC* by default. I have just tested your code on my machine (Linux, CMake 3.4.1), and have got very strange results: 1. `priv` is noted in export file when and only when `exp-lib` is *STATIC* (!!), type of `priv` library doesn't affect on that. 2. Neither error nor warning is generated with any combination of *STATIC* / *SHARED* for `exp-lib` and `priv` libraries. – Tsyvarev Nov 29 '17 at 08:05
  • 2
    What if `priv` was a header-only library defined with `add_library(INTERFACE)` followed by target_include_directories(INTERFACE)? Shouldn't it be excluded from the export file? I have this case and cmake tell me in an error message that I have to export priv as well. – Mohammed Safwat Jul 16 '18 at 09:55
  • "... cmake tell me in an error message that I have to export priv as well."- Just do what CMake tells you. Like normal libraries, *INTERFACE* libraries can be exported and installed too. – Tsyvarev Jul 16 '18 at 10:09
  • As John notes, `STATIC` is default, and I can confirm that this doesn't solve the issue (with CMake 3.10.2). – definelicht Feb 04 '19 at 14:01
  • `STATIC` is the default unless `BUILD_SHARED_LIBS` is set, and then `SHARED` is the default. I just tried it and if I explicitly set `STATIC` then the information is indeed not stored in the export file. – tomereli Nov 21 '19 at 23:22
  • That's because if it's linked as a shared library, downstream libraries need to know where to locate the shared library dependency. – Ryan Friedman Jun 28 '23 at 23:12
  • The answer has been rewritten, as old variant was completely wrong. Actually, it is STATIC nature of `exp-lib` library causes given error message. So my observations in the [first comment](https://stackoverflow.com/questions/47534442/cmake-how-to-export-a-library-with-private-dependencies/47540871#comment82052074_47540871) have logical explanations. – Tsyvarev Jun 29 '23 at 00:20