#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 Спасибо, что указали на это. Я умолчал об этом, и да, кажется, что кто-то пытается динамически загружать статическую библиотеку, когда на самом деле она не поддерживается.