Создание простого (Hello-World-esque) примера использования опции LD -Rpath с $ origin
Вопрос
Примечание: полный рабочий пример сейчас ниже. Первоначальный вопрос следует:
У меня проблемы с использованием 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
, Линкера выяснит, что вы намеревались, и поступит правильно. Но если вы собираетесь использовать необычные соглашения об именах, вам придется помочь:
Измените строку ссылки для библиотеки, чтобы явно установил Soname для вашей библиотеки, чтобы просто
foo.sh
:g++ -shared -Wl,-soname,foo.sh -o lib/foo.sh obj/foo.o
Исправьте 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
) пути поиска.
Так что, если у вас есть две библиотеки с одинаковым именем, но разные места, вы не сможете связать их обоих. (Надеюсь, я ошибаюсь или что это исправлено).