Связывание статической библиотеки с JNI

#java #java-native-interface #static-libraries #java-8 #static-linking

#java #java-native-interface #статические библиотеки #java-8 #статическое связывание

Вопрос:

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

Как я могу статически связать библиотеку JNI с моим java-приложением?

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

1. Где ты это прочитал? Пожалуйста, предоставьте некоторые доказательства 🙂

2. Видел это на странице истории версий Java в Википедии, их источнике: openjdk.java.net/jeps/178

Ответ №1:

Спецификация Java SE 8 была изменена для поддержки статического связывания, а статическое связывание реализовано в JDK. Это кратко упоминается в спецификации для System.LoadLibrary. Разделы спецификации JNI, на которые она ссылается, находятся здесь и здесь .

Сигнатуры собственных методов и типы данных одинаковы для статически и динамически связанных методов. Возможно, вам придется взломать файлы JDK makefile, чтобы заставить его статически связать вашу библиотеку.

Одним из существенных отличий является способ инициализации статических библиотек. Динамические библиотеки инициализируются вызовом JNI_OnLoad функции и деинициализируются вызовом JNI_OnUnload . Каждая динамическая библиотека может иметь свою собственную версию этих функций. Если существует несколько статически связанных библиотек, очевидно, что все они не могут иметь функции с одинаковыми именами. Для статической библиотеки с именем libname функции загрузки / выгрузки являются JNI_OnLoad_libname и JNI_OnUnload_libname .

JNI_OnLoad_libname Функция должна возвращать значение JNI_VERSION_1_8 или выше. Если этого не произойдет, JVM будет игнорировать статическую библиотеку.

По сути, при вызове System.loadLibrary("foo") система ищет функцию JNI_OnLoad_foo в исполняемом образе, и если она найдена, предполагается, что библиотека статически связана, а ее собственные методы ищутся в исполняемом образе. Если JNI_OnLoad_foo не найдено, то выполняется обычный поиск и загрузка динамических библиотек, и собственные методы связываются из найденной таким образом динамической библиотеки.

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

1. Спасибо за ваш ответ. Но теперь я немного не уверен. Могу ли я по-прежнему использовать javah для создания заголовка для источника или мне нужно самому называть методы и тому подобное?

2. @chmod Механика написания самого собственного метода должна быть такой же, как и для динамических нативов. Отличия от static заключаются в том, что вам нужно скомпилировать и связать свой собственный код для создания статической библиотеки, а затем выполнить второй шаг, чтобы связать эту статическую библиотеку с самой JVM.

3. Хорошо, вы знаете, как я могу изменить свой JDK, чтобы заставить его работать с моей библиотекой?

4. @chmod Я не думаю, что вы можете модифицировать предварительно созданный JDK, поскольку (я полагаю) нельзя связать дополнительную статическую библиотеку с исполняемым файлом. Если вы создаете из исходного кода, вам может потребоваться взломать makefile с дополнительными аргументами или настройками переменных, чтобы предоставить статические библиотеки команде компоновщика. Смотрите vm.make из OpenJDK, например, рядом со строками 320 и далее.

5. Не забудьте сделать так, чтобы ваша JNI_OnLoad_X функция возвращала как минимум JNI_VERSION_1_8 , иначе библиотека будет молча проигнорирована.

Ответ №2:

В соответствии с JEP 178, на который вы ссылались в своем комментарии, вам не нужно ничего делать по-другому. System.loadLibrary теперь будут загружены как динамические, так и статические библиотеки.

Не требуется вносить изменения в существующий Java-код, чтобы использовать статическую встроенную библиотеку в отличие от динамической встроенной библиотеки. Вызов метода формы System.LoadLibrary («foo»), в частности, должен иметь возможность загружать библиотеку «foo» независимо от того, предоставляется ли эта библиотека в статической или динамической форме.

Вероятно, вам просто нужно убедиться, что ваш java.library.path установлен правильно.

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

1. Итак, единственное, что мне нужно сделать по-другому по сравнению с разделяемой библиотекой, это скомпилировать ее по-другому? Никаких изменений в коде C / C ?

2. @user3525110 Никаких изменений ни в Java, ни в C-коде. Просто используйте любые параметры компилятора, которые вы обычно используете, для создания общей или статической библиотеки из скомпилированных объектных файлов C.

3. Действительно ли это работает? Я получил статическую библиотеку (файл .a), но даже если я правильно установил java.library.path, библиотека не найдена: «Исключение в потоке «main» java.lang. Ошибка UnsatisfiedLinkError: нет <library> в java.library.path». Я использую Java 8 и Debian.

4. @little_planet: нет, вы не можете просто скопировать статическую библиотеку в path. Новый подход актуален только для тех, кто встраивает JVM в свой исполняемый файл.

Ответ №3:

Улучшение Java 8 https://openjdk.java.net/jeps/178 предназначен для JVM.

Даны два файла:

  • Main.java
  • Main.c

Создать libnative.so:

 javac Main.java
javah Main
gcc -c Main.c
gcc -c Main.c -I /home/dx/.sdkman/candidates/java/current/include/linux -I /home/dx/.sdkman/candidates/java/current/include
gcc -shared -o libnative.so Main.o
  

Создайте libnative.a:

 ar -cvq libnative.a Main.o
  

Для каждого libnative.a, libnative.so тестовый запуск через:

 java -Djava.library.path=.  Main
  

Результат:

  • Успешное выполнение при libnative.so
  • Сбой выполнения при libnative.a

Это доказывает, что 178 для JVM.

Ссылки:

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

1. Так разве невозможно использовать статическую библиотеку в Linux? Это работает в Windows