Загрузка статически скомпилированной библиотеки в Java

#java #c #java-native-interface

#java #c #java-native-интерфейс

Вопрос:

У меня возникли проблемы с загрузкой статически скомпилированной библиотеки из Java с помощью System.LoadLibrary («»), но я могу загрузить ее как динамически скомпилированную библиотеку (когда я создаю ее таким образом) просто отлично. Я использую JDK 8, и, насколько я понимаю, он может загружать статические библиотеки через System.LoadLibrary(«»), если вы укажете JNI_OnLoad_L в файлах * .cpp и * .h .

Мой kdu_jni.h имеет:

 extern "C"
JNIEXPORT jint JNICALL JNI_OnLoad_kdu_1jni(JavaVM *, void *);
  

Мой kdu_jni.cpp имеет:

 JNIEXPORT jint JNICALL JNI_OnLoad_kdu_1jni(JavaVM *vm, void *reserved)
{
  return JNI_VERSION_1_8;
}
  

У меня есть файл libkdu_jni.a в моем каталоге java.library.path, когда я пытаюсь запустить скомпилированную версию. Он отлично работает с libkdu_jni.so файл в том же каталоге, когда я пытаюсь загрузить его динамически. При попытке со статическим файлом (libkdu_jni.a) я получаю:

 Exception in thread "main" java.lang.UnsatisfiedLinkError: no kdu_jni in java.library.path
    at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1867)
    at java.lang.Runtime.loadLibrary0(Runtime.java:870)
    at java.lang.System.loadLibrary(System.java:1122)
  

Я извлек файл .so, прежде чем пытаться загрузить файл .a.

Я не уверен, что я делаю неправильно. Я не думаю, что он даже видит JNI_OnLoad_kdu_1jni() файла libkdu_jni.a, потому что я вставил туда исключение и не вижу, чтобы оно выдавалось. Я пробовал несколько итераций с этим именем: JNI_OnLoad_kdu_jni(), JNI_OnLoad_kdu_1jni(), JNI_OnLoad() и т.д.

Есть идеи?

Комментарии:

1. Обернуто ли определение JNI_OnLoad_kdu_1jni extern "C" ? Единственное, что я бы посоветовал попробовать, это назвать библиотеку чем-то простым, например «L.a».

2. Вы не можете загружать статически скомпилированные библиотеки. Вы должны связать их с .so или .dll. Ваш вопрос не имеет смысла.

3. @EJP Java8 теперь поддерживает загрузку статических библиотек. Я собирался вставить комментарий, подобный вашему, но JEP 178 меняет ситуацию.

4. @EdwinBuck Невозможно. Статическая библиотека предназначена для ввода в компоновщик, а не в качестве исполняемого файла. Например, ссылки внутри библиотеки не разрешаются. В JEP 178 описана библиотека, статически связанная с JVM. Этап связывания остается важным.

5. Я не могу найти хорошего объяснения, но я считаю, что это вообще не работает: смотрите здесь .

Ответ №1:

насколько я понимаю, он может загружать статические библиотеки через System.LoadLibrary(«»), если вы укажете JNI_OnLoad_L в файлах * .cpp и * .h .

Ваше понимание неверно. Вы не можете загружать .a файл динамически. Он не является исполняемым ни в какой форме или форме:

  • ссылки на инфрабиблиотеку не разрешены
  • ссылки за пределами библиотеки также не разрешаются: например, на библиотеку C.

Шаг связывания необходим, и JVM не делает этого за вас. То, что вы прочитали, относится к библиотекам, статически связанным с JVM.

Комментарии:

1. Так что, я думаю, я застрял в компиляции динамической библиотеки для платформ с разными версиями glibc. Это, вероятно, проще, чем скомпилировать один исполняемый файл с включенной JVM.

2. Вы можете статически связать предпочитаемый вами glibc с динамической библиотекой вместо того, чтобы использовать динамическую библиотеку.

3. Спасибо, я здесь на новой территории. Я буду исследовать в этом направлении, если это возможно.

Ответ №2:

Я предлагаю вам попробовать JNI_OnLoad_kdu_jni в качестве имени функции. Если это не сработает, это может не сработать с именами библиотек, которые содержат символ подчеркивания.

— Исходное сообщение следует —

До Java 8 поддерживались только библиотеки общих объектов.

Это означает, что для того, чтобы узнать, является ли статическая библиотека Java 8, в библиотеке должна быть реализована новая функция.

 JNI_OnLoad_libname must return a value of JNI_VERSION_1_8 or higher.
  

Я предполагаю, что, поскольку ваш код работает динамически, но не статично, возможно, эта функция отсутствует. Приведенная ниже часть JEP 178 заставляет меня поверить в это:

Спецификации java.lang.Методы System.LoadLibrary и java.lang.Runtime.LoadLibrary будут пересмотрены для чтения:

Загружает собственную библиотеку, указанную аргументом libname. Имя библиотеки не должно содержать префикса, расширения файла или пути, зависящего от платформы.

Если собственная библиотека с именем libname статически связана с виртуальной машиной, то вызывается функция JNI_OnLoad_libname, экспортируемая библиотекой. Более подробную информацию см. в спецификации JNI.

В противном случае имя библиотеки загружается из расположения системной библиотеки и отображается в образ собственной библиотеки в зависимости от реализации.

Также примечания в улучшении отражают это мнение

Исходный код для загрузчика полезен

Я бы запустил java в debug (gdb) и поставил точку останова в at Java_java_lang_ClassLoader_00024NativeLibrary_findBuiltinLib . Вы правы, хороших примеров не так много.

Комментарии:

1. «Статически связанный с JVM» — это не то же самое, что «статически скомпилированная библиотека».

2. @EJP Спасибо, что указали на это. Я умолчал об этом, и да, кажется, что кто-то пытается динамически загружать статическую библиотеку, когда на самом деле она не поддерживается.