# Add only library headers during target\_link\_libraries()

**URL:** https://discourse.cmake.org/t/add-only-library-headers-during-target-link-libraries/2973
**Category:** Code
**Created:** [March 17, 2021, 8:43pm UTC](https://discourse.cmake.org/t/add-only-library-headers-during-target-link-libraries/2973 "2021-03-17T20:43:52Z")
**Posts on this page:** 18
**Page:** 1

<div class="post-metadata">

### Author: ![cerna](https://discourse.cmake.org/user_avatar/discourse.cmake.org/cerna/32/1299_2.png) [@cerna](https://discourse.cmake.org/u/cerna)
#### Post date: [March 17, 2021, 8:43pm UTC](https://discourse.cmake.org/t/add-only-library-headers-during-target-link-libraries/2973/1 "2021-03-17T20:43:52Z")

</div>

Hello,

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?

Thanks.

_Forgot to mention_: This is Linux only question. Probably GNU Libc only too.

---

<div class="post-metadata">

### Author: ![Angew](https://discourse.cmake.org/user_avatar/discourse.cmake.org/angew/32/229_2.png) [@Angew](https://discourse.cmake.org/u/Angew)
#### Post date: [March 18, 2021, 10:22am UTC](https://discourse.cmake.org/t/add-only-library-headers-during-target-link-libraries/2973/2 "2021-03-18T10:22:14Z")

</div>

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:

```auto
# 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.

---

<div class="post-metadata">

### Author: ![hsattler](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/h/59ef9b/32.png) [@hsattler](https://discourse.cmake.org/u/hsattler)
#### Post date: [March 18, 2021, 11:04am UTC](https://discourse.cmake.org/t/add-only-library-headers-during-target-link-libraries/2973/3 "2021-03-18T11:04:33Z")

</div>

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.

---

<div class="post-metadata">

### Author: ![Angew](https://discourse.cmake.org/user_avatar/discourse.cmake.org/angew/32/229_2.png) [@Angew](https://discourse.cmake.org/u/Angew)
#### Post date: [March 18, 2021, 11:12am UTC](https://discourse.cmake.org/t/add-only-library-headers-during-target-link-libraries/2973/4 "2021-03-18T11:12:16Z")

</div>

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).

---

<div class="post-metadata">

### Author: ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)
#### Post date: [March 18, 2021, 1:10pm UTC](https://discourse.cmake.org/t/add-only-library-headers-during-target-link-libraries/2973/5 "2021-03-18T13:10:46Z")

</div>

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.

---

<div class="post-metadata">

### Author: ![themarpe](https://discourse.cmake.org/user_avatar/discourse.cmake.org/themarpe/32/1613_2.png) [@themarpe](https://discourse.cmake.org/u/themarpe)
#### Post date: [May 14, 2022, 1:45pm UTC](https://discourse.cmake.org/t/add-only-library-headers-during-target-link-libraries/2973/6 "2022-05-14T13:45:42Z")

</div>

Hi.

I also think that this should be an option. I initially (wrongfully) thought that this is what `INTERFACE` linking did. (As it was constantly mentioned in relation with header only libraries).

Our use case is that we compile a couple of static libraries into a single shared library, but we still need to expose some include headers and defines down to consumers, without having the link to those static libraries again, causing issues.

The workaround mentioned by @Angew looks great, but one issue is that its actually not the same as a “header/define only linking” would be. (Same issue over at official documentation: [https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#transitive-usage-requirements](https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#transitive-usage-requirements))

```auto
target_link_libraries(myExe lib1 lib2 lib3)
target_include_directories(myExe
  PRIVATE $<TARGET_PROPERTY:lib3,INTERFACE_INCLUDE_DIRECTORIES>)

```

Both Petrs and above examples have one specific flaw, which puts it into a hack/workaround section instead of a proper means of doing it - it sets these include directories to the “myExe” target instead of the “lib3”.

If some consuming CMake code would like to get all include directories of myExe, those would then also include lib3’s include directories. (currently facing this issue myself, trying to integrate this into our project. Some bindings generation mechanism now tries to parse the library headers as well…)

Not sure on scope of implementing this (or if there is any proper means of working around it), but I assume CMake could add an option which along scope of linking, also specifies to what to link to.

```auto
target_link_libraries(tgt PRIVATE lib1)
target_link_libraries(tgt INTERFACE_NO_LINK lib1)

```

or something along these lines. Maybe a generator expression, inverse of `LINK_ONLY`?

One approach I saw and I think will likely pursue in our case is to create another “header-only” library for those static libraries. Then one can link to eg: `lib1Headers` publically/interface and PRIVATE `lib1`. I think this should resolve my issue.

Regards,  
Martin Peterlin

---

<div class="post-metadata">

### Author: ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)
#### Post date: [May 15, 2022, 1:26pm UTC](https://discourse.cmake.org/t/add-only-library-headers-during-target-link-libraries/2973/7 "2022-05-15T13:26:29Z")

</div>

> [@themarpe](#):
>
> Maybe a generator expression, inverse of `LINK_ONLY`

You mean something like this?

> [@ben.boeckel](#):
>
> a `$<COMPILE_ONLY>` genex for such a use case

---

<div class="post-metadata">

### Author: ![themarpe](https://discourse.cmake.org/user_avatar/discourse.cmake.org/themarpe/32/1613_2.png) [@themarpe](https://discourse.cmake.org/u/themarpe)
#### Post date: [May 16, 2022, 4:52pm UTC](https://discourse.cmake.org/t/add-only-library-headers-during-target-link-libraries/2973/8 "2022-05-16T16:52:14Z")

</div>

@ben.boeckel

If `COMPILE_ONLY` stands in for such feature, then yes. Naming wise, I think maybe `INTERFACE_ONLY` or something along those lines would be better.

If you happen to find this discussion, would gladly read through it:)

---

<div class="post-metadata">

### Author: ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)
#### Post date: [May 16, 2022, 5:23pm UTC](https://discourse.cmake.org/t/add-only-library-headers-during-target-link-libraries/2973/9 "2022-05-16T17:23:48Z")

</div>

How is `INTERFACE_ONLY` better? Isn’t that just putting things under the `INTERFACE` scope to begin with?

---

<div class="post-metadata">

### Author: ![themarpe](https://discourse.cmake.org/user_avatar/discourse.cmake.org/themarpe/32/1613_2.png) [@themarpe](https://discourse.cmake.org/u/themarpe)
#### Post date: [May 16, 2022, 6:06pm UTC](https://discourse.cmake.org/t/add-only-library-headers-during-target-link-libraries/2973/10 "2022-05-16T18:06:43Z")

</div>

Not sure - just that `COMPILE_ONLY` seems like something has to be compiled along. If we only want headers and defines, that seems off?

Why I lean (again, erroneously) to `INTERFACE` is that header only libraries are defined in such way - thats why I have the association.

Better to have some other naming for such feature.

---

<div class="post-metadata">

### Author: ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)
#### Post date: [May 16, 2022, 9:02pm UTC](https://discourse.cmake.org/t/add-only-library-headers-during-target-link-libraries/2973/11 "2022-05-16T21:02:56Z")

</div>

> [@themarpe](#):
>
> If we only want headers and defines, that seems off?

Yes, those are only used during the compilation phase. Hence the name.

---

<div class="post-metadata">

### Author: ![themarpe](https://discourse.cmake.org/user_avatar/discourse.cmake.org/themarpe/32/1613_2.png) [@themarpe](https://discourse.cmake.org/u/themarpe)
#### Post date: [May 16, 2022, 11:47pm UTC](https://discourse.cmake.org/t/add-only-library-headers-during-target-link-libraries/2973/12 "2022-05-16T23:47:05Z")

</div>

Got it - so is this something you’d be up to have developed and/or is in the process of being developed?

---

<div class="post-metadata">

### Author: ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)
#### Post date: [May 17, 2022, 1:15am UTC](https://discourse.cmake.org/t/add-only-library-headers-during-target-link-libraries/2973/13 "2022-05-17T01:15:28Z")

</div>

It’s on my wish list, but it is far longer than I can get to. Feel free to submit an MR. I’d suggest tracing how `$<LINK_ONLY>` works and do something similar for the compile codepath.

---

<div class="post-metadata">

### Author: ![themarpe](https://discourse.cmake.org/user_avatar/discourse.cmake.org/themarpe/32/1613_2.png) [@themarpe](https://discourse.cmake.org/u/themarpe)
#### Post date: [May 17, 2022, 9:09am UTC](https://discourse.cmake.org/t/add-only-library-headers-during-target-link-libraries/2973/14 "2022-05-17T09:09:51Z")

</div>

Noted - I’ll try looking into it if some free time presents, but will be slow regardless as I’m not familiar with CMake underlying codebase:)

If I do however create any progress, I’ll open the MR just so that there is a single point of development there if it does gain traction.

---

<div class="post-metadata">

### Author: ![ignus2](https://discourse.cmake.org/user_avatar/discourse.cmake.org/ignus2/32/3075_2.png) [@ignus2](https://discourse.cmake.org/u/ignus2)
#### Post date: [January 23, 2023, 9:30am UTC](https://discourse.cmake.org/t/add-only-library-headers-during-target-link-libraries/2973/15 "2023-01-23T09:30:07Z")

</div>

I know this is an old topic but I faced a similar situation in a large project I’m porting to CMake, so I’ll post my solution in case someone also comes this across.

In our case a set of static libs was linked into a DLL, and that DLL was linked by an EXE. The EXE is also using the static lib headers, but does not link against them directly, but only against the DLL.  
The solution I came up with was to create an INTERFACE library for the static libs which only allows actual linking if a certain property is set on the target using the libs.  
To create the INTERFACE library I created a function which pulls in the relevant compile only related properties from the static lib, and puts the static library into the INTERFACE\_LINK\_LIBRARIES of the interface library with a conditional generator expression.

```auto
function(add_library_with_interface tgt)
    # the real lib, hidden
    add_library(_${tgt} ${ARGN})
    set_property(TARGET _${tgt} PROPERTY OUTPUT_NAME ${tgt}) # lib name
    set_property(TARGET _${tgt} PROPERTY PROJECT_LABEL ${tgt}) # vs project name
    
    # the interface lib to be used
    add_library(${tgt} INTERFACE)
    foreach(p COMPILE_DEFINITIONS COMPILE_FEATURES COMPILE_OPTIONS INCLUDE_DIRECTORIES SOURCES SYSTEM_INCLUDE_DIRECTORIES)
        set_property(TARGET ${tgt} APPEND PROPERTY INTERFACE_${p} $<TARGET_PROPERTY:_${tgt},INTERFACE_${p}>)
    endforeach()
    target_link_libraries(${tgt} INTERFACE $<$<BOOL:$<TARGET_PROPERTY:${tgt}_DO_LINK>>:$<LINK_ONLY:_${tgt}>>)
endfunction()

# libA is the one for which we would like to prevent linking
add_library_with_interface(libA STATIC a.cpp) # during setup _libA must be used!!!
target_include_directories(_libA PUBLIC incA) # use _libA here

# libB uses libA
add_library(libB STATIC b.cpp)
target_include_directories(libB PUBLIC incB)
target_link_libraries(libB PUBLIC libA)

# libShared uses libB (and transitively libA) and links in libA
add_library(libShared SHARED c.cpp)
target_link_libraries(libShared PRIVATE libB)
set_property(TARGET libShared PROPERTY libA_DO_LINK 1) # causes libA to be linked in

# app uses libShared and libA headers but doesn't link in libA
add_executable(app app.cpp)
target_link_libraries(app libShared libA) # libA is not linked in

```

---

<div class="post-metadata">

### Author: ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)
#### Post date: [January 26, 2023, 2:12pm UTC](https://discourse.cmake.org/t/add-only-library-headers-during-target-link-libraries/2973/16 "2023-01-26T14:12:08Z")

</div>

`$<COMPILE_ONLY>` is also be part of [this MR](https://gitlab.kitware.com/cmake/cmake/-/merge_requests/8118).

---

<div class="post-metadata">

### Author: ![Artalus](https://discourse.cmake.org/user_avatar/discourse.cmake.org/artalus/32/1527_2.png) [@Artalus](https://discourse.cmake.org/u/Artalus)
#### Post date: [November 20, 2023, 1:46pm UTC](https://discourse.cmake.org/t/add-only-library-headers-during-target-link-libraries/2973/17 "2023-11-20T13:46:58Z")

</div>

`$<COMPILE_ONLY>` has been added in CMake 3.27 [[1]](https://cmake.org/cmake/help/latest/release/3.27.html#generator-expressions) [[2]](https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html#genex:COMPILE_ONLY) and can now be used like this:

```cmake
target_link_libraries(y $<COMPILE_ONLY:x>)
target_link_libraries(z PRIVATE y)
target_link_libraries(executable z)

```

In the resuling build, the executable will be linked as `c++ -o executable liz.a liby.a` without linking against `libx.a` as well. Include directories of `x`, if any, will me mentioned only in compilation commands for `y` and `x` itself.

Huge thanks to you, Ben, for finally implementing it; I remember quite a few places among my codebases where this might be of service 🙂

---

<div class="post-metadata">

### Author: ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)
#### Post date: [November 20, 2023, 1:52pm UTC](https://discourse.cmake.org/t/add-only-library-headers-during-target-link-libraries/2973/18 "2023-11-20T13:52:04Z")

</div>

> [@Artalus](#):
>
> Huge thanks to you, Ben, for finally implementing it; I remember quite a few places among my codebases where this might be of service 🙂

I got it started. @robert.maynard took it across the finish line 🙂 .
