Создание простого (Hello-World-esque) примера использования опции LD -Rpath с $ origin

StackOverflow https://stackoverflow.com/questions/6311016

  •  26-10-2019
  •  | 
  •  

Вопрос

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

У меня проблемы с использованием LD -rpath параметр с $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: Который требует полного имени библиотечного файла (среди других причин, его проще скрасить с переменными, когда все функции принимают один и тот же формат имени).

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

Это было полезно?

Решение

(Я бы предпочел иметь [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 это путь (или набор путей), встроенный в двоичные файлы (общие библиотеки (.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 добавляет путь к время сборки Список пути поиска библиотеки. (Примечание: 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) пути поиска.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top