3

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?

Ceylo
  • 362
  • 2
  • 11

2 Answers2

4

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.

Marc Liyanage
  • 4,601
  • 2
  • 28
  • 28
  • Oh that was it!!! Thank you so much!! It does more looks like a dyld bug as it prints a valid expansion path but fails to load… anyway, solved :) Will have a look at your script too :) – Ceylo Mar 08 '14 at 11:17
  • Glad to hear it worked. I agree, this behavior does not match the documentation. – Marc Liyanage Mar 08 '14 at 17:25
  • 1
    It looks like `@executable_path` (without "/") works well on 10.9 El Capitan, although I can confirm that on 10.7 Mavericks you have to use `@exectuable_path/` (I have app compiled to 10.7 target working on 10.9 but not on 10.7 - after spending few hours finding issue I found out that the "/" was the problem...) Thanks @marc-liyanage! – pawel Dec 15 '16 at 18:54
0

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.

andrewdotn
  • 32,721
  • 10
  • 101
  • 130
  • With your scheme, the user is forced to put the library in a lib directory next to the executable. And if he does not want that he'll have to edit the dylib before linking against it (or edit the executable after every link step). I forgot to give a precision about this point: I want to let he user choose where to put the framework, which is why I'm trying to use rpath. Thanks though :) – Ceylo Mar 08 '14 at 10:25