Вопрос по g++, linker, c++, shared – При запуске компоновщика C ++ отсутствует библиотека (поведение SONAME)

7

Я создал программу, которая использует две общие библиотеки (которые я скомпилировал) и размещается так:

<code>/home_directory_where_I_compile_and_run_everything
-->/lib/libjson_linux-gcc-4.4.6_libmt.so
-->/lib/libre2.so.0
</code>

Когда я компилирую свою программу, я передаю относительное расположение этих библиотек компоновщику, например так:

<code>g++ ...... stuff ........ my_program.cc lib/libjson_linux-gcc-4.4.6_libmt.so lib/libre2.so.0
</code>

И он прекрасно компилируется, однако при запуске программы не удается найти libre2.so, и если я проверяю его с помощью ldd, вот что происходит:

<code>....
lib/libjson_linux-gcc-4.4.6_libmt.so (0x00007f62906bc000)
libre2.so.0 => not found
....
</code>

Очевидно, он признает, что путь на libjson относителен, но на libre2.so.0 он этого не делает (он обрезает весь путь и просто оставляет libre2.so.0).

Может кто-нибудь сказать мне, почему это происходит?

Кроме того, есть ли способ изменить это с помощью аргумента g ++?

Лучший.

* UPDATE * Вау проверить это! Я изменил имя libre2.so.0 на stuff.so, а затем попытался скомпилировать по существу так же, как это:

<code>g++ ...... stuff ........ my_program.cc lib/libjson_linux-gcc-4.4.6_libmt.so lib/stuff.so
</code>

И это в любом случае терпит неудачу; он не только терпит неудачу, но и терпит неудачу, потому что не может найти "libre2.so.0".

Whyyy?

* UPDATE # 2 *

Выход дляreadelf -d the_program.o

<code>0x0000000000000001 (NEEDED)             Shared library: [lib/libjson_linux-gcc-4.4.6_libmt.so]
0x0000000000000001 (NEEDED)             Shared library: [libre2.so.0]
</code>

Теперь, если бы я мог просто сделать это [libre2.so.0] как [lib / libre2.so.0], это было бы хорошо.

* UPDATE # 3 *

Как узнал @troubadour:

When an executable is linked with a shared object which has a DT_SONAME field, then when the executable is run the dynamic linker will attempt to load the shared object specified by the DT_SONAME field rather than the using the file name given to the linker.

Вот почему он работает с libjson ..... и не с libre2.so.0. (libjson ..... так что нет записи для SONAME).

И, наконец, я нашел точный вопрос о том, что я ищу:

Is there any way to tell the gcc linker to ignore the SONAME entries on a shared library file and link instead to the specific file path?

Хорошо, я запустил ldconfig и ничего не изменилось. Кроме того, здесь мой LD_LIBRARY_PATH = & lt; empty & gt ;. almosnow
Запустите ldconfig, чтобы обновить кеш, и тогда он должен работать. Matt
Извините, я предположил, что эти библиотеки находятся в стандартных местах, поскольку они нашли первую. Отредактируйте /etc/ld.so.conf и добавьте в него путь к вашей библиотеке, затем снова запустите ldconfig. Matt
Текущий каталог в вашемLD_LIBRARY_PATH? На самом деле, вы можете отредактировать свой вопрос, чтобы показать нам, что находится в вашемLD_LIBRARY_PATH? Кроме того, я предполагаю, что библиотекиnot строится с любым-rpath или же-runpath опции? Troubadour

Ваш Ответ

4   ответа
11

Сначала я отвечу на вторую часть вашего вопроса, т. Е. Почему переименование libre2.so.0 не соответствует вашим ожиданиям.

Имя файла, которое вы передаете компоновщику, не имеет значения, когда вы запускаете исполняемый файл (если вы не указали-soname при сборке библиотеки - см. второе редактирование ниже). Зависимость берется из того, что называется «soname». Если вы запуститеreadelf По команде в вашей библиотеке вы можете определить его имя, например.

readelf -d libre2.so.0 | grep SONAME

Не имеет значения, переименовываете ли вы файл. Результат выполнения вышеуказанной команды по-прежнему даст вам то же имя, поэтому программа не смогла найти & quot; libre2.so.0 & quot ;.

Что касается оригинальной части вашего вопроса, то все зависит от того, есть ли в библиотекахRPATH или жеRUNPATH встроенный в них и / или каково содержание вашегоLD_LIBRARY_PATH переменная окружения есть. Это то, что будет использовать компоновщик времени выполнения (ld.so) для поиска разделяемых библиотек. Пытаться

man ld.so

для дополнительной информации.

Поскольку вы сами создали библиотеки, вы будете знать, использовали ли они-rpath или же-runpath варианты на заключительном этапе связывания. В качестве альтернативы используйтеreadelf опять например

readelf -d libre2.so.0 | grep RPATH
readelf -d libre2.so.0 | grep RUNPATH

Я подозреваю, что две вышеупомянутые команды ничего не вернут.

Я предполагаю, что у вас есть текущий каталог в вашемLD_LIBRARY_PATH что позволило бы компоновщику во время выполнения найти lib / libjson_linux-gcc-4.4.6_libmt.so, но не libre2.so.0. Я заметил, что вы ответили на мой комментарий по вашему вопросу, сказав, что вашLD_LIBRARY_PATH пустой. Это странно.

Возможно, вы каким-то образом получили префикс "lib /" на сонаме для libjson? то есть сделалreadelf команда для возврата SONAME

lib/libjson_linux-gcc-4.4.6_libmt.so

а не просто

libjson_linux-gcc-4.4.6_libmt.so

Кроме того, проверьте, что нужно программе с точки зрения soname, запустив

readelf -d my_progam | grep NEEDED

Возможно, & quot; lib / & quot; префикс там из-за того, как вы передали его в gcc. Если это так, то если вы используете команду gcc, заданную @enobayram, то она выровняет игровое поле, то есть не сможет найти libjson.

Первое, что нужно установить, это не то, почемуnot найти libre2.so.0 но как этоis удалось найти libjson. Если вы попытаетесь запустить свой исполняемый файл из другого каталога, он все еще будет работать или теперь он не будет работать и для libjson? Или, если вы скопируете libre2.so.0 рядом с исполняемым файлом, это что-нибудь изменит?

Edit

размещение на форуме Fedora Предположим, что версия Fedora ld.so имеет текущий каталог в качестве встроенного пути поиска. Хотя я не смог проверить это, но это объяснило бы, почему вы вообще берете какие-либо библиотеки, учитывая, что все остальные вещи, которые использует ld.so, отсутствуют в вашем случае.

Edit 2

Со страницы man ld в моей системе

-soname=name

When creating an ELF shared object, set the internal DT_SONAME field to the specified name. When an executable is linked with a shared object which has a DT_SONAME field, then when the executable is run the dynamic linker will attempt to load the shared object specified by the DT_SONAME field rather than the using the file name given to the linker.

Copyright (c) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, with no Front-Cover Texts, and with no Back- Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License".

Итак, теория в вашем комментарии верна. Если нет-soname явно указывается при сборке библиотеки, тогда в общем объекте SONAME не существует, а поле NEEDED в исполняемом файле просто имеет имя файла, присвоенное компоновщику, который, в вашем случае, содержал лидирующий «lib /».

@almosnow: Спасибо за попытку. Я добавил еще один бит в свой ответ. Попробуйтеreadelf  Команда на вашем исполняемом файле, который ищетNEEDED, Я надеюсь, что это приведет к добавлению "lib /" мы ищем.
Итак, readelf ничего не показывает на RPATH и RUNPATH для libre2.so и libjson .... так. Я заметил, что у libjson ...... нет записи для SONAME. А также, если я перемещаю файл в другой каталог и выполняю его, он не может найти ни одну из обеих библиотек. almosnow
Что касается "pretty-print", я обновил мой вопрос с выходными данными для этого. almosnow
@almosnow: Хорошо, это объясняет, где дополнительные "lib /" происходит от. Однако я все еще не уверен, почему компоновщик во время выполнения выполняет поиск относительно исполняемого файла. Если твойLD_LIBRARY_PATH действительно пустой (то есть не содержит даже одной точки), тогда остается только /etc/ld.so.conf. Содержит ли она строку с точкой?
Здесь, в соответствии с «теорией», компоновщик не может найти SONAME для libjson .... так что он «запечатлевает»; полный путь к ссылке на библиотеку, а затем, поскольку libre2.so.0 имеет SONAME, он делает что-то вроде «хорошо, этот чувак ДОЛЖЕН установить libre2.so.0 в любом из стандартных мест» & quot; и просто помещает туда имя библиотеки. almosnow
3

Когда вы связываетесь с общими библиотеками (.so), они должны существовать в пути загрузки библиотеки, когда выexecute программа. Местоположение, которое вы указали во время ссылки, не "запоминается" в исполняемом файле.

Альтернативные решения:

place the .so files in the same directory as the executable run with LD_LIBRARY_PATH=lib ./program install the .so files to a location in the library path, for example /usr/local/lib, before you run the program. link statically
Это не так, я уже сделал "найти /", хе-хе. almosnow
Ты бежалldconfig как @MattH предложил?
Спасибо за Ваш ответ. Если это правда, почему это работает с libjson ..... так? Лучший. almosnow
Трудно сказать, может быть, libjson_linux-gcc-4.4.6_libmt.so находится где-то еще в вашей системе? ld.so работает таинственным образом ...
1

Вы должны сказать, где находится общая библиотека в двух ситуациях.

One is at linking time.
Есть несколько способов:

copy library to some standard directory, like /usr/local/lib, and install it via ldconfig. In this way, no other option/operation is needed. use -L to tell gcc where to find the lib

One is at running time.
Также несколько способов:

like linking time, install it via ldconfig, then no other action needed.

using LD_LIBRARY_PATH.

LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./a.out

using rpath to write searching path into executable

g++ main.cpp -lxxx -L/a/b/c -Wl,-rpath,/a/b/c

Указание только расположения общей библиотеки на этапе компоновки, например, через-L, не означает, что при запуске программы загрузчик системы найдет нужную библиотеку.

0

Правильная командная строка компилятора должна быть:

g++ ...... stuff ........ my_program.cc -Llib -ljson_linux-gcc-4.4.6_libmt -lre2

И вы должны либо поместить общие объекты в стандартный каталог (например, / usr / lib), либо добавить их путь кLD_LIBRARY_PATH чтобы иметь возможность запустить свой исполняемый файл.

Я понял что не так?
Хорошо, если вы настаиваете на том, чтобы неправильно (на мой взгляд) работать. Мне также интересно знать, почему это «работает» хотя с libjson.
Да, это определенно проливает некоторый свет (по крайней мере для меня) на то, как действительно работает компоновщик. almosnow
Нет, вы ошиблись: c almosnow
Я имею в виду, что вы могли бы это сделать, но это не ответ на мой вопрос, но все равно спасибо: D almosnow

Похожие вопросы