ProblemWithVerifyELFAndRPATH: различия между версиями
(Import from freesource.info) |
|||
(не показано 11 промежуточных версий 6 участников) | |||
Строка 1: | Строка 1: | ||
[[Category:Devel]] | [[Category:Devel]] | ||
{{ | {{Category navigation|title=Сборка пакетов|category=Сборка пакетов|sortkey={{SUBPAGENAME}}}} | ||
== Проблемы с ELF == | == Проблемы с ELF == | ||
=== RPATH === | === RPATH === | ||
При сборке | При сборке {{pkg|wmnetload}} я столкнулся со следующей ошибкой: | ||
<pre>verify-elf: ./usr/bin/wmnetload: RPATH entry contains ":": :/usr/local/lib</pre> | <pre>verify-elf: ./usr/bin/wmnetload: RPATH entry contains ":": :/usr/local/lib</pre> | ||
Строка 11: | Строка 11: | ||
Было два возможных выхода из сложившейся ситуации, даже три: | Было два возможных выхода из сложившейся ситуации, даже три: | ||
# ослабить проверку, добавив в спек <tt>%set_verify_elf_method rpath=relaxed</tt> | |||
# докопаться до истинной причины и решить проблему в корне | |||
# не собирать wmnetload :-) | |||
Я, конечно же, выбрал второй вариант и ниже опишу последовательность своих действий, в результате которых удалось избежать этой ошибки. Возможно, что в вашем случае разрешить подобную ошибку придется иным способом, но в моем сработал этот. В любом случае рекомендую вам ознакомиться с материалами, ссылки на которые приведены в конце. | |||
=== RPATH при сборке не в репозиторий === | |||
В случае если вы собираете сторонний пакет для ALT, не планируя размещать его в репозиторий, и если файлы расположены по нестандартному пути, вы можете столкнуться с ошибкой | |||
<pre>verify-elf: ERROR: ./opt/pgpro/std-15/lib/timescaledb-tsl-2.10.0.so: RPATH contains illegal absolute entry "/opt/pgpro/std-15/lib": /opt/pgpro/std-15/lib</pre> | |||
если вы знаете, что в вашем проекте так и должно быть, ослабьте проверку, добавив в спек <tt>%set_verify_elf_method rpath=relaxed</tt> | |||
==== Немного теории ==== | ==== Немного теории ==== | ||
Перед тем как начать что-то делать | Перед тем как начать что-то делать, неплохо бы узнать, что такое <tt>RPATH</tt> и почему {{path|/usr/local/lib}}, присутствующий в нем, является ошибкой. | ||
<tt>RPATH</tt> | <tt>RPATH</tt> — это свойство некоего ELF-объекта (программы или библиотеки) хранить в себе дополнительные пути поиска разделяемых библиотек (shared libraries). То есть, программа будет искать so’шку сначала там, куда указывает RPATH, а затем в {{path|/lib}}, {{path|/usr/lib}} и других системных путях, которые указаны в {{path|/etc/ld.so.conf}}. Значение переменной RPATH «зашито» в самой программе и вы можете увидеть его, вызвав {{cmd|readelf -a program}}. Среди множества появившейся информации ищите упоминание про RPATH. Маленькая тонкость: в бинарниках со стандартным значением RPATH вы не найдете упоминания о нем, так как по умолчанию значение у переменной пустое. Для примера приведу часть вывода readelf для все того же wmnetload, скомпилированного с {{path|/usr/local/lib}} в RPATH: | ||
<pre>[c0der@mycomp ~/wm/bin]$ readelf -a wmnetload | grep | <pre>[c0der@mycomp ~/wm/bin]$ readelf -a wmnetload | grep PATH | ||
0x0000000f (RPATH) Library rpath: [ :/usr/local/lib]</pre> | 0x0000000f (RPATH) Library rpath: [ :/usr/local/lib]</pre> | ||
Обратите внимание, что существует RPATH, а существует RUNPATH. Для удобства и то, и то обычно называют «RPATH». | |||
В случае, если RPATH не содержит дополнительных путей, мы ничего не увидим, т.е. вывод программы будет пустым. | В случае, если RPATH не содержит дополнительных путей, мы ничего не увидим, т.е. вывод программы будет пустым. | ||
Почему RPATH не должен содержать | Почему RPATH не должен содержать стандартные пути? Потому что ld-linux(1) их там найдет и без RPATH. Почему стоит избегать RPATH? Потому что все библиотеки должны располагаться в стандартных и отведенных для этого местах, а именно в {{path|/usr/lib}}. "Потому что должны быть веские причины держать разделяемую библиотеку не в {{path|/usr/lib}} и тем более веские — держать их в разных местах, ни одно из которых не является {{path|/usr/lib}}" (с) lioka. А когда библиотека лежит в нестандартном месте, большинство программ ее не найдет, а RPM-пакет будет содержать в себе ненужные Provides, вводя другие пакеты в заблуждение. | ||
==== Поиск источника проблемы ==== | ==== Поиск источника проблемы ==== | ||
Начал я с того, что по'grep'ал исходники на предмет этого самого RPATH. Все указывало на файл | Начал я с того, что по'grep'ал исходники на предмет этого самого RPATH. Все указывало на файл {{path|configure.in}}, в котором я обнаружил следующие строки: | ||
<pre>dnl | <pre>dnl | ||
Строка 46: | Строка 56: | ||
...</pre> | ...</pre> | ||
Как видим, RPATH включает в себя <tt>$LIBRARY_RPATH</tt>. Тогда ищем где и как определяется <tt>$LIBRARY_RPATH</tt>. Наша цель узнать как в ней оказывается | Как видим, RPATH включает в себя <tt>$LIBRARY_RPATH</tt>. Тогда ищем, где и как определяется <tt>$LIBRARY_RPATH</tt>. Наша цель узнать как в ней оказывается {{path|/usr/local/lib}} и удалить этот путь. | ||
<pre>LIBRARY_RPATH=`echo "$LIBRARY_SEARCH_PATH" | sed 's/[ *]-L[ *]/:/g'`</pre> | <pre>LIBRARY_RPATH=`echo "$LIBRARY_SEARCH_PATH" | sed 's/[ *]-L[ *]/:/g'`</pre> | ||
Теперь ищем где же определяется <tt>$LIBRARY_SEARCH_PATH</tt>: | Теперь ищем, где же определяется <tt>$LIBRARY_SEARCH_PATH</tt>: | ||
<pre>LIBRARY_SEARCH_PATH="$lib_search_path -L/usr/local/lib"</pre> | <pre>LIBRARY_SEARCH_PATH="$lib_search_path -L/usr/local/lib"</pre> | ||
Вот то что мы искали! Вот откуда | Вот то, что мы искали! Вот откуда «растут ноги» у нашей проблемы. Остаётся лишь удалить этот путь из RPATH. | ||
==== Решение проблемы ==== | ==== Решение проблемы ==== | ||
Как мы выяснили выше для ликвидации проблемы нужно удалить путь /usr/local/lib из $LIBRARY_SEARCH_PATH. Я сделал это так: | Как мы выяснили выше, для ликвидации проблемы нужно удалить путь {{path|/usr/local/lib}} из <tt>$LIBRARY_SEARCH_PATH</tt>. Я сделал это так: | ||
<pre>sed -i 's|LIBRARY_SEARCH_PATH="$lib_search_path -L/usr/local/lib"|LIBRARY_SEARCH_PATH="$lib_search_path"|' configure.in</pre> | |||
Т.е. просто заменил строку sed'ом. Этот код следует вызывать в секции <tt>%pre</tt>, т.е. до вызова <tt>%configure</tt>. Также следует не забыть пересоздать configure-скрипт, вызвав autoconf (или даже <tt>%autoreconf</tt>). | |||
<pre>% | ==== Дополнение ==== | ||
В некоторых случаях у configure есть опция --enable-rpath / --disable-rpath и достаточно в спеке указать <pre>%configure --disable-rpath</pre> | |||
Для cmake может помочь добавление <pre>-DCMAKE_SKIP_RPATH=ON</pre>. | |||
=== LD_LIBRARY_PATH === | === LD_LIBRARY_PATH === | ||
При расположении библиотек в нестандартных местах и использовании нестандартной среды сборки (не autotools) | При расположении библиотек в нестандартных местах и использовании нестандартной среды сборки (не autotools) может возникнуть проблема, при которой проверка бинарных файлов не может пройти. | ||
может возникнуть проблема, при которой проверка бинарных файлов не может пройти. | Если не проходит проверка бинарных файлов из {{path|/usr/bin}}, скорее всего в них указан неверный RPATH (или вовсе не указан). | ||
Если не проходит проверка бинарных файлов из /usr/bin, скорее всего в них указан (или вовсе не указан) | |||
==== Проверка при сборке пакета ==== | ==== Проверка при сборке пакета ==== | ||
Для проверки бинарных файлов и библиотек используется значение LD_LIBRARY_PATH, полученное примерно следующим образом: | Для проверки бинарных файлов и библиотек используется значение LD_LIBRARY_PATH, полученное примерно следующим образом: | ||
* добавляется значение RPATH; | |||
* добавляется архитектурно-зависимый путь поиска библиотек (%_libdir:/%_lib); | |||
* к вычисленному значению добавляется вывод от {{cmd|libtool-ldconfig-dump}} (я так понимаю, он скажет, какие мы нестандартные каталоги для библиотек использовали в проекте) | |||
* к полученному списку добавляется в начало он же, но с префиксом <tt>%buildroot</tt> для каждого элемента; | |||
=== Благодарности === | === Благодарности === | ||
Строка 87: | Строка 100: | ||
* [http://wiki.sisyphus.ru/devel/TextRel/libtool http://wiki.sisyphus.ru/devel/TextRel/libtool] | * [http://wiki.sisyphus.ru/devel/TextRel/libtool http://wiki.sisyphus.ru/devel/TextRel/libtool] | ||
* [http://lists.altlinux.ru/pipermail/devel/2005-June/021705.html http://lists.altlinux.ru/pipermail/devel/2005-June/021705.html] | * [http://lists.altlinux.ru/pipermail/devel/2005-June/021705.html http://lists.altlinux.ru/pipermail/devel/2005-June/021705.html] | ||
* [http://lists.altlinux.org/pipermail/devel/2011-December/192724.html Обзор трех типов ошибок в RPATH] | |||
*# [http://lists.altlinux.org/pipermail/devel/2011-December/192725.html Некорректные RPATH, содержащие относительные пути] (тж. [http://lists.altlinux.org/pipermail/devel/2011-December/192739.html здесь]) | |||
*# [http://lists.altlinux.org/pipermail/devel/2011-December/192726.html Некорректные RPATH, содержащие пути за пределами стандартного размещения библиотек и плагинов] | |||
*# [http://lists.altlinux.org/pipermail/devel/2011-December/192727.html Некорректные RPATH, содержащие пути к стандартным библиотекам]<br />(NB: замена может быть применима к {{path|configure}} при отсутствии {{path|libtool}}) |
Текущая версия от 13:41, 13 марта 2023
Проблемы с ELF
RPATH
При сборке wmnetload я столкнулся со следующей ошибкой:
verify-elf: ./usr/bin/wmnetload: RPATH entry contains ":": :/usr/local/lib
Было два возможных выхода из сложившейся ситуации, даже три:
- ослабить проверку, добавив в спек %set_verify_elf_method rpath=relaxed
- докопаться до истинной причины и решить проблему в корне
- не собирать wmnetload :-)
Я, конечно же, выбрал второй вариант и ниже опишу последовательность своих действий, в результате которых удалось избежать этой ошибки. Возможно, что в вашем случае разрешить подобную ошибку придется иным способом, но в моем сработал этот. В любом случае рекомендую вам ознакомиться с материалами, ссылки на которые приведены в конце.
RPATH при сборке не в репозиторий
В случае если вы собираете сторонний пакет для ALT, не планируя размещать его в репозиторий, и если файлы расположены по нестандартному пути, вы можете столкнуться с ошибкой
verify-elf: ERROR: ./opt/pgpro/std-15/lib/timescaledb-tsl-2.10.0.so: RPATH contains illegal absolute entry "/opt/pgpro/std-15/lib": /opt/pgpro/std-15/lib
если вы знаете, что в вашем проекте так и должно быть, ослабьте проверку, добавив в спек %set_verify_elf_method rpath=relaxed
Немного теории
Перед тем как начать что-то делать, неплохо бы узнать, что такое RPATH и почему /usr/local/lib, присутствующий в нем, является ошибкой.
RPATH — это свойство некоего ELF-объекта (программы или библиотеки) хранить в себе дополнительные пути поиска разделяемых библиотек (shared libraries). То есть, программа будет искать so’шку сначала там, куда указывает RPATH, а затем в /lib, /usr/lib и других системных путях, которые указаны в /etc/ld.so.conf. Значение переменной RPATH «зашито» в самой программе и вы можете увидеть его, вызвав readelf -a program. Среди множества появившейся информации ищите упоминание про RPATH. Маленькая тонкость: в бинарниках со стандартным значением RPATH вы не найдете упоминания о нем, так как по умолчанию значение у переменной пустое. Для примера приведу часть вывода readelf для все того же wmnetload, скомпилированного с /usr/local/lib в RPATH:
[c0der@mycomp ~/wm/bin]$ readelf -a wmnetload | grep PATH 0x0000000f (RPATH) Library rpath: [ :/usr/local/lib]
Обратите внимание, что существует RPATH, а существует RUNPATH. Для удобства и то, и то обычно называют «RPATH».
В случае, если RPATH не содержит дополнительных путей, мы ничего не увидим, т.е. вывод программы будет пустым.
Почему RPATH не должен содержать стандартные пути? Потому что ld-linux(1) их там найдет и без RPATH. Почему стоит избегать RPATH? Потому что все библиотеки должны располагаться в стандартных и отведенных для этого местах, а именно в /usr/lib. "Потому что должны быть веские причины держать разделяемую библиотеку не в /usr/lib и тем более веские — держать их в разных местах, ни одно из которых не является /usr/lib" (с) lioka. А когда библиотека лежит в нестандартном месте, большинство программ ее не найдет, а RPM-пакет будет содержать в себе ненужные Provides, вводя другие пакеты в заблуждение.
Поиск источника проблемы
Начал я с того, что по'grep'ал исходники на предмет этого самого RPATH. Все указывало на файл configure.in, в котором я обнаружил следующие строки:
dnl dnl Hack in rpath -- yes, this sucks, and it even has a hidden dependency dnl on the implementation of AC_PATH_XTRA. F@&* you, portability. dnl if test "$GCC" = yes; then if test "ac_R_space" = no; then RPATH="-Wl,\"-R$LIBRARY_RPATH\"" else RPATH="-Wl,\"-R $LIBRARY_RPATH\"" fi ...
Как видим, RPATH включает в себя $LIBRARY_RPATH. Тогда ищем, где и как определяется $LIBRARY_RPATH. Наша цель узнать как в ней оказывается /usr/local/lib и удалить этот путь.
LIBRARY_RPATH=`echo "$LIBRARY_SEARCH_PATH" | sed 's/[ *]-L[ *]/:/g'`
Теперь ищем, где же определяется $LIBRARY_SEARCH_PATH:
LIBRARY_SEARCH_PATH="$lib_search_path -L/usr/local/lib"
Вот то, что мы искали! Вот откуда «растут ноги» у нашей проблемы. Остаётся лишь удалить этот путь из RPATH.
Решение проблемы
Как мы выяснили выше, для ликвидации проблемы нужно удалить путь /usr/local/lib из $LIBRARY_SEARCH_PATH. Я сделал это так:
sed -i 's|LIBRARY_SEARCH_PATH="$lib_search_path -L/usr/local/lib"|LIBRARY_SEARCH_PATH="$lib_search_path"|' configure.in
Т.е. просто заменил строку sed'ом. Этот код следует вызывать в секции %pre, т.е. до вызова %configure. Также следует не забыть пересоздать configure-скрипт, вызвав autoconf (или даже %autoreconf).
Дополнение
В некоторых случаях у configure есть опция --enable-rpath / --disable-rpath и достаточно в спеке указать
%configure --disable-rpath
Для cmake может помочь добавление
-DCMAKE_SKIP_RPATH=ON
.
LD_LIBRARY_PATH
При расположении библиотек в нестандартных местах и использовании нестандартной среды сборки (не autotools) может возникнуть проблема, при которой проверка бинарных файлов не может пройти. Если не проходит проверка бинарных файлов из /usr/bin, скорее всего в них указан неверный RPATH (или вовсе не указан).
Проверка при сборке пакета
Для проверки бинарных файлов и библиотек используется значение LD_LIBRARY_PATH, полученное примерно следующим образом:
- добавляется значение RPATH;
- добавляется архитектурно-зависимый путь поиска библиотек (%_libdir:/%_lib);
- к вычисленному значению добавляется вывод от libtool-ldconfig-dump (я так понимаю, он скажет, какие мы нестандартные каталоги для библиотек использовали в проекте)
- к полученному списку добавляется в начало он же, но с префиксом %buildroot для каждого элемента;
Благодарности
- Дмитрию Левину (ldv@) за то что сделал все эти проверки
- Виталию Липатову (lav@) за то что предложил и вдохновил написать об этом
- Сергею Большакову aka lioka (sbolshakov@) за объяснение теоретических основ
Смотри также
- http://lists.altlinux.ru/pipermail/community/2002-December/063777.html
- http://wiki.sisyphus.ru/devel/TextRel/libtool
- http://lists.altlinux.ru/pipermail/devel/2005-June/021705.html
- Обзор трех типов ошибок в RPATH
- Некорректные RPATH, содержащие относительные пути (тж. здесь)
- Некорректные RPATH, содержащие пути за пределами стандартного размещения библиотек и плагинов
- Некорректные RPATH, содержащие пути к стандартным библиотекам
(NB: замена может быть применима к configure при отсутствии libtool)