Является ли интерфейс Java Native (JNI) затронутым проблемами совместимости с С++ ABI?

Является ли интерфейс Java Native (JNI) затронутым проблемами совместимости с С++ ABI?

Я разрабатываю Java-приложение. Я хотел бы использовать Java Native Interface (JNI) для вызова функций в библиотеке С++. У меня есть доступ к коду для библиотеки С++, и я могу его перестроить, но мне может понадобиться. (Например, я могу статически связать время выполнения С++.)

Я могу потребовать, чтобы мои пользователи имели JRE 6 или больше, но я не могу требовать от них какой-либо конкретной среды выполнения С++.

Сотрудник указал мне на эту статью в блоге: http://www.trilithium.com/johan/2005/06/static-libstdc/, который советует не использовать динамически загруженный код на С++.

Другой сотрудник указал мне на этот отчет об ошибке: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4694590, в котором подробно описывается, как эти проблемы были адресованы обратно в Java 1.4.2.

Суть проблемы, как я понимаю, в том, что бинарный интерфейс libstdС++ часто изменяется. Если приложение С++ загружает общую библиотеку С++, которая была построена с другим компилятором, две несовместимые библиотеки libstdС++ будут загружены в память одновременно.

В отчете об ошибке объясняется решение для Java 1.4.2: "Мы статически связываем среду выполнения С++ в JDK и включенный компоновщик script, чтобы скрыть символы из libstdС++ и других внутренних символов. В результате эти символы становятся невидимыми для JNI код, а когда какой-то собственный код нужно вызвать в С++ runtime, вызов будет разрешен с помощью соответствующего libstdС++. Таким образом, есть еще два libstdС++, поэтому они загружаются одновременно, но они должны быть доброкачественными."

У меня есть несколько вопросов об этом.

Во-первых, продолжает ли OpenJDK использовать этот подход?

[ EDIT: Я задал этот вопрос в списке рассылки OpenJDK build-dev. Ответ: да, HotSpot все еще статически связывает libstdС++, но, по-видимому, "большинство дистрибутивов Linux исправляет это". Другой разработчик отмечает, что для этого даже не требуется патч: "Настройка STATIC_CXX = false должно быть достаточно (по умолчанию оно равно true). "]

Во-вторых, даже в этом случае, действительно ли полезно иметь два несовместимых libstdС++, загруженных одновременно?

В-третьих, поддерживает ли этот подход (чтобы скрыть символы в JDK) все проблемы совместимости?

В статье в блоге, приведенной выше, предупреждается, что "код, составленный для разных ABI, просто не совместим с бинарными". И позже, что "поддержка времени выполнения языка обычно полагается на некоторые совместно используемые данные, например, для доступа к какой-либо блокировке или глобальной структуре данных (подобно тому, как программы на C требуют совместного использования errno).

Это звучит так, будто проблема не может быть решена.

Опять же, возможно, несовместимость ABI больше не проблема. Статья в блоге старше шести лет. Один ответ для другого вопроса о stackoverflow (совместимость GCC ABI) утверждает, что "Начиная с gcc-3.4.0, ABI совместим с переходом". Успешно ли это?

Буду признателен за любые рекомендации по этим вопросам. (И эй, спасибо, что прочитал все это!)

редактирует

Мой вопрос становился довольно длинным, поэтому я не дал всей специфики. Чтобы отправить комментарии Уилла:

  • Мне нужно только вызвать внешние функции "С". (Например, я использую javah для создания файла заголовка C.)
  • Мне не нужно взаимодействовать со средой выполнения С++ в JVM. (Мне просто нужно отправить строки в библиотеку С++.)

Ответ 1

Я не знаю. Но это меня не остановило.

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

Далее, в отношении JNI, сначала вы будете называть C-функции, а не С++, я не верю, что JNI имеет любое связывание на С++. Итак, любой С++, который вы хотите использовать, должен быть завернут в подпрограмму C, чтобы поговорить с Java.

Затем ваш С++.so будет динамически связываться с ОС в значительной степени, как обычно, я предполагаю. Кажется довольно драконовским ожидать, что подпрограмма JNI не будет работать с динамической связью .so, а С++.so не должен отличаться. И, без сомнения, С++ настолько популярен, как кажется, кажется драконовским, что вы не сможете динамически связываться с С++.so. Итак, какими бы ни были махинации, которые должны были произойти для облегчения этого, разумное предположение о том, что они (tm) сделали работу, чтобы это произошло.

Тем не менее, не должно быть никаких ожиданий о том, что любой С++, который вы используете, будет иметь какое-либо взаимодействие со средой выполнения С++ в среде выполнения Java. В идеальном случае они просто мирно сосуществуют.

Учитывая, что, предполагая, что это вообще работает, ваш С++, безусловно, будет иметь проблему с переносимостью ABI, поскольку он будет динамически связываться и будет во власти OS'ы, установленной на С++.

Итак, в конце концов, я просто даю ему рип и посмотрю, что произойдет.