Построение простого (hello-world-esque) примера использования опции ld-rpath с $ORIGIN

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

у меня проблемы с использованием 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

С

2 ответов


(я бы предпочел [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. исправить путь 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)

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

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

$ 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 директория, беги!--12--> (если он не будет работать, обеспечить make.sh обладает разрешением).

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


Примечания:

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

структура файла (после Я использую -l: который требует полного имени файла библиотеки (среди других причин, легче писать с переменными, когда все функции имеют одинаковый формат имени).
Это более распространенное использование -l, whereby -l<NAME> обозначает Либ.так.

ограничения

насколько мне известно (поправьте меня, если я ошибаюсь), нет способа добавить библиотеку внутри подкаталога в пути поиска (за исключением добавления этого каталога в качестве подкаталога). Это справедливо для обоих build-time (-L) и (-rpath) пути поиска.

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