Создание простого (hello-world-esque) примера использования опции ld -rpath с $ ORIGIN - PullRequest
16 голосов
/ 10 июня 2011

Примечание. Полный рабочий пример приведен ниже. Исходный вопрос следует:

У меня проблемы с использованием параметра -rpath ld с $ORIGIN.
Поскольку я не смог найти полный пример, я подумал, что постараюсь написать один сам, чтобы я и другие могли использовать его позже. Как только я получу это, я приведу это в порядок.

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

В примере проекта создается одна общая библиотека и один исполняемый файл, который ссылается на указанную библиотеку.
Он очень маленький (3 файла, 22 строки, включая buildscript).
Вы можете скачать проект с здесь


Структура файла (перед сборкой):

  • project/
    • src/
      • foo.cpp
      • main.cpp
    • make.sh

project/src/foo.cpp


int foo()
  { return 3; }

project/src/main.cpp


int foo();

#include <iostream>
int main()
  {
    std::cout << foo() << std::endl;
    return 0;
  }

project/make.sh


# Make directories:
mkdir -p -v obj
mkdir -p -v lib
mkdir -p -v run

# Build the library:
g++ -c -o obj/foo.o src/foo.cpp -fPIC
g++ -shared -o lib/foo.sh obj/foo.o

# Build the executable:
g++ -c -o obj/main.o src/main.cpp
g++ -o run/main.run obj/main.o -Wl,-rpath,'$ORIGIN/../../lib' -Llib -l:foo.sh

Из каталога project запустите make.sh (убедитесь, что он исполняемый).


Файловая структура (после сборки):

  • project/
    • src/
      • foo.cpp
      • main.cpp
    • obj/
      • foo.o
      • main.o
    • lib/
      • foo.so
    • run/
      • main.run
    • make.sh

run/main.run теперь должен загружать lib/foo.sh при выполнении из любого места.


Проблемы

В настоящее время это работает только частично.
Файлы компилируются и связываются нормально, но при запуске из какого-либо каталога, кроме project (что и является смыслом упражнения), ссылка не устанавливается.

Проверка main.run с readelf -d показывает:
0x0000000000000001 (NEEDED) Shared library: [lib/foo.sh]
0x000000000000000f (RPATH) Library rpath: [$ORIGIN/../../lib] Который выглядит близко (я бы предпочел [foo.sh], чем [lib/foo.sh], но я исправлю это позже).

AFAICT $ORIGIN в -Wl,-rpath,'$ORIGIN/../../lib' означает project/run/main.run, поэтому этот rpath должен стать project/lib.

Я пытался $ORIGIN/.., $ORIGIN/../lib, $ORIGIN/../.., $ORIGIN/../../lib безрезультатно.

Примечание: я использую -l:, для которого требуется полное имя файла библиотеки (среди прочих причин проще создавать сценарии с переменными, когда все функции принимают одинаковый формат имени).

Кто-нибудь знает, почему это не работает?
Или, альтернативно, кто-нибудь знает или знает полный рабочий пример?

Ответы [ 2 ]

6 голосов
/ 11 июня 2011

(Я бы предпочел [foo.sh], чем [lib/foo.sh], но я исправлю это позже).

Большая часть вашей проблемы: / в названииостанавливает динамический компоновщик от выполнения магии rpath.

(Ваш rpath также неверен. Подумайте об этом: из оболочки, если вы в данный момент находились в каталоге, где находится ваш исполняемый файл, как бы вы попали в каталоггде ваша библиотека? Здесь вам нужно cd ../lib. Таким образом, ваш rpath должен быть $ORIGIN/../lib.)

Если вы построили свой объект как libfoo.so и связали его с -Llib -lfoo, компоновщикбудет работать, что вы хотели, и делать правильные вещи.Но если вы собираетесь использовать необычные соглашения об именах, вам придется выручить:

  1. Измените строку ссылки для библиотеки, чтобы явно установить SONAME для вашей библиотеки простоfoo.sh:

    g++ -shared -Wl,-soname,foo.sh -o lib/foo.sh obj/foo.o

  2. Fix rpath:

    g++ -o run/main.run obj/main.o -Wl,-rpath,'$ORIGIN/../lib' -Llib -l:foo.sh

