# RPATH not set, but necessary

**URL:** https://discourse.cmake.org/t/rpath-not-set-but-necessary/861
**Category:** Code
**Tags:** os:macos
**Created:** [March 25, 2020, 5:51pm UTC](https://discourse.cmake.org/t/rpath-not-set-but-necessary/861 "2020-03-25T17:51:50Z")
**Posts on this page:** 9
**Page:** 1

<div class="post-metadata">

### Author: ![CodingNickNick](https://discourse.cmake.org/user_avatar/discourse.cmake.org/codingnicknick/32/445_2.png) [@CodingNickNick](https://discourse.cmake.org/u/CodingNickNick)
#### Post date: [March 25, 2020, 5:51pm UTC](https://discourse.cmake.org/t/rpath-not-set-but-necessary/861/1 "2020-03-25T17:51:50Z")

</div>

I am linking an imported target against an executable, but the RPATH of the resulting executable is not set up correctly: when I run it, I get the ‘image not found’ error for this library. When I manually set the BUILD\_RPATH target property for the executable, everything runs fine, but I was wondering why it ‘does work’ for the few other shared libraries I’m linking: Qt5, and 2 of our own, which are linked via their path e.g. target\_link\_libraries(foo /some/path/to/lib.so). The target that does not ‘work’ is linked as a target, e.g. target\_link\_libraries(foo bar::bar).

Thanks in advance,

---

<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 25, 2020, 7:16pm UTC](https://discourse.cmake.org/t/rpath-not-set-but-necessary/861/2 "2020-03-25T19:16:56Z")

</div>

I suspect this is macOS (based on the “image not found” mention). Libraries which have `@rpath` as their ID get linked in expecting to get found via an `@rpath` entry. However, nothing ends up setting this on CMake’s side. There’s an issue (though I can’t find it right now) about having this rpath information be a new usage requirement that would allow CMake to make the right flag decisions.

---

<div class="post-metadata">

### Author: ![CodingNickNick](https://discourse.cmake.org/user_avatar/discourse.cmake.org/codingnicknick/32/445_2.png) [@CodingNickNick](https://discourse.cmake.org/u/CodingNickNick)
#### Post date: [March 25, 2020, 7:23pm UTC](https://discourse.cmake.org/t/rpath-not-set-but-necessary/861/3 "2020-03-25T19:23:25Z")

</div>

It’s macOS! 🍎

Okay, thanks! That’s helpful. So the only option for now is to propagate the BUILD\_RPATH requirements myself?

As for the other part of the question: how do the other targets achieve this? I read on the [RPATH page of the wiki](https://gitlab.kitware.com/cmake/community/-/wikis/doc/cmake/RPATH-handling):

> When building a target with RPATH, CMake determines the RPATH by  
> using the directories of all libraries to which this target links.

Shouldn’t this also happen for my bar::bar target, or is it because the LC\_ID\_DYLIB, the install name, contains @rpath that this mechanism doesn’t kick in or something?

Thanks again!

---

<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 25, 2020, 7:40pm UTC](https://discourse.cmake.org/t/rpath-not-set-but-necessary/861/4 "2020-03-25T19:40:47Z")

</div>

CMake doesn’t look at library IDs on macOS (as of now). In any case, `@rpath/foo/bar/baz.dylib` is possible (and done for frameworks), so a simple `dirname` isn’t the solution either. Other platforms don’t have this problem either by not having them (Windows) or library lookups being purely filename based (Linux and other ELF platforms) rather than supporting directory traversal like macOS does.

---

<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 25, 2020, 7:41pm UTC](https://discourse.cmake.org/t/rpath-not-set-but-necessary/861/5 "2020-03-25T19:41:07Z")

</div>

> [@CodingNickNick](#):
>
> So the only option for now is to propagate the BUILD\_RPATH requirements myself?

`target_link_options` is probably your best bet.

---

<div class="post-metadata">

### Author: ![CodingNickNick](https://discourse.cmake.org/user_avatar/discourse.cmake.org/codingnicknick/32/445_2.png) [@CodingNickNick](https://discourse.cmake.org/u/CodingNickNick)
#### Post date: [March 26, 2020, 8:31am UTC](https://discourse.cmake.org/t/rpath-not-set-but-necessary/861/6 "2020-03-26T08:31:57Z")

</div>

Thanks for the answers so far, very helpful!

My only remaining question is why there are some RPATHS in my executable then, but not for this one. CMake seems to use the dirname option when linking paths? I made a diff of the output of `otool -l` linking directly with the IMPORTED\_LOCATION instead of with the target:

```
$ diff -u /tmp/with-{target,path}
--- /tmp/with-target	2020-03-26 09:27:02.000000000 +0100
+++ /tmp/with-path	2020-03-26 09:28:59.000000000 +0100
@@ -1,7 +1,7 @@
 assimp-driver:
 Mach header
       magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
- 0xfeedfacf 16777223 3 0x80 2 20 1712 0x00218085
+ 0xfeedfacf 16777223 3 0x80 2 21 1832 0x00218085
 Load command 0
       cmd LC_SEGMENT_64
   cmdsize 72
@@ -218,7 +218,7 @@
 Load command 9
      cmd LC_UUID
  cmdsize 24
- uuid 01703D72-9DF2-3F50-B4B6-6B34D12D09E3
+ uuid E02E6587-E352-3DB5-9BAF-901D11700B5B
 Load command 10
        cmd LC_BUILD_VERSION
    cmdsize 32
@@ -267,14 +267,18 @@
 compatibility version 1.0.0
 Load command 17
           cmd LC_RPATH
+ cmdsize 120
+ path /Users/nick/build-circlelabsnl-Desktop_Qt_5_14_1_clang_64bit-Debug/external-libs/inst64/assimp-5.0.1/lib (offset 12)
+Load command 18
+ cmd LC_RPATH
       cmdsize 112
          path /Users/nick/build-circlelabsnl-Desktop_Qt_5_14_1_clang_64bit-Debug/external-libs/inst64/ml-0.1/bin (offset 12)
-Load command 18
+Load command 19
       cmd LC_FUNCTION_STARTS
   cmdsize 16
   dataoff 21968
  datasize 56
-Load command 19
+Load command 20
       cmd LC_DATA_IN_CODE
   cmdsize 16
   dataoff 22024

```

In other words: with `target_link_libraries(executable path)` the executable does get an RPATH as expected (and the executable can at least be started in the build dir) but with the `target_link_libraries(executable target)` it does not. Is this expected behavior, a bug, or is the imported target maybe missing a property or something?

Thanks again!

---

<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 26, 2020, 12:16pm UTC](https://discourse.cmake.org/t/rpath-not-set-but-necessary/861/7 "2020-03-26T12:16:22Z")

</div>

I think linking to paths may end up falling back on the ELF behavior. This works most of the time, but fails for frameworks that come bundled together (e.g., Qt5 binaries have an rpath at the bundle level and use directory traversal to get into `Frameworks/QtCore.framework`).

Cc: @brad.king

---

<div class="post-metadata">

### Author: ![CodingNickNick](https://discourse.cmake.org/user_avatar/discourse.cmake.org/codingnicknick/32/445_2.png) [@CodingNickNick](https://discourse.cmake.org/u/CodingNickNick)
#### Post date: [March 26, 2020, 1:34pm UTC](https://discourse.cmake.org/t/rpath-not-set-but-necessary/861/8 "2020-03-26T13:34:09Z")

</div>

While my solution may be specific to my problem here, I figured it might be useful to document it.

In the end I made an INTERFACE library that wraps the imported library and adds INTERFACE\_LINK\_OPTIONS:

```auto
add_library(SphereAssimp INTERFACE)
target_link_libraries(SphereAssimp INTERFACE assimp::assimp)
target_link_options(SphereAssimp INTERFACE "LINKER:-rpath,${LIBDIR}/lib")

```

This nicely propagates. One caveat: even targets that are only included in “implementation files” (.cpp, .c, .cc, whatever) must be target\_link\_libraries(PUBLIC) for this to propagate correctly. Link options are in that sense part of the ‘interface’, and if your consumers need it down the road, they need to be exposed, even if they don’t need other properties like their INTERFACE\_INCLUDE\_DIRS.

Thanks again, really happy to have this working! 🥳

---

<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 26, 2020, 2:44pm UTC](https://discourse.cmake.org/t/rpath-not-set-but-necessary/861/9 "2020-03-26T14:44:53Z")

</div>

Yeah, the need to have a usage requirement pierce`PRIVATE` dependencies for those that impose requirements on any end binary in the chain (`EXECUTABLE` or possibly a `MODULE`). I don’t know of the best way to do it.

`$<LINK_ONLY:>` can remove the interface or compile usage requirements at least.
