# Link only directly dependent SHARED libraries

**URL:** <https://discourse.cmake.org/t/link-only-directly-dependent-shared-libraries/8231>\
**Category:** Code\
**Created:** [May 29, 2023, 2:15pm UTC](https://discourse.cmake.org/t/link-only-directly-dependent-shared-libraries/8231 "2023-05-29T14:15:26Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![chapuni](https://discourse.cmake.org/user_avatar/discourse.cmake.org/chapuni/32/1555_2.png) [@chapuni](https://discourse.cmake.org/u/chapuni)\
**Post date:** [May 29, 2023, 2:15pm UTC](https://discourse.cmake.org/t/link-only-directly-dependent-shared-libraries/8231/1 "2023-05-29T14:15:26Z")

</div>

I would like;

- Properties for compilation shall be propagated transitively. (eg. `target_include_directories(PUBLIC/INTERFACE)`
- Libraries shall be specified as `add_library(SHARED)`.
- The linker shall use directly specified library targets.

```auto
add_library(A SHARED)
target_compile_definitions(A PUBLIC FOO)

add_library(B SHARED)
target_compile_definitions(B PUBLIC BAR)
target_link_libraries(B PUBLIC A)

add_library(C SHARED)
target_compile_definitions(C PUBLIC HOGE)
target_link_libraries(C PUBLIC B)

add_executable(X)
target_link_libraries(X PRIVATE A C)

```

I will see each definition below in compilation;

- `A`: `-DFOO`
- `B`: `-DFOO` `-DBAR`
- `C`: `-DFOO` `-DBAR` `-DHOGE`
- `X`: Same as `C`

This is expected and desirable to my use.  
OTOH, I will see libraries in each linker command line below;

- `A`: (none)
- `B`: `A`
- `C`: `B` `A`
- `X`: `C` `B` `A`

I would like to enforce link libraries as directly depends by `target_link_libraries`.

- `A`: (none)
- `B`: `A`
- `C`: `B` (excludes `A`)
- `X`: `C` `A` (excludes `B`)

To enforce direct depends, I could specify `PRIVATE` for each `target_link_libraries`. But it prevents transitive `target_compile_definitions`, like;

- `A`: `-DFOO`
- `B`: `-DFOO` `-DBAR`
- `C`: `-DBAR` `-DHOGE` (A’s `-DFOO` is invisible)
- `X`: `-DFOO` `-DHOGE` (B’s `-DBAR` is invisible)

Can I make compatible “`target_compile_definitions` is propagated transitively but linking shall use direct depends only”?

---

<div class="post-metadata">

**Author:** ![marc.chevrier](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/m/ecb155/32.png) [@marc.chevrier](https://discourse.cmake.org/u/marc.chevrier)\
**Post date:** [May 29, 2023, 3:54pm UTC](https://discourse.cmake.org/t/link-only-directly-dependent-shared-libraries/8231/2 "2023-05-29T15:54:27Z")

</div>

You can achieve this by splitting requirements in two libraries:

```cmake
add_library(A_INTERFACE INTERFACE)
target_compile_definitions(A_INTERFACE INTERFACE FOO)

add_library(A SHARED)
target_link_libraries(A PUBLIC A_INTERFACE)

add_library(B_INTERFACE INTERFACE)
target_compile_definitions(B_INTERFACE INTERFACE BAR)
target_link_libraries(B_INTERFACE INTERFACE A_INTERFACE)

add_library(B SHARED)
target_link_libraries(B PUBLIC B_INTERFACE)
target_link_libraries(B PRIVATE A)

add_library(C_INTERFACE INTERFACE)
target_compile_definitions(C_INTERFACE INTERFACE HOGE)
target_link_libraries(C_INTERFACE INTERFACE B_INTERFACE)

add_library(C SHARED)
target_link_libraries(C PUBLIC C_INTERFACE)
target_link_libraries(C PRIVATE B)

add_executable(X)
target_link_libraries(X PRIVATE A C)

```

---

<div class="post-metadata">

**Author:** ![robert.maynard](https://discourse.cmake.org/user_avatar/discourse.cmake.org/robert.maynard/32/4_2.png) [@robert.maynard](https://discourse.cmake.org/u/robert.maynard)\
**Post date:** [May 30, 2023, 2:13pm UTC](https://discourse.cmake.org/t/link-only-directly-dependent-shared-libraries/8231/3 "2023-05-30T14:13:42Z")

</div>

The upcoming `COMPILE_ONLY` generator expression for CMake 3.27 should simplify this.  
You would have something like:

```cmake
add_library(A SHARED)
target_compile_definitions(A PUBLIC FOO)

add_library(B SHARED)
target_compile_definitions(B PUBLIC BAR)
target_link_libraries(B PUBLIC $<COMPILE_ONLY:A> PRIVATE A)

add_library(C SHARED)
target_compile_definitions(C PUBLIC HOGE)
target_link_libraries(C PUBLIC $<COMPILE_ONLY:B> PRIVATE B)

add_executable(X)
target_link_libraries(X PRIVATE A C)

```

---

<div class="post-metadata">

**Author:** ![chapuni](https://discourse.cmake.org/user_avatar/discourse.cmake.org/chapuni/32/1555_2.png) [@chapuni](https://discourse.cmake.org/u/chapuni)\
**Post date:** [May 31, 2023, 1:29pm UTC](https://discourse.cmake.org/t/link-only-directly-dependent-shared-libraries/8231/4 "2023-05-31T13:29:34Z")

</div>

@marc.chevrier Thank you for the suggestion.

This assumes every library should have its interface library. I think it would be intrusive a bit. Even if the genex to prune undefined libs for each `target_link_libraries` would be introduced, I also think the latter solution would be less intrusive.

@robert.maynard Thank you to let me know.

Although I haven’t tried master, I expect it would work.  
I have confirmed `$<COMPILE_ONLY>` could be emulated with like `target_link_libraries(B INTERFACE $<IF:$<BOOL:$<LINK_ONLY:1>>,,A>)`

As consistency to `CMAKE_LINK_WHAT_YOU_USE`, I think introducing an option might be introduced like `CMAKE_LINK_ONLY_DIRECT_USE`.