Полезно запустить ldd main/main.run, чтобы посмотреть, что происходит.В исходном неудачном случае вы увидите что-то вроде:

    lib/foo.sh (0xNNNNNNNN)

(отсутствие каких-либо => /some/resolved/path, показывающих, что не выполняется разрешение пути).В фиксированном случае вы увидите что-то вроде:

    foo.sh => /your/path/to/run/../lib/foo.sh (0xNNNNNNNN)
5 голосов
/ 12 июня 2011

Это пример связывания относительного пути (с ld) с использованием $ORIGIN в rpath.

rpath - это путь (или набор путей), встроенных в двоичные файлы (общие библиотеки (.so) и исполняемые файлы).
Эти пути являются основными путями поиска для общих библиотек, с которыми двоичный файл должен быть связан во время выполнения.

$ ORIGIN - это потенциальный начальный каталог для пути rpath.Он разрешается в каталог, содержащий исполняемый файл.(например: $ORIGIN/lib)

В примере проекта создается одна общая библиотека и один исполняемый файл, который ссылается на указанную библиотеку с использованием rpath и $ORIGIN.
. Скачать проект можно по адресу здесь..


Структура файла (до сборки):

  • project/
    • src/
      • foo.cpp
      • main.cpp
    • make.sh

project/src/foo.cpp


int foo()
  { return 3; }

project/src/main.cpp


int foo();

#include <iostream>
int main()
  {
    std::cout << foo() << std::endl;
    return 0;
  }

project/make.sh


# Make directories:
mkdir -p -v obj
mkdir -p -v lib/dir
mkdir -p -v run

# Build the library:
g++ -c -o obj/foo.o src/foo.cpp -fPIC
g++ -shared -o lib/dir/foo.so -Wl,-soname,foo.so obj/foo.o

# Build the executable:
g++ -c -o obj/main.o src/main.cpp
g++ -o run/main.run obj/main.o -Wl,-rpath,'$ORIGIN/../lib/dir' -Llib/dir -l:foo.so

Из каталога project запустите make.sh (если он не запустится, убедитесь, что у make.sh есть разрешения на выполнение).

Если все прошло нормально, main.run теперь должен загружать lib/dir/foo.so при выполнении независимо от абсолютного пути к project (вы можете переместить его куда угодно) и независимо от текущего рабочего каталога (выможет запускать его из любого места).


Примечания:

  • -fPIC указывает компилятору создавать перемещаемые объектные файлы (объектные файлы встраиваются в общийбиблиотеки должны быть перемещаемыми).
  • -Wl,-soname,<NAME> встраивает <NAME> в созданную библиотеку.Это должно совпадать с именем, которое вы указываете для параметров -l или -l: при ссылке на эту библиотеку.
  • -Wl,-rpath,'<PATH>' встраивает <PATH> в сгенерированную библиотеку в качестве пути поиска библиотеки времени выполнения (или rpath - см. Выше).
  • -L добавляет путь к build-время список путей поиска библиотеки.(Примечание: rpath не имеет значения во время сборки, -L не имеет значения во время выполнения).
  • -l: добавляет имя файла (без пути) библиотеки для ссылки.(Аналогично -l, за исключением того, что -l: требует полного имени файла.

Структура файла (после сборки):

  • project/
    • src/
      • foo.cpp
      • main.cpp
    • obj/
      • foo.o
      • main.o
    • lib/
      • dir/
        • foo.so
    • run/
      • main.run
    • make.sh

Примечание: яиспользование -l:, которое требует полного имени файла библиотеки (среди прочих причин проще создавать сценарии с переменными, когда все функции принимают одинаковый формат имени).
Чаще используется -l, тогда как -l<NAME> обозначает lib.so.

Ограничения

Насколько я знаю (поправьте меня, если я ошибаюсь), нет способа добавить библиотеку в подкаталог в пути поиска (кроме добавлениятоткаталог как подпуть).Это верно как для путей поиска во время сборки (-L), так и во время выполнения (-rpath).

Так что если у вас есть две библиотеки с одинаковыми именами, но в разных местах, вы не будетевозможность связать их обоих.(Надеюсь, я ошибаюсь или что это исправлено).

...