Question

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?

Was it helpful?

Solution

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.

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top