Reputation: 412
I have built an executable (named demux) on OS X that always fails to load and I cannot find why:
$ ./demux
RPATH failed to expanding @rpath/sfeMovie.framework/Versions/2.0/sfeMovie to: @executable_path/sfeMovie.framework/Versions/2.0/sfeMovie
dyld: Library not loaded: @rpath/sfeMovie.framework/Versions/2.0/sfeMovie
Referenced from: …current_dir/./demux
The framework is next to the executable. Otool shows the following :
$ otool -L sfeMovie.framework/Versions/2.0/sfeMovie
sfeMovie.framework/Versions/2.0/sfeMovie:
@rpath/sfeMovie.framework/Versions/2.0/sfeMovie (compatibility version 2.0.0, current version 2.0.0)
And:
$ otool -L demux
demux:
@rpath/sfeMovie.framework/Versions/2.0/sfeMovie (compatibility version 2.0.0, current version 2.0.0)
Given that, I thought that adding @executable_path to the runtime search path of the executable would allow it to look at any framework and library whose relative install name is simply prefixed with @rpath (like in @rpath/sfeMovie.framework/…) and which is next to the executable. To make sure that this runtime search path is correct:
$ otool -l demux | grep LC_RPATH -A 2
cmd LC_RPATH
cmdsize 32
path @executable_path (offset 12)
But this fails and I don't know why. To me @executable_path/sfeMovie.framework/Versions/2.0/sfeMovie looks like the correct path but it still fails… is there any misuse of @rpath or @executable_path?
Upvotes: 3
Views: 1592
Reputation: 4681
I was able to reproduce your issue with a quick test project. It was fixed when I appended a trailing slash to the LD_RUNPATH_SEARCH_PATH
build setting.
Instead of:
@executable_path
you should try
@executable_path/
The output from otool -l
now looks like this:
cmd LC_RPATH
cmdsize 32
path @executable_path/ (offset 12)
In general, you can check your toplevel executable (in this case "demux") with my dyld analyzer script at https://github.com/liyanage/macosx-shell-scripts/blob/master/checklibs.py
./checklibs.py demux
This tool attempts to faithfully reproduce dyld
's resolution logic. It can usually provide a hint about which references don't work, but in this case it doesn't catch the issue with the missing trailing slash. I will update it accordingly to match dyld
's behavior.
Upvotes: 4
Reputation: 34873
demux
contains an @rpath
link, and RPATH contains @executable_path
, but the dyld man page says, “You can even add a LC_RPATH
load command path that starts with @loader_path
” which seems to imply that @executable_path
isn’t allowed in RPATH.
If demux
contains @executable_path
directly instead of indirecting to RPATH
, then it will work.
See man dyld and dyld.cpp for the gory details.
If this is demux.c
:
#include <stdio.h>
int foo();
int main() {
printf("%d\n", foo());
}
and this is lib/sfeMovie.c
:
int foo() {
return 42;
}
and this is your Makefile
:
run:
$(MAKE) clean
$(MAKE) demux
cd .. && "$(shell pwd -P)/demux"
demux: demux.o lib/sfeMovie.dylib
cc -o $@ $^
install_name_tool \
-change \
'lib/sfeMovie.dylib' \
'@executable_path/lib/sfeMovie.dylib' \
$@
lib/sfeMovie.dylib: lib/sfeMovie.o
cc -shared -o $@ $<
clean::
rm -f demux *.o lib/*.o lib/*.dylib
Then demux
loads the library correctly, even if the current directory is not the one containing demux
. However if sfeMovie
is referencing a bunch of other libraries then you may still need an RPATH.
Upvotes: 0