# What is the use of target\_link\_libraries( ... PUBLIC ... )?

**URL:** https://discourse.cmake.org/t/what-is-the-use-of-target-link-libraries-public/10839
**Category:** Usage
**Created:** [May 11, 2024, 5:35pm UTC](https://discourse.cmake.org/t/what-is-the-use-of-target-link-libraries-public/10839 "2024-05-11T17:35:24Z")
**Posts on this page:** 8
**Page:** 1

<div class="post-metadata">

### Author: ![dabrahams](https://discourse.cmake.org/user_avatar/discourse.cmake.org/dabrahams/32/4265_2.png) [@dabrahams](https://discourse.cmake.org/u/dabrahams)
#### Post date: [May 11, 2024, 5:35pm UTC](https://discourse.cmake.org/t/what-is-the-use-of-target-link-libraries-public/10839/1 "2024-05-11T17:35:24Z")

</div>

If I’m reading the documentation correctly, the difference between the `target_link_libraries` signature without `PUBLIC|PRIVATE|INTERFACE` and the one with `PUBLIC` is that the former propagates the link dependency transitively and the latter does not. That makes me wonder when one wants to use `PUBLIC`. It seems to me that means in the following, whatever properties of the code cause `E` to need to link `A` also cause `Y` to need to link `A`, and `Y` should therefore fail to link, while `X` links just fine.

_if_ I’m understanding that correctly, it seems like `PUBLIC` serves no purpose when used with `target_link_libraries`. In fact it seems like it’s never what you want, and a huge footgun because the developer of `B` may never try to create two levels of dependents on `B`. Am I misunderstanding the situation?

```cmake
# Create (X -> D -> C -> A) and (Y -> E -> B -> PUBLIC A)
add_library(A ...)

add_library(B ...)
target_link_libraries(B PUBLIC A)

add_library(C ...)
target_link_libraries(C A)

add_library(D ...)
target_link_libraries(D C)

add_library(E ...)
target_link_libraries(E B)

add_executable(X ...)
target_link_libraries(X D)

add_executable(Y ...)
target_link_libraries(Y E)

```

---

<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: [May 13, 2024, 1:49pm UTC](https://discourse.cmake.org/t/what-is-the-use-of-target-link-libraries-public/10839/2 "2024-05-13T13:49:46Z")

</div>

`PUBLIC` propagates the linking transitively too; that is its primary purpose. The docs say so, albeit in a rather jargon-y way:

> Libraries and targets following `PUBLIC` are linked to, **and are made part of the link interface.**

The emphasised (by me) part means that the dependency becomes part of the link interface, i.e. anything which links to the consuming target will also link against the PUBLIC dependency.

My rule of thumb is to never use the legacy (i.e. keywordless) signature of `target_link_libraries()`, and always specify `PRIVATE`, `PUBLIC`, or `INTERFACE`, as applicable.

---

<div class="post-metadata">

### Author: ![dabrahams](https://discourse.cmake.org/user_avatar/discourse.cmake.org/dabrahams/32/4265_2.png) [@dabrahams](https://discourse.cmake.org/u/dabrahams)
#### Post date: [May 13, 2024, 7:13pm UTC](https://discourse.cmake.org/t/what-is-the-use-of-target-link-libraries-public/10839/3 "2024-05-13T19:13:15Z")

</div>

> [@Angew](#):
>
> `PUBLIC` propagates the linking transitively too; that is its primary purpose. The docs say so, albeit in a rather jargon-y way:
> 
> > Libraries and targets following `PUBLIC` are linked to, **and are made part of the link interface.**

Is “link interface” described somewhere as having this transitive property? If not, I don’t think the implication holds. Normally an “interface” only applies between adjacent things in a dependency graph. I can find no special definition for “link interface” in the CMake docs.

I don’t know what it means, in the current implementation, to be “in the link interface” of a target but I think if it’s going to be a useful abstraction it would need to propagate differently for static and shared libraries.

> The emphasised (by me) part means that the dependency becomes part of the link interface, i.e. anything which links to the consuming target will also link against the PUBLIC dependency.

Yes, that much is clearly implied; what’s not implied AFAICT is that the same applies to things that link to _things that link to_ the consuming target (`Y` in my example).

> My rule of thumb is to never use the legacy (i.e. keywordless) signature of `target_link_libraries()`, and always specify `PRIVATE`, `PUBLIC`, or `INTERFACE`, as applicable.

Nothing in the docs marks that signature a “legacy” or deprecated and in fact there are other signatures in the `target_link_libraries` doc that _are_ clearly marked as “legacy,” so I think this signature needs to be viewed as legitimate and still useful. Because one form is not documented in terms of the other, I conclude that its semantics must differ from those of `PUBLIC`. That’s one of the things that led me to think `PUBLIC` doesn’t have the transitive property. If I’ve got that wrong, I want to know how the semantics differ.

---

<div class="post-metadata">

### Author: ![dabrahams](https://discourse.cmake.org/user_avatar/discourse.cmake.org/dabrahams/32/4265_2.png) [@dabrahams](https://discourse.cmake.org/u/dabrahams)
#### Post date: [May 13, 2024, 7:55pm UTC](https://discourse.cmake.org/t/what-is-the-use-of-target-link-libraries-public/10839/4 "2024-05-13T19:55:50Z")

</div>

FWIW, my experiments with [this example](https://gist.github.com/aa4d81d1230a1f4b802507912ab8a418.git) (you can git clone that URL), lead me to believe that using `PUBLIC` is indeed equivalent to using the keywordless signature, and works as @Angew describes. Also that the propagation stops at the boundary of any `PRIVATE` library dependency (you can observe that by `PRIVATE`-izing `D -> C` or `E -> B`).

Maybe the documentation just needs to be updated to clarify all these things. I’d still like authoritative confirmation that my current understanding is correct.

---

<div class="post-metadata">

### Author: ![adaldev](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/a/9dc877/32.png) [@adaldev](https://discourse.cmake.org/u/adaldev)
#### Post date: [May 14, 2024, 9:04am UTC](https://discourse.cmake.org/t/what-is-the-use-of-target-link-libraries-public/10839/5 "2024-05-14T09:04:02Z")

</div>

does it help? [the usage of target\_include\_directories vs target\_link\_libraries - #4 by Joseph](https://discourse.cmake.org/t/the-usage-of-target-include-directories-vs-target-link-libraries/7914/4)

---

<div class="post-metadata">

### Author: ![craig.scott](https://discourse.cmake.org/user_avatar/discourse.cmake.org/craig.scott/32/20_2.png) [@craig.scott](https://discourse.cmake.org/u/craig.scott)
#### Post date: [May 14, 2024, 10:17am UTC](https://discourse.cmake.org/t/what-is-the-use-of-target-link-libraries-public/10839/6 "2024-05-14T10:17:15Z")

</div>

> [@dabrahams](#):
>
> FWIW, my experiments with [this example](https://gist.github.com/aa4d81d1230a1f4b802507912ab8a418.git) (you can git clone that URL), lead me to believe that using `PUBLIC` is indeed equivalent to using the keywordless signature

I don’t recall the exact scenario, but my recollection is that in certain specific circumstances, leaving out the keyword can result in effectively getting `PRIVATE` behavior. It isn’t always going to be `PUBLIC`. I have the following sentence in my Professional CMake book, but I no longer recall the origins of how I arrived at that conclusion:

> In particular, if a project defines a chain of library dependencies with a mix of old and new command forms, the old-style form will generally be treated as PRIVATE.

---

<div class="post-metadata">

### Author: ![dabrahams](https://discourse.cmake.org/user_avatar/discourse.cmake.org/dabrahams/32/4265_2.png) [@dabrahams](https://discourse.cmake.org/u/dabrahams)
#### Post date: [May 15, 2024, 12:05am UTC](https://discourse.cmake.org/t/what-is-the-use-of-target-link-libraries-public/10839/7 "2024-05-15T00:05:43Z")

</div>

> [@craig.scott](#):
>
> I don’t recall the exact scenario, but my recollection is that in certain specific circumstances, leaving out the keyword can result in effectively getting `PRIVATE` behavior.

Interesting data point. [Here’s](https://gitlab.kitware.com/cmake/cmake/-/issues/25981#note_1520611) another: @brad.king seeming to imply (with parentheses) that is not the case. 🤷

---

<div class="post-metadata">

### Author: ![brad.king](https://discourse.cmake.org/user_avatar/discourse.cmake.org/brad.king/32/11_2.png) [@brad.king](https://discourse.cmake.org/u/brad.king)
#### Post date: [May 15, 2024, 1:28pm UTC](https://discourse.cmake.org/t/what-is-the-use-of-target-link-libraries-public/10839/8 "2024-05-15T13:28:45Z")

</div>

`target_link_libraries(A B)`'s affect on `A` is the same as `target_link_libraries(A PUBLIC B)`. However, if there are multiple calls to `target_link_libraries(A ...)`, they all need to be either plain or keyword. [CMP0023](https://cmake.org/cmake/help/v3.29/policy/CMP0023.html) disallowed mixing them. These days the `PUBLIC/PRIVATE/INTERFACE` keywords are preferred. As discussed in [CMake Issue 25981](https://gitlab.kitware.com/cmake/cmake/-/issues/25981), the `target_link_libraries` documentation could use an overhaul to present the modern conventions first.
