Add only library headers during target_link_libraries()


I have a set of C source files and headers. From this I want to compile a shared library for normal linkage and then similar (just some different DEFINEs) MODULE library used to dynamically load the functionality as a module with RTLD_GLOBAL, so the namespace will be afterwards infused with its symbols.

For modules which depends on symbols from previous modules, I need to create an interface - set of header files. For the normal shared library, this works well as I just set the include directory PUBLIC and every library depending on it with target_link_libraries() will transitively get the headers. But I cannot use the target_link_libraries() call to get the same functionality for MODULE library because in that case that library will be linked in the binary, which cannot be.

One way how to solve this is to create an INTERFACE library with only the PUBLIC headers and target_link_libraries() this to both the shared library and the MODULE library. Any additional module which will depend on this module will just target_link_libraries() the INTERFACE library.

Problem is, I feel this is ugly, and I am making everybody who wants to add another module to the software package to add basically two targets instead of one (not every module will have both shared library and MODULE library version).

So, can I somehow set an option on the MODULE library that when somebody calls target_link_libraries() on it, it will only add the headers, but will not link in any way?


Forgot to mention: This is Linux only question. Probably GNU Libc only too.

I wholeheartedly second the request for such a feature. We have a large suite of runtime-loaded libraries in a project. They have usage requirements (all have include directories, sometime have compile definitions too) which we’d love to propagate using CMake’s transitive usage requirement mechanism, but without linking the library itself.

I am aware there’s this possible workaround:

# instead of target_link_libraries(Consumer PRIVATE Library), do
target_include_directories(Consumer PRIVATE $<TARGET_PROPERTY:Library,INTERFACE_INCLUDE_DIRECTORIES>)

However, that needs one such line for each INTERFACE_* property potentially set on the Library target. It could be wrapped in a project-side function to set all such properties, but that then needs maintenance whenever CMake adds a new INTERFACE_* property, and still feels like unnecessary duplication of functionality CMake must have internally anyway.

Can someone enlighten me about the concept of plugin modules where the loader must know about them? Or even need header files or definitions of them. Sounds kinda weird.

In our case, each such module defines some pure virtual interfaces, and then registers itself as "I can create objects which implement I1 and I2" into a central registry. Consumer code uses only the interfaces (so it needs the headers for them), but requests actual objects from the central registry. The registry satisfies the requests based on which modules were loaded at runtime (the runtime loading happens via Qt’s plugin mechanism).

This allows rebuilding a module without the need to re-link everything, and code can make runtime decisions based on which modules were loaded (i.e. which objects are available).

There was an issue where I opined on a $<COMPILE_ONLY> genex for such a use case. I can’t find it right now though.