2015-04-02 6 views
1

У меня есть libA.so, который зависит от libB.so, который находится в ../libB/ (от libA.c). Я пытаюсь скомпилировать вещи таким образом, что мне не нужно устанавливать какие-либо переменные среды. У меня есть:Как установить путь, который библиотека .so будет искать для других .so библиотек?

cc -std=c99 -c -fPIC -I../libB/ -Wall libA.c 
    cc -std=c99 -shared libA.o -L../libB -lB -o libA.so 

Это компилируется в порядке. Когда я запускаю программу, которая загружает Либ с dlopen я получаю:

dyld: Library not loaded: libB.so 
    Referenced from: libA/libA.so 
    Reason: image not found 
Trace/BPT trap: 5 

так Либ не находит libB во время выполнения. Я нашел это решение изменить путь выполнения на Mac OS X:

install_name_tool -смена libB.so @loader_path /../ libB.so libA.so

, но я хотел бы найти решение, которое будет работать как на OS X, так и на Linux. Опять же, я пытаюсь сделать конечного пользователя как можно меньше, поэтому я не хочу, чтобы они устанавливали переменные окружения, и мне нужно использовать cc (для меня это версия LLVM для Apple, версия 4.2 (clang-425.0 .27) (на основе LLVM 3.2svn), и я хотел бы, чтобы он тоже работал на Linux, поэтому предположительно cc = gcc там).

EDIT Моя проблема может быть сложнее, чем я понял. Я делаю эту динамическую библиотеку на C, но пытаюсь использовать ее изнутри python. Я могу использовать libB.so (который не имеет зависимостей) изнутри python без проблем, и когда я загружаю libA.so изнутри python, он находит его (см. Выше), просто в тот момент libA.so понимает, что он не " t знать, где найти libB.so. Если я правильно понимаю ваши ответы ниже, решения зависят от установки пути компоновщика при компиляции исполняемого файла, который в моем случае находится в python.

Невозможно ли установить libA.so, где искать libB.so при компиляции? Я могу сделать это позже с помощью install_name_tool на OSX, но разве не существует способа с компилятором, который будет работать как на OSX, так и на Linux?

ответ

5

Суть в том, что ваш окончательный исполняемый файл должен знать, где находится ваша библиотека. Вы можете сделать это двумя способами: (1), экспортирующий LD_LIBRARY_PATH, содержащий путь к вашей библиотеке, или (2), используя rpath, поэтому ваш исполняемый файл знает, где найти вашу библиотеку. Экспорт LD_LIBRARY_PATH обычно выглядит примерно так:

LD_LIBRARY_PATH=/path/to/your/lib:${LD_LIBRARY_PATH} 
export LD_LIBRARY_PATH 

Я предпочитаю использовать rpath. Чтобы использовать rpath скомпилировать библиотеку в обычном режиме (пример ниже моя расширенные тестовой функции библиотека libetf.so)

gcc -fPIC -Wall -W -Werror -Wno-unused -c -o lib_etf.o lib_etf.c 
gcc -o libetf.so.1.0 lib_etf.o -shared -Wl,-soname,libetf.so.1 

Затем скомпилировать исполняемое использование решений этой библиотеки, вы компилируете объект, а затем связать объект с rpath дается как вариант компоновщика. Вы должны указать путь для libA.so и libB.so в вашем случае.Строительство мой testso исполняемым:

gcc -O2 -Wall -W -Wno-unused -c -o testetf.o testetf.c 
gcc -o testso testetf.o -L/home/david/dev/src-c/lib/etf -Wl,-rpath=/home/david/dev/src-c/lib/etf -letf 

Используйте ldd, чтобы подтвердить, что исполняемый файл правильно расположен в вашей библиотеке:

$ ldd testso 
     linux-vdso.so.1 (0x00007fffd79fe000) 
     libetf.so.1 => /home/david/dev/src-c/lib/etf/libetf.so.1 (0x00007f4d1ef23000) 
     libc.so.6 => /lib64/libc.so.6 (0x00007f4d1eb75000) 
     /lib64/ld-linux-x86-64.so.2 (0x00007f4d1f126000) 

Примечание:libetf.so.1 указывает на /home/david/dev/src-c/lib/etf/libetf.so.1.

1

Используйте опцию -rpath linker.

-rpath dir

Add a directory to the runtime library search path. This is used when linking an ELF executable with shared objects. All -rpath arguments are concatenated and passed to the runtime linker, which uses them to locate shared objects at runtime. The -rpath option is also used when locating shared objects which are needed by shared objects explicitly included in the link; see the description of the -rpath-link option. If -rpath is not used when linking an ELF executable, the contents of the environment variable LD_RUN_PATH will be used if it is defined. The -rpath option may also be used on SunOS. By default, on SunOS, the linker will form a runtime search patch out of all the -L options it is given. If a -rpath option is used, the runtime search path will be formed exclusively using the -rpath options, ignoring the -L options. This can be useful when using gcc, which adds many -L options which may be on NFS mounted filesystems. For compatibility with other ELF linkers, if the -R option is followed by a directory name, rather than a file name, it is treated as the -rpath option.

+0

Спасибо за вашу помощь. Когда я человек cc, я не вижу никаких вариантов для rpath. К сожалению, я должен использовать cc. Есть идеи? – Dan

+0

Когда вы говорите «cc», вам нужно быть более конкретным. «cc» зависит от системы. В Linux это просто ссылка на «gcc». В любом случае, «rpath» - это вариант компоновщика, а не параметр компилятора. Так что прочитайте его: man ld – kaylum

+0

Если это не ясно. С помощью gcc (и, возможно, вашего cc) параметры могут быть переданы компоновщику с параметром -Wl. – kaylum

3

Несмотря на то, что вы не создаете исполняемый файл самостоятельно, подход практически такой же, за исключением того, что вы установите rpath в libA.so, а не в исполняемый двоичный файл. При настройке rpath используйте специальную строку $ ORIGIN, чтобы местоположение libB.so всегда относилось к libA.so.

ld: Using -rpath,$ORIGIN inside a shared library (recursive)

Например:

cc -std=c99 -c -fPIC -I../libB/ -Wall libA.c 
cc -std=c99 -shared libA.o -L../libB -lB -o libA.so -Wl,-rpath,\$ORIGIN/../libB 

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

Как и в сторону, если вы предпочитаете следовать подобный подход к тому, что вы делаете на OS X, вы можете изменить RPATH в .so файл после того, как он был собран с помощью команды chrpath - см:

Can I change 'rpath' in an already compiled binary?

[Отредактировано добавить]

Ну это весело! Между чтением разных сообщений на -rpath и install_name и с различными вариантами. Думаю, я нашел комбо, которое работает. Основной трюк, кажется, установив install_name на libB.so вместе с @loader_path на Либе:

cc -shared -o libA.so libA.o -L../libB -lB -Wl,-rpath,@loader_path 
cc -shared -o libB.so libB.o -install_name @loader_path/../libB/libB.so 

Теперь libB.so всегда находятся в ../libB/ относительно везде libA.so есть.

+0

Большое спасибо за вашу помощь. Я попробовал ваше предложение, но, к сожалению, это не сработало - из первой ссылки, похоже, способ заставить ее работать, это добавить параметр -rpath-link, но мой компилятор в OS X не поддерживает его. Chrpath во второй ссылке также будет замечательным, но когда я проверил свою рабочую станцию ​​Linux (красная шляпа), она не была установлена. Я надеялся найти решение, которое сделало его так, чтобы конечный пользователь не должен был устанавливать какие-либо зависимости. Любые другие идеи? – Dan

+0

Похоже, что специальная строка $ ORIGIN не поддерживается в OS X ... Таким образом, вы должны придерживаться своего плана при построении на OS X. Используйте трюк, описанный выше при построении на Linux, или установите «chrpath» с помощью: 'sudo yum install chrpath'. В принципе, если вы построите его соответствующим образом на каждой платформе, вашим конечным пользователям не придется ничего делать, кроме как загружать и запускать. – bgstech

+0

Спасибо, ваше решение выше для меня работает на OS X, но, конечно, не на Linux. Я думал, что должен быть простой способ сделать это на обеих операционных системах, но, может быть, ответ заключается в том, что нет? – Dan

 Смежные вопросы

  • Нет связанных вопросов^_^