ProblemWithVerifyELFAndRPATH

Материал из ALT Linux Wiki

(Различия между версиями)
Перейти к: навигация, поиск
(Import from freesource.info)
(Решение проблемы: %configure --disable-rpath)
 
(8 промежуточных версий не показаны.)
Строка 1: Строка 1:
[[Category:Devel]]
[[Category:Devel]]
-
{{MovedFromFreesourceInfo|AltLinux/Sisyphus/devel/ProblemWithVerifyELFAndRPATH}}
+
{{Category navigation|title=Сборка пакетов|category=Сборка пакетов|sortkey={{SUBPAGENAME}}}}
== Проблемы с ELF ==
== Проблемы с ELF ==
=== RPATH ===
=== RPATH ===
-
При сборке [http://freshmeat.net/projects/wmnetload/ wmnetload] я столкнулся со следующей ошибкой:
+
При сборке {{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:
Было два возможных выхода из сложившейся ситуации, даже три:
Было два возможных выхода из сложившейся ситуации, даже три:
-
1) ослабить проверку, добавив в спек <tt>%set_verify_elf_method textrel=relaxed</tt>
+
# ослабить проверку, добавив в спек <tt>%set_verify_elf_method textrel=relaxed</tt>
-
2) докопаться до истинной причины и решить проблему в корне
+
# докопаться до истинной причины и решить проблему в корне
-
3) не собирать wmnetload :-)
+
# не собирать wmnetload :-)
-
Я конечно же выбрал второй вариант и ниже опишу последовательность своих действий, в результате которых удалось избежать этой ошибки. Возможно, что в вашем случае разрешить подобную ошибку придется иным способом, но в моем сработал этот. В любом случае рекомендую вам ознакомиться с материалами, ссылки на которые приведены в конце.
+
Я, конечно же, выбрал второй вариант и ниже опишу последовательность своих действий, в результате которых удалось избежать этой ошибки. Возможно, что в вашем случае разрешить подобную ошибку придется иным способом, но в моем сработал этот. В любом случае рекомендую вам ознакомиться с материалами, ссылки на которые приведены в конце.
==== Немного теории ====
==== Немного теории ====
-
Перед тем как начать что-то делать не плохо бы узнать что такое <tt>RPATH</tt> и почему <tt>/usr/local/lib</tt>, присутствующий в нем, является ошибкой.
+
Перед тем как начать что-то делать, неплохо бы узнать, что такое <tt>RPATH</tt> и почему {{path|/usr/local/lib}}, присутствующий в нем, является ошибкой.
-
<tt>RPATH</tt> -- это свойство некоего ELF-объекта (программы или библиотеки) хранить в себе дополнительные пути поиска разделяемых (shared) библиотек. Т.е. программа будет искать so'шку сначала там, куда указывает RPATH, а затем в <tt>/lib</tt>, <tt>/usr/lib</tt> и других системных путях, которые указаны в <tt>/etc/ld.so.conf</tt>. Значение переменный RPATH "зашито" в самой програме и вы можете увидеть его вызвав <tt>readelf -a program</tt>. Среди множества появившейся информации ищите упоминание про RPATH. Маленькая тонкость: в бинарниках со стандартным значением RPATH вы не найдете упоминания о нем, так как по умолчанию значение у переменной пустое. Для примера приведу часть вывода readelf для все того же wmnetload, скомпилированного с <tt>/usr/local/lib</tt> в RPATH:
+
<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 RPATH
<pre>[c0der@mycomp ~/wm/bin]$ readelf -a wmnetload | grep RPATH
Строка 28: Строка 28:
В случае, если RPATH не содержит дополнительных путей, мы ничего не увидим, т.е. вывод программы будет пустым.
В случае, если RPATH не содержит дополнительных путей, мы ничего не увидим, т.е. вывод программы будет пустым.
-
Почему RPATH не должен содержать какие-либо пути отличные от стандартных? Потому что все библиотеки должны располагаться в стандартных и отведенных для этого местах, а именно в /usr/lib. "Потому что должны быть веские причины держать разделяемую библиотеку не в /usr/lib и тем более веские держать их в разных местах, ни одно из которых не является /usr/lib" (с) lioka
+
Почему RPATH не должен содержать какие-либо пути, отличные от стандартных? Потому что все библиотеки должны располагаться в стандартных и отведенных для этого местах, а именно в {{path|/usr/lib}}. "Потому что должны быть веские причины держать разделяемую библиотеку не в {{path|/usr/lib}} и тем более веские — держать их в разных местах, ни одно из которых не является {{path|/usr/lib}}" (с) lioka
==== Поиск источника проблемы ====
==== Поиск источника проблемы ====
-
Начал я с того, что по'grep'ал исходники на предмет этого самого RPATH. Все указывало на файл <tt>configure.in</tt>, в котором я обнаружил следующие строки:
+
Начал я с того, что по'grep'ал исходники на предмет этого самого RPATH. Все указывало на файл {{path|configure.in}}, в котором я обнаружил следующие строки:
<pre>dnl
<pre>dnl
Строка 46: Строка 46:
...</pre>
...</pre>
-
Как видим, RPATH включает в себя <tt>$LIBRARY_RPATH</tt>. Тогда ищем где и как определяется <tt>$LIBRARY_RPATH</tt>. Наша цель узнать как в ней оказывается <tt>/usr/local/lib</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.
+
Вот то, что мы искали! Вот откуда «растут ноги» у нашей проблемы. Остаётся лишь удалить этот путь из 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>
+
<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>. Также следует не забыть  
+
Т.е. просто заменил строку sed'ом. Этот код следует вызывать в секции <tt>%pre</tt>, т.е. до вызова <tt>%configure</tt>. Также следует не забыть пересоздать configure-скрипт, вызвав autoconf (или даже <tt>%autoreconf</tt>).
-
пересоздать configure-скрипт, вызвав autoconf (<tt>%__autoconf</tt>).
+
 
 +
==== Дополнение ====
 +
В некоторых случаях у configure есть опция --enable-rpath / --disable-rpath и достаточно в спеке указать %configure --disable-rpath
=== LD_LIBRARY_PATH ===
=== LD_LIBRARY_PATH ===
-
При расположении библиотек в нестандартных местах и использовании нестандартной среды сборки (не autotools)
+
При расположении библиотек в нестандартных местах и использовании нестандартной среды сборки (не autotools) может возникнуть проблема, при которой проверка бинарных файлов не может пройти.
-
может возникнуть проблема, при которой проверка бинарных файлов не может пройти.
+
Если не проходит проверка бинарных файлов из {{path|/usr/bin}}, скорее всего в них указан неверный RPATH (или вовсе не указан).
-
Если не проходит проверка бинарных файлов из /usr/bin, скорее всего в них указан (или вовсе не указан) неверный RPATH.
+
==== Проверка при сборке пакета ====
==== Проверка при сборке пакета ====
Для проверки бинарных файлов и библиотек используется значение LD_LIBRARY_PATH, полученное примерно следующим образом:
Для проверки бинарных файлов и библиотек используется значение LD_LIBRARY_PATH, полученное примерно следующим образом:
-
- добавляется значение RPATH;
+
* добавляется значение RPATH;
-
- добавляется архитектурно-зависимый путь поиска библиотек (%_libdir:/%_lib);
+
* добавляется архитектурно-зависимый путь поиска библиотек (%_libdir:/%_lib);
-
- к вычисленному значению добавляется вывод от libtool-ldconfig-dump (я так понимаю он скажет какие мы нестандартные каталоги для библиотек использовали в проекте)
+
* к вычисленному значению добавляется вывод от {{cmd|libtool-ldconfig-dump}} (я так понимаю, он скажет, какие мы нестандартные каталоги для библиотек использовали в проекте)
-
- к полученному списку добавляется в начало он же, но с префиксом %buildroot для каждого элемента;
+
* к полученному списку добавляется в начало он же, но с префиксом <tt>%buildroot</tt> для каждого элемента;
=== Благодарности ===
=== Благодарности ===
Строка 87: Строка 88:
* [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}})

Текущая версия на 05:16, 20 октября 2016


Содержание

Проблемы с ELF

RPATH

При сборке wmnetload я столкнулся со следующей ошибкой:

verify-elf: ./usr/bin/wmnetload: RPATH entry contains ":": :/usr/local/lib

Было два возможных выхода из сложившейся ситуации, даже три:

  1. ослабить проверку, добавив в спек %set_verify_elf_method textrel=relaxed
  2. докопаться до истинной причины и решить проблему в корне
  3. не собирать wmnetload :-)

Я, конечно же, выбрал второй вариант и ниже опишу последовательность своих действий, в результате которых удалось избежать этой ошибки. Возможно, что в вашем случае разрешить подобную ошибку придется иным способом, но в моем сработал этот. В любом случае рекомендую вам ознакомиться с материалами, ссылки на которые приведены в конце.

Немного теории

Перед тем как начать что-то делать, неплохо бы узнать, что такое 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 RPATH
 0x0000000f (RPATH)                      Library rpath: [ :/usr/local/lib]

В случае, если RPATH не содержит дополнительных путей, мы ничего не увидим, т.е. вывод программы будет пустым.

Почему RPATH не должен содержать какие-либо пути, отличные от стандартных? Потому что все библиотеки должны располагаться в стандартных и отведенных для этого местах, а именно в /usr/lib. "Потому что должны быть веские причины держать разделяемую библиотеку не в /usr/lib и тем более веские — держать их в разных местах, ни одно из которых не является /usr/lib" (с) lioka

Поиск источника проблемы

Начал я с того, что по'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

LD_LIBRARY_PATH

При расположении библиотек в нестандартных местах и использовании нестандартной среды сборки (не autotools) может возникнуть проблема, при которой проверка бинарных файлов не может пройти. Если не проходит проверка бинарных файлов из /usr/bin, скорее всего в них указан неверный RPATH (или вовсе не указан).

Проверка при сборке пакета

Для проверки бинарных файлов и библиотек используется значение LD_LIBRARY_PATH, полученное примерно следующим образом:

  • добавляется значение RPATH;
  • добавляется архитектурно-зависимый путь поиска библиотек (%_libdir:/%_lib);
  • к вычисленному значению добавляется вывод от libtool-ldconfig-dump (я так понимаю, он скажет, какие мы нестандартные каталоги для библиотек использовали в проекте)
  • к полученному списку добавляется в начало он же, но с префиксом %buildroot для каждого элемента;

Благодарности

  • Дмитрию Левину (ldv@) за то что сделал все эти проверки
  • Виталию Липатову (lav@) за то что предложил и вдохновил написать об этом
  • Сергею Большакову aka lioka (sbolshakov@) за объяснение теоретических основ

Смотри также

 
Личные инструменты