Linux приложение не видит библиотеку so
Как вы знаете каждая программа, установленная на вашем компьютере, состоит из нескольких частей. Это непосредственно исполняемый файл, который вы запускаете через терминал, а также библиотеки с набором функций, которые может использовать программа.
Все, без исключения, программы используют библиотеки. Даже если это ваша программа и у нее нет своих библиотек, она использует стандартную библиотеку языка программирования С.
В этой статье мы подробно рассмотрим что такое библиотеки Ubuntu, как их устанавливать, где брать и что делать если библиотека установлена, а программа говорит что ее нет. Мы не будем трогать создание библиотек, это совсем не наша тема. Как обычно, начнем с теории.
Что такое библиотеки
Библиотеки в Linux содержат наборы функций или если сказать проще алгоритмов или действий для решения определенных задач. Например, если программе нужно вывести строку на экран она не начинает сама закрашивать нужные пиксели, а просто обращается к отвечающей за это функции из библиотеки, то же самое если программе нужно прочитать содержимое файла, она не работает с секторами жесткого диска, ей достаточно вызвать функцию из стандартной библиотеки с (libc.so) и передать ей в параметрах имя нужного файла, а библиотека уже вернет ей запрашиваемые данные.
На самом деле, такая структура реализации программного обеспечения очень выгодна, поскольку достаточно написать алгоритм лишь один раз и его смогут использовать все программы просто загружая библиотеку.
Не нужно думать что библиотеки есть только в Linux, в Windows они тоже есть, только имеют другой формат и расширение dll. В Linux же все библиотеки находятся в папах /lib/, /usr/lib, /usr/local/lib или для 64 битных систем также появляется папка lib64 во всех этих подкаталогах, для библиотек специфичных для этой архитектуры. Библиотека имеет расширение .so и ее название начинается со слова lib. Например, libfuse.so, libc.so.
Дальше, после расширения файла .so идет номер версии библиотеки. Номер версии меняется всякий раз, когда разработчики вносят в нее изменения ломающие совместимость со всеми рассчитанными на нее программами. В таком случае в системе будут уже две библиотеки и каждая программа будет использовать правильную версию. Например, glibc.so.6 и glibc.so.5.
Если интересно можно даже посмотреть какие библиотеки и каких версий, использует та или иная программа, например:
linux-vdso.so.1 (0x00007ffd99167000)
libmount.so.1 => /usr/lib64/libmount.so.1 (0x00007f0f6beb0000)
libc.so.6 => /lib64/libc.so.6 (0x00007f0f6bb08000)
libblkid.so.1 => /usr/lib64/libblkid.so.1 (0x00007f0f6b8c8000)
libselinux.so.1 => /lib64/libselinux.so.1 (0x00007f0f6b6a4000)
/lib64/ld-linux-x86-64.so.2 (0x000055aca8227000)
libuuid.so.1 => /usr/lib64/libuuid.so.1 (0x00007f0f6b49f000)
libpcre.so.1 => /usr/lib64/libpcre.so.1 (0x00007f0f6b238000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f0f6b034000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f0f6ae17000)
Также эта информация может быть полезна при создании портативных версий программ. А теперь давайте рассмотрим как устанавливаются библиотеки в Ubuntu.
Установка библиотек в Ubuntu
Обычно, если вы используете менеджер пакетов вашего дистрибутива для установки новых программ, то библиотеки устанавливаются автоматически. Но если вы хотите собрать программу из исходников или запустить 32 битную программу на 64 битной системе могут начаться проблемы. Например, при запуске или компиляции программы вы получаете ошибку:
error while loading shared libraries: xxxx.so.0
cannot open shared object file no such file or directory
Обычно, в Ubuntu имена пакетов библиотек соответствуют имени нужной библиотеки. Поэтому чтобы определить точное имя в большинстве случаев достаточно воспользоваться поиском по базе пакетов:
apt search libfuse
Как видите, найдено два варианта библиотеки, libfuse2 и libfuse-dev.
Если библиотека нужна обычной программе и ее не нужно собирать из исходников, то будет достаточно установить библиотеку ubuntu без префикса dev. Например:
sudo apt install libfuse2
Если же вам нужно собрать приложение из исходников, то кроме обычной библиотеки понадобятся заголовочные файлы, в которых содержится описание реализованных в библиотеке функций. Такие пакеты имеют приставку dev, например, libfuse-dev, тогда нужно устанавливать этот пакет, а он уже в зависимостях потянет и обычную библиотеку, если она еще не установлена:
sudo apt install libfuse-dev
Много проблем может вызвать ситуация, когда вам нужно запустить 32 битную программу в 64 битной системе. Например, если вы установили 64 битную версию библиотеки, а программа все равно говорит о том, что не может ее найти, возможно это 32 битная программа и ей необходима именно 32 библиотека. Если программа не устанавливается с помощью пакетного менеджера, вам тоже придется устанавливать библиотеки вручную.
Посмотреть разрядность бинарника можно с помощью утилиты file:
На скриншоте показаны два варианта вывода программы, для 32 бит, в нашем случае Skype и для 64 - mount.
Для того чтобы установить библиотеку Ubuntu с архитектурой i386 сначала необходимо добавить поддержку архитектуры i386 в dpkg:
sudo dpkg --add-architecture i386
Затем обновляем наши репозитории:
sudo apt update
А во время установки нужной вам библиотеки теперь необходимо указать архитектуру через двоеточие после имени пакета:
sudo apt install libfuse-dev:i386
Если вы уверенны, что библиотека установлена, но программа все равно говорит, что такой библиотеки нет, то возможно, ей просто нужна другая версия библиотеки. Например, в системе есть libudev.so.0, а программе нужна libudev.so.0.1. Такое случается, если вы попытаетесь установить пакет для другого дистрибутива, особенно в Red Hat системах. Если в репозиториях нет нужной версии библиотеки, то скорее всего, они одинаковы, и можно просто создать символическую ссылку:
ln -s /lib/libudev.so.0 /lib/libudev.so.0.1
Затем программа найдет нужную библиотеку.
Управление библиотеками в Linux
Установка библиотек ubuntu уже рассмотрена, но хотелось бы упомянуть еще пару моментов. Как я сказал, библиотеки ubuntu размещаются в определенных каталогах, но расположение библиотек можно настроить.
Перед тем как библиотека будет подключена к программе, ее должна найти в системе специальная программа - менеджер библиотек. Он берет адреса библиотек из файла /etc/ld.cache, а этот файл формируется утилитой ldconfig, на основе файлов конфигурации /etc/ld.so.conf.
В этом файле перечислены все пути к библиотекам. Если вы хотите добавить свою папку для библиотек просто добавьте ее в этот файл:
Затем обновите кэш просто выполнив:
Теперь ваша библиотека может быть загружена программой, например, вы можете добавить путь /opt/lib или даже /home/user/lib. И система будет нормально грузить оттуда библиотеки.
Посмотреть какие библиотеки находятся в кеше ld.cache можно командой:
Также мы можем проверить находится ли там определенная библиотека:
ldconfig -p | grep libjpeg
Еще один способ указать программе где нужно искать библиотеки - это переменная LD_LIBRARY_PATH. Например:
Теперь программы, запускаемые в этом терминале, кроме стандартных путей поиска библиотек, будут использовать и указанную папку.
Выводы
Вот и все. Теперь вы знаете как работают библиотеки Ubuntu, как выполняется установка библиотек Ubuntu и делать так, чтобы программа видела нужную ей библиотеку. У новичков это может вызвать очень много головной боли, но теперь вы знаете что делать и избежите многих ошибок. Если у вас остались вопросы, пишите в комментариях!
В прошлый раз мы с Вами обнаружили, что запуск программ, скомпилированных вместе с динамическими библиотеками, вызывает ошибку:
Первая программа называется ldd. Она выдает на экран список динамических библиотек используемых в программе и их местоположение. В качестве параметра ей сообщается название обследуемой программы. Давайте попробуем использовать ее для нашей программы rezultdyn:
- libc.so.6 - стандартную библиотеку функций языка C++.
- ld-linux.so.2 - библиотеку динамической линковки программ ELF формата.
- libfsdyn.so - нашу динамическую библиотеку функций.
Нашу библиотеку она найти не может. И правильно! Динамический линковщик ищет библиотеки только в известных ему каталогах, а каталог нашей программы ему явно не известен.
Для того, чтобы добавить нашу директорию с библиотекой в список известных директорий надо подредактировать файл /etc/ld.so.conf. Например, у меня этот файл состоит из таких строк:
Во всех этих директории хранятся всеми используемые библиотеки. В этом списке нет лишь одной директории - /lib, которая сама по себе не нуждается в описании, так как она является главной. Получается, что наша библиотека станет "заметной", если поместить ее в один их этих каталогов, либо отдельно описать в отдельном каталоге. Давайте для теста опишем, добавим строку в конец файла ld.so.conf:
У меня этот файл валяется в домашнем каталога пользователя root, у Вас он может быть в другом месте. Теперь после этого динамический линковщик будет знать где можно найти наш файл, но после изменения конфигурационного файла ld.so.conf необходимо, чтобы система перечитала настройки заново. Это делает программа ldconfig. Пробуем запустить нашу программу:
Как видите все заработало :) Если теперь Вы удалите добавленную нами строку и снова запустите ldconfig, то данные о расположении нашей библиотеки исчезнут и будет появляться таже самая ошибка.
Но описанный метод влияет на всю систему в целом и требует доступа администратора системы, т.е. root. А если Вы простой пользователь без сверх возможностей ?!
Для такого случая есть другое безболезненное решение. Это использование специальной переменной среды LD_LIBRARY_PATH, в которой перечисляются все каталоги содержащие пользовательские динамические библиотеки. Для того, чтобы установить эту переменную в командной среде bash надо набрать всего несколько команд. Для начала посмотрим есть ли у нас такая переменная среды:
У меня в ответ выводится пустая строка, означающая, что такой переменной среды нет. Устанавливается она следующим образом:
После этого программа rezultdyn будет прекрасно работать. В случае, если у Вас в системе эта переменная среды уже уставновлена, то, чтобы не испортить ее значение, надо новый каталог прибавить к старому значению. Делается это другой командой:
Если Вы обнулите эту переменную, то снова библиотека перестанет работать:
Вы также параллельно можете зайти в систему под другим пользователем или даже тем же самым, но если Вы захотите просмотреть значение LD_LIBRARY_PATH, то увидите ее прежнее значение. Это означает, что два разных пользователя Linux не могут влиять на работу друг друга, а это и есть самое главное хорошее отличие систем Unix от большинства других систем.
Многие пользователи Linux рано или поздно сталкиваются с ошибкой error while loading shared libraries. Как правило, при установке программ вручную. Сегодня поговорим об исправлении данной ошибки. Для примера возьмём старый ноутбук с Ubuntu 14.04 LTS, поддержка которой недавно закончилась, а значит что-то приходится доустанавливать вручную.
Ошибка error while loading shared libraries означает, что программа, которую пользователь пытается запустить, не смогла найти необходимую для своего запуска библиотеку. Такое часто случается, если программа устанавливалась не из репозиториев, а вручную. Например, на скриншоте ниже мы видим, что свежая версия Mozilla Firefox требует для своей работы библиотеку libatomic.so.1, но не может её обнаружить.
При этом, кстати, совершенно не обязательно, что данная библиотека отсутствует в системе. Поэтому сперва выполним поиск библиотеки (подробнее о locate в статье по этой ссылке):
Естественно, в Вашем случае библиотека может называться иначе. Смотрите, что упоминается в тексте ошибки.
Если команда ничего не выдаст, это значит, что библиотеки в системе нет (а вот если библиотека найдена, тогда об этом ниже).
Поищем библиотеку в репозиториях:
В результате мы получим перечень пакетов, которые в названии содержат libatomic:
В моем случае речь идёт о стареньком ноутбуке с 32-битной системой, поэтому мой выбор пал на libatomic1. Если Вы собираете программу из исходников, то будет полезным поставить не только библиотеку, но и заголовочные файлы с приставкой -dev. Сама установка проста:
Кстати, иногда команда locate может не выдать Вам информацию о библиотеке, так как, на самом деле она не осуществляет поиск файлов или каталогов. Но это отдельный разговор. Посмотреть, установлена ли библиотека в системе, можно и при поиске пакетов в репозитории. Как видите, наш пакет libatomic1 теперь помечен как установленный.
Теперь о том, что делать, если библиотека есть в системе, но ошибка error while loading shared libraries всё равно появляется. Очень часто причиной этого является то, что загрузчик ОС не может найти библиотеку. По умолчанию поиск производится в каталогах: /usr/lib, /lib, /usr/lib64, /lib64. Не исключено, что библиотека просто лежит за пределами этих каталогов.
Вариантов тут несколько: переместить или скопировать библиотеку, ну или же указать загрузчику, где её искать. Последний способ более корректный, так как при нём Вы точно ничего не напортачите в системе.
Можно зайти в папку /etc/ld.so.conf.d/, открыть там любой конфигурационный файл и просто прописать местонахождение нужной библиотеки.
А можно сделать символьную (символическую) ссылку:
ln -s [путь_к_библиотеке/имя_библиотеки] /usr/lib/[имя_библиотеки]
Есть ещё одна причина ошибки while loading shared libraries даже когда нужна библиотека имеется в операционной системе. Библиотека может быть не той версии.
Версия библиотеки (или ещё её называют ревизией) пишется после расширения .so. В нашем примере нам требовалась библиотека libatomic.so.1, т.е. libatomic первой версии.
В разных дистрибутивах используются разные версии библиотек, а программы собираются под дистрибутив (и, как следствие, библиотеку конкретной версии). На практике же различия между версиями библиотек чаще всего минимальны. Поэтому для начала можно выдать библиотеку одной версии за библиотеку другой версии. В этом нам опять поможет символьная ссылка:
ln -s [путь_к_библиотеке/настоящее_имя_библиотеки] [путь_к_библиотеке/имя_библиотеки_с_нужной_версией]
И последнее: после манипуляций с библиотеками желательно обновить кэш командой
Вот, пожалуй, и всё, что нужно знать про ошибку error while loading shared libraries.
Система Fedora 20 (Heisenbug) x86_64
Устанавливается 1С Предприятие 8.3.4.428 x86_64 сервер и клиент на Linux и клиент 32 разр на windows.
Результат толстый клиент - работает без проблем.
Тонкий клиент (режим управл. приложения)после ввода пароля завершается с ошибкой:
"Ошибка загрузки библиотеки libWand.so по причине:Библиотека не обнаружена."
Начинаем разбираться:
1) Что у нас есть:
yum info ImageMagick выдает
Available Packages
Name : ImageMagick
Arch : x86_64
Version : 6.8.6.3
Release : 3.fc20
Size : 147 k
Repo : fedora/20/x86_64
Библиотеки этого пакета:
/usr/lib64/libMagickWand-6.Q16.so.1.0.0
Теперь самое интересное - что все таки происходит? Тут не обойтись без strace - утилита для отслеживания системных вызовов.
Находим pid рабочего процесса 1С rphost:
ps -afx | grep rphost
Желательно чтобы был один процесс rphost. Дело в том, что в 8.3 мы уже не можем создавать или удалять процессы - все в автомате.
Подключимся к рабочему процессу и выловим все системные вызовы.
Для этого:
Откроем 1С на клиенте и остановимся на моменте когда пароль набран , но еще не нажата кнопка ОК. (Это для того, чтобы не собирать слишком большой файл логов strace ).
В консоли сервера вводим
strace -p <Ваш pid> -f -s 512 -o /root/123456.txt
(-f - обязательно указываем отслеживать все порожденные субпроцессы,
-s 512 - длина строки в логах , стандартное значение слишком маленькое,
-o - это имя файла логов)
и нажимаем Enter, затем сразу нажимаем Ок в форме ввода пароля 1С, после вывода ошибки 1С, останавливаем strace и изучаем файл логов.
Ищем строку с вхождением "Wand" и получаем:
18507 execve("/bin/sh", ["sh", "-c", "/sbin/ldconfig -p | grep -P '^[\\t ]*libMagickWand.so\\.1' | sort -r | sed -e 's/.*=>[\\t ]*//'"], [/* 22 vars */]) = 0
Это вызов "ldconfig -p", в котором ищется подстрока libMagickWand.so.
Но этой подстроки нет, т.к. в ImageMagick 6.8.6.3 нет такой библиотеки, она переименована в libMagickWand-6.Q16.so.
Но 1С попрежнему ищет библиотеку libMagickWand.so, причем анализируя вывод ldconfig - т.е. если мы сделаем симлинк (ln -s) это не поможет т.к все равно не попадет в вывод ldconfig.
Почему так сделано ? Не понятно.
Далее мне пришлось найти последний пакет до переименования от CENTOS-
ImageMagick-6.7.9-10.src.rpm (Это исходник - мы будем делать rpmbuild )
Затем перезапустим сервер.
После этого у меня все заработало.
Наименование библиотек пакета libMagickWand изменилось в 2013 году начиная с версии 6.8
Читайте также: