# PRIVATE vs PUBLIC shared library dependencies and INTERFACE\_LINK\_DIRECTORIES semantics

**URL:** https://discourse.cmake.org/t/private-vs-public-shared-library-dependencies-and-interface-link-directories-semantics/15458
**Category:** Code
**Created:** [January 14, 2026, 2:50pm UTC](https://discourse.cmake.org/t/private-vs-public-shared-library-dependencies-and-interface-link-directories-semantics/15458 "2026-01-14T14:50:41Z")
**Posts on this page:** 8
**Page:** 1

<div class="post-metadata">

### Author: ![Braden](https://discourse.cmake.org/user_avatar/discourse.cmake.org/braden/32/358_2.png) [@Braden](https://discourse.cmake.org/u/Braden)
#### Post date: [January 14, 2026, 2:50pm UTC](https://discourse.cmake.org/t/private-vs-public-shared-library-dependencies-and-interface-link-directories-semantics/15458/1 "2026-01-14T14:50:42Z")

</div>

Consider:

C –depends-on→ shared-lib-B –depends-on→ shared-lib-A

B doesn’t expose any parts of A to C; so, B’s dependency on A is `PRIVATE`. When C goes to link with B at build time, there are no symbols from A to resolve and the linker is happy.

But A and B end up being installed to different directories. When running C, its `INTERFACE_LINK_DIRECTORIES` only includes B’s installation directory because B’s dependency on A is `PRIVATE`, AFAICT. So, the run-time linker cannot find A and C fails to run.

Should A’s install directory be included in B’s `INTERFACE_LINK_DIRECTORIES` even though A is a `PRIVATE` dependency?

I suppose the counterargument to this is: `INTERFACE_LINK_DIRECTORIES` is only concerned with what’s needed to resolve things at build-time. If that’s the case, what, then, should clients be using to derive a correct `LD_LIBRARY_PATH` to run C?

---

<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: [January 14, 2026, 8:44pm UTC](https://discourse.cmake.org/t/private-vs-public-shared-library-dependencies-and-interface-link-directories-semantics/15458/2 "2026-01-14T20:44:26Z")

</div>

On non-Windows systems, clients shouldn’t be needing to set `LD_LIBRARY_PATH` or similar at all. Set up your RPATH details and rely on those instead. That is far more reliable and convenient for consumers, as long as all your dependencies also set up their RPATH correctly (which third party vendors often don’t, unfortunately).

I don’t have a solution for you for Windows, sorry. It’s lack of RPATH support is a constant PITA.

---

<div class="post-metadata">

### Author: ![Braden](https://discourse.cmake.org/user_avatar/discourse.cmake.org/braden/32/358_2.png) [@Braden](https://discourse.cmake.org/u/Braden)
#### Post date: [January 15, 2026, 5:06am UTC](https://discourse.cmake.org/t/private-vs-public-shared-library-dependencies-and-interface-link-directories-semantics/15458/3 "2026-01-15T05:06:58Z")

</div>

Historically I’ve tended to avoid `RPATH` due to concerns with relocatability of binaries as well as its effect on expected behavior when `LD_LIBRARY_PATH` is used. I’m willing to entertain the notion that these concerns are outdated or otherwise misinformed.

My current use case is Conan, where each package is effectively “installed” under its own prefix. (And, yes, I’m well aware of the `Virtual[Build|Run]Environment` stuff; but it comes with its own set of inconveniences that I am hoping to avoid by solving this at the CMake level.) I have gotten rather far by inspecting `INTERFACE_LINK_DIRECTORIES` at the CMake level; but it does require that `PRIVATE` shared library dependencies be explicitly accounted for in the consumer’s `INTERFACE_LINK_DIRECTORIES`. Am I correct that the `RPATH` solution would involve a similar explicit propagation of a `PRIVATE` shared library dependency’s `INTERFACE_LINK_DIRECTORIES` to the consumer’s `INSTALL_RPATH`?

(And fortunately, Windows is not a concern.)

---

<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: [January 15, 2026, 8:09pm UTC](https://discourse.cmake.org/t/private-vs-public-shared-library-dependencies-and-interface-link-directories-semantics/15458/4 "2026-01-15T20:09:14Z")

</div>

> [@Braden](#):
>
> Historically I’ve tended to avoid `RPATH` due to concerns with relocatability of binaries as well as its effect on expected behavior when `LD_LIBRARY_PATH` is used. I’m willing to entertain the notion that these concerns are outdated or otherwise misinformed.

Old RPATH doesn’t play nice with environment variables like `LD_LIBRARY_PATH`. New RUNPATH does play nice, and my understanding is that most linkers will now embed RUNPATH by default instead of RPATH. You can explicitly state which of the two behaviors you want with linker flags like `--enable-new-dtags`, but these days, that’s unlikely to be necessary. I talked a bit about the RPATH / RUNPATH differences in my [2019 CppCon talk](https://crascit.com/2019/10/16/cppcon-2019-deep-cmake-for-library-authors/), I think somewhere in the back half of that talk.

The Conan case is more interesting because, as you observed, each package is installed in its own separate directory. That means the relative path to other dependencies no longer follows the more standard layout that you’d get if they were collocated like for packages distributed as part of the OS. I don’t know how Conan manages the RPATH details of its packages, but I haven’t come across anything in the various recipes and generated files that seem to do anything special (but I’ve been working mostly with static libraries via Conan). I can’t comment on your `INTERFACE_LINK_DIRECTORIES` approach, I can’t say I’ve ever used that directly myself. I don’t know if the `INSTALL_RPATH_USE_LINK_PATH` target property and its associated `CMAKE_INSTALL_RPATH_USE_LINK_PATH` variable might be closer to what you’re looking for or not.

---

<div class="post-metadata">

### Author: ![AnthonyD973](https://discourse.cmake.org/user_avatar/discourse.cmake.org/anthonyd973/32/3130_2.png) [@AnthonyD973](https://discourse.cmake.org/u/AnthonyD973)
#### Post date: [January 15, 2026, 11:58pm UTC](https://discourse.cmake.org/t/private-vs-public-shared-library-dependencies-and-interface-link-directories-semantics/15458/5 "2026-01-15T23:58:34Z")

</div>

> [@Braden](#):
>
> Historically I’ve tended to avoid `RPATH` due to concerns with relocatability of binaries as well as its effect on expected behavior when `LD_LIBRARY_PATH` is used.

Another advantage or the `RUNPATH` is its natural ability to allow users to replace the versions of the libraries by their own versions by setting `LD_LIBRARY_PATH`. Since the ability to do this is a requirement of some open-source licenses (some LGPL ones I think?), if your library has such a license then building your libraries with `RUNPATH` would directly support e.g. closed-source consumers.

(I’m not a lawyer; this is not legal advice! 😄)

---

<div class="post-metadata">

### Author: ![Braden](https://discourse.cmake.org/user_avatar/discourse.cmake.org/braden/32/358_2.png) [@Braden](https://discourse.cmake.org/u/Braden)
#### Post date: [February 13, 2026, 11:15pm UTC](https://discourse.cmake.org/t/private-vs-public-shared-library-dependencies-and-interface-link-directories-semantics/15458/6 "2026-02-13T23:15:28Z")

</div>

From what I can tell, it seems that `RPATH`/`RUNPATH` solve a problem for _intra_package dependencies (i.e., everything installed under a single prefix, but perhaps at arbitrary locations under that prefix). They don’t seem to provide a solution for _inter_package dependencies (i.e., things installed to potentially different prefixes).

It does seem to me that CMake should be providing better support for this. The executables run by the `test` target could very easily require such augmentation of `LD_LIBRARY_PATH`. And CMake already has the information it needs in `INTERFACE_LINK_DIRECTORIES`, with the caveat that the `INTERFACE_LINK_DIRECTORIES` of `PRIVATE` dependencies don’t get propagated in that property. Perhaps introduce a new property where these directories are _always_ propagated? `FULL_INTERFACE_LINK_DIRECTORIES` or some such?

This situation feels analogous to the way `PRIVATE` must be treated when building/using static libraries.

---

<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: [February 14, 2026, 4:27am UTC](https://discourse.cmake.org/t/private-vs-public-shared-library-dependencies-and-interface-link-directories-semantics/15458/7 "2026-02-14T04:27:24Z")

</div>

Keep in mind that ideally projects shouldn’t use `LINK_DIRECTORIES` or `INTERFACE_LINK_DIRECTORIES` at all. For robustness reasons, CMake prefers to link libraries by the full path to the library, not rely on the linker search path.

---

<div class="post-metadata">

### Author: ![Braden](https://discourse.cmake.org/user_avatar/discourse.cmake.org/braden/32/358_2.png) [@Braden](https://discourse.cmake.org/u/Braden)
#### Post date: [February 14, 2026, 2:23pm UTC](https://discourse.cmake.org/t/private-vs-public-shared-library-dependencies-and-interface-link-directories-semantics/15458/8 "2026-02-14T14:23:30Z")

</div>

> Keep in mind that ideally projects shouldn’t use `LINK_DIRECTORIES` or `INTERFACE_LINK_DIRECTORIES` at all. For robustness reasons, CMake prefers to link libraries by the full path to the library, not rely on the linker search path.

I think “ideally” might be doing some heavy lifting here. (What, exactly, is the “ideal” scenario? One where everything is installed under the same prefix and we could simply dispense with large swaths of logic supporting other situations?)

If, for robustness reasons, CMake prefers to convey the full path of the library to the linker at link time, that’s just fine (and mostly, I’d suggest, an implementation detail of CMake). But that full path came from somewhere; and there’s a fairly good chance that CMake had, in some fashion, to compose it from a directory and a library name. Whether CMake or the linker is solving this, it’s the same problem.
