RPATH не удалось расширить

Я создал исполняемый файл (названный демультиплексором) в OS X, который всегда не загружается, и я не могу понять, почему:

$ ./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

Фреймворк находится рядом с исполняемым файлом. Otool показывает следующее:

$ 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)

И:

$ otool -L demux 
demux:
@rpath/sfeMovie.framework/Versions/2.0/sfeMovie (compatibility version 2.0.0, current version 2.0.0)

Учитывая это, я подумал, что добавление @executable_path к пути поиска исполняемого файла во время выполнения позволит ему просматривать любой фреймворк и библиотеку, относительное имя установки которых просто начинается с префикса @rpath (например, в @rpath/sfeMovie.framework/…) и который находится рядом с исполняемым файлом. Чтобы убедиться, что этот путь поиска во время выполнения правильный:

$ otool -l demux | grep LC_RPATH -A 2
      cmd LC_RPATH
  cmdsize 32
     path @executable_path (offset 12)

Но это не удается, и я не знаю, почему. Для меня @executable_path/sfeMovie.framework/Versions/2.0/sfeMovie выглядит как правильный путь, но он все равно не работает… есть ли неправильное использование @rpath или @executable_path?


person Ceylo    schedule 07.03.2014    source источник


Ответы (2)


Я смог воспроизвести вашу проблему с помощью быстрого тестового проекта. Это было исправлено, когда я добавил косую черту в конце параметра сборки LD_RUNPATH_SEARCH_PATH.

Вместо:

@executable_path

тебе стоит попробовать

@executable_path/

Вывод из otool -l теперь выглядит так:

      cmd LC_RPATH
  cmdsize 32
     path @executable_path/ (offset 12)

Как правило, вы можете проверить свой исполняемый файл верхнего уровня (в данном случае «демультиплексор») с помощью моего скрипта анализатора dyld по адресу https://github.com/liyanage/macosx-shell-scripts/blob/master/checklibs.py

./checklibs.py demux

Этот инструмент пытается точно воспроизвести логику разрешения dyld. Обычно он может дать подсказку о том, какие ссылки не работают, но в этом случае он не улавливает проблему с отсутствующей косой чертой в конце. Я обновлю его соответствующим образом, чтобы он соответствовал поведению dyld.

person Marc Liyanage    schedule 08.03.2014
comment
О, это было!!! Большое спасибо!! Это больше похоже на ошибку dyld, так как печатает правильный путь расширения, но не загружается… в любом случае, решено :) Также посмотрю ваш скрипт :) - person Ceylo; 08.03.2014
comment
Рад слышать, что это сработало. Я согласен, такое поведение не соответствует документации. - person Marc Liyanage; 08.03.2014
comment
Похоже, что @executable_path (без /) хорошо работает на 10.9 El Capitan, хотя я могу подтвердить, что на 10.7 Mavericks вам нужно использовать @exectuable_path/ (у меня есть приложение, скомпилированное для цели 10.7, работающее на 10.9, но не на 10.7 - потратив несколько часов на поиск проблемы Я узнал, что проблема была в /...) Спасибо, @marc-liyanage! - person pawel; 15.12.2016

demux содержит ссылку @rpath, а RPATH содержит @executable_path, но справочная страница dyld говорит: «Вы даже можете добавить путь к команде загрузки LC_RPATH, который начинается с @loader_path», что, по-видимому, подразумевает, что @executable_path не разрешено в RPATH.

Если demux содержит @executable_path напрямую, а не косвенно к RPATH, то это сработает.

См. man dyld и < href="http://www.opensource.apple.com/source/dyld/dyld-239.3/src/dyld.cpp" rel="nofollow">dyld.cpp, чтобы узнать подробности.

Если это demux.c:

#include <stdio.h>

int foo();

int main() {
    printf("%d\n", foo());
}

а это lib/sfeMovie.c:

int foo() {
    return 42;
}

а это твой 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

Тогда demux правильно загружает библиотеку, даже если текущий каталог не тот, который содержит demux. Однако, если sfeMovie ссылается на кучу других библиотек, вам все равно может понадобиться RPATH.

person andrewdotn    schedule 07.03.2014
comment
В вашей схеме пользователь вынужден поместить библиотеку в каталог lib рядом с исполняемым файлом. И если он этого не хочет, ему придется отредактировать dylib перед связыванием с ним (или отредактировать исполняемый файл после каждого шага связывания). Я забыл уточнить этот момент: я хочу, чтобы пользователь сам выбирал, куда поместить фреймворк, поэтому я пытаюсь использовать rpath. Спасибо хоть :) - person Ceylo; 08.03.2014