Как отладить ошибку java system.loadlibrary в Linux?

У меня есть программа Java, которая вызывает код C через JNI, которую я пытаюсь запустить в Linux. Внешний код состоит из двух файлов .so: один для привязок JNI (созданный с помощью swig), а другой — с фактическими функциями. У меня есть две библиотеки в одном каталоге, и LD_LIBRARY_PATH установлен правильно. ldd не сообщает о проблемах при запуске из командной строки, но когда я устанавливаю LD_LIBRARY_PATH в то же значение в диалоговом окне «запуск конфигураций» в редакторе Eclipse и пытаюсь выполнить программу, появляется следующая ошибка:

java.lang.UnsatisfiedLinkError: [путь к библиотекам]/[библиотека привязки JNI].so: [фактическая библиотека кода].so: невозможно открыть общий объектный файл: нет такого файла или каталога

Это наводит меня на мысль, что библиотека-оболочка JNI успешно загружена, но происходит сбой, когда эта библиотека пытается загрузить библиотеку, содержащую фактический код. Есть ли способ отладить это дальше?

Я также отмечу, что эта проблема возникает в самом редакторе eclipse и что я не пытался упаковать код в банку и запустить его в отдельном экземпляре jvm.


person user98166    schedule 18.06.2009    source источник


Ответы (7)


Я думаю, что проблема связана с вызовом System.loadLibrary(String) и использованием LD_LIBRARY_PATH. Использование loadLibrary("foo") будет искать в вашем java.library.path что-то с именем libfoo.so. Если ничего с именем libfoo.so не найдено, вы получите эту ошибку.

Теперь, если вы просто настроите LD_LIBRARY_PATH, нужные вам собственные символы будут автоматически выбраны компоновщиком, поэтому вам не нужно настраивать -Djava.library.path.

По моему опыту работы с swig в проекте gdal, эта ошибка на самом деле безобидна, и поскольку LD_LIBRARY_PATH настроен, это будет работать нормально.

Я бы порекомендовал использовать -Djava.library.path и вызвать loadLibrary явно, причина в том, что если вы когда-нибудь решите развернуть свое приложение с помощью webstart, вам нужно будет явно вызвать loadLibrary, чтобы получить ваши собственные библиотеки.

Когда я использую eclipse, я следую инструкциям, которые дал Дафф, где вы редактируете собственную библиотеку под банкой на вкладке «Библиотеки» в пути сборки. Просто напомню еще раз, что это просто устанавливает java.library.path под обложки.

person carrino    schedule 24.06.2009

Возможно, вам просто нужно найти правильное место в диалоговом окне конфигурации запуска, чтобы указать параметр -Djava.library.path=.... Навскидку, я думаю, вы хотите, чтобы -D определял в «аргументах vm» на вкладке аргументов, тогда как если вы хотите определить LD_LIBRARY_PATH, который идет на вкладке среды. Eclipse весело позволит вам размещать вещи в местах, где они не будут означать то, что вы думаете. В любом случае, я использовал библиотеки таким образом раньше, и если у меня будет возможность, я посмотрю, что я сделал, и отредактирую свой ответ здесь.

Еще одна вещь, которую стоит попробовать, это поиграть с LD_DEBUG. Вы можете установить переменную окружения LD_DEBUG на разные вещи (попробуйте ВСЕ), и тогда загрузчик linux выдаст всевозможную полезную информацию о том, что приложение пытается загрузить, где оно ищет что-то и т. д. , Конечно, это предполагает, что вы запускаете eclipse из командной строки, так что вы можете установить env vars и посмотреть диагностику загрузчика; но что касается системы, когда вы запускаете свое приложение из eclipse, ваше приложение - это просто то, что делает eclipse, поэтому любое поведение загрузки библиотеки можно увидеть таким образом.

person JustJeff    schedule 24.06.2009

Возможно, вы могли бы попробовать -Djava.library.path=actual.so в параметрах командной строки?

В Windows у меня были аналогичные проблемы со сторонней библиотекой, которая использовала DLL-оболочку JNI для своих DLL. В моем проекте DLL была в каталоге lib, поэтому я добавил lib в PATH (например, переменную среды PATH=%PATH%;./lib, и все заработало.

person akarnokd    schedule 18.06.2009

Насколько я знаю, Eclipse не использует LD_LIBRARY_PATH. Самый простой способ настроить правильный путь к собственной библиотеке — перейти к свойствам проекта -> Путь сборки Java -> Библиотеки. Расположение библиотеки", затем нажмите "Изменить..." и выберите папку, в которой находятся ваши библиотеки. На самом деле она устанавливает переменную -Djava.library.path, поэтому вам нужно включить ее в свою командную строку, если вы запускаете свою программу из-за пределов eclipse. .

person Daff    schedule 18.06.2009

Существуют ли какие-либо другие библиотеки, от которых зависят ваши две библиотеки? Если это так, вам нужно убедиться, что они также доступны для JVM.

Имейте в виду, что ручная установка «-Djava.library.path», похоже, стирает путь к библиотеке по умолчанию.

Итак, со следующим кодом:

public class LibTest {
    public static void main(String[] args) {
        String property = System.getProperty("java.library.path");
        StringTokenizer parser = new StringTokenizer(property, ":");
        while (parser.hasMoreTokens()) {
            System.err.println(parser.nextToken());
        }
    }
}

Запущено из eclipse с выводами Java 1.6.0_14:

/opt/java/jre/lib/i386/client
/opt/java/jre/lib/i386
/opt/java/jre/../lib/i386
/opt/java/jre/lib/i386/client
/opt/java/jre/lib/i386
/usr/lib/xulrunner-devel-1.9.0.11
/usr/lib/xulrunner-devel-1.9.0.11
/usr/java/packages/lib/i386
/lib
/usr/lib

Но когда я устанавливаю аргумент JVM "-Djava.library.path=/tmp/", я получаю только:

/tmp/

Если вы вручную устанавливаете java.library.path, это может объяснить, почему ldd работает из командной строки, а ваш .so не работает из eclipse/java.

Вы можете попробовать не устанавливать java.library.path и использовать System.load с абсолютным путем к вашей библиотеке вместо вызова System.loadLibrary. Это может позволить JVM найти ваш .so и по-прежнему использовать путь по умолчанию при поиске его зависимостей.

Конечно, если это бесполезно, вы также можете попробовать включить отладочный вывод jni с помощью «-verbose:jni» в командной строке. Это может дать вам некоторые подсказки к проблеме.

person Aaron    schedule 29.06.2009

Да, LD_LIBRARY_PATH у меня работал

person MSSV    schedule 10.11.2010

Добавление этого ответа может быть полезным. На компьютерах AIX нам нужно настроить переменную среды LIBPATH вместо LD_LIBRARY_PATH.

person Dungeon Hunter    schedule 20.11.2012