Java 本机接口 (JNI) 是否受 C++ ABI 兼容性问题影响?
我正在开发一个 Java 应用程序。我想使用 Java 本机接口 (JNI) 来调用 C++ 库中的函数。我可以访问 C++ 库的代码,并且可以根据需要重建它。 (例如,我可以静态链接 C++ 运行时。)
我可以要求我的用户拥有 JRE 6 或更高版本,但我不能要求他们拥有任何特定的 C++ 运行时。
一位同事向我推荐了这篇博客文章:http://www.trilithium.com/johan/2005/06/static-libstdc/ http://www.trilithium.com/johan/2005/06/static-libstdc/建议不要使用动态加载的 C++ 代码。
另一位同事向我指出了这个错误报告:https://bugs.java.com/bugdatabase/view_bug?bug_id=4694590 https://bugs.java.com/bugdatabase/view_bug?bug_id=4694590其中详细介绍了 Java 1.4.2 中如何解决这些问题。
据我了解,问题的要点是libstdc++的二进制接口经常发生变化。如果 C++ 应用程序加载使用不同编译器构建的 C++ 共享库,则两个不兼容的 libstdc++ 库将同时加载到内存中。
该错误报告解释了 Java 1.4.2 的解决方案:“我们在 JDK 中静态链接 C++ 运行时,并启用链接描述文件来隐藏 libstdc++ 和其他内部符号中的符号。结果,这些符号对 JNI 代码变得不可见,并且当某些本机代码需要调用 C++ 运行时,该调用将使用适当的 libstdc++.so 进行解析。仍然有两个 libstdc++.so 同时加载,但它应该是良性的。”
我对此有几个问题。
首先,OpenJDK 会继续采取这种做法吗?
[EDIT:我在 OpenJDK 的构建开发邮件列表上问了这个问题。答案是肯定的,HotSpot 仍然静态链接 libstdc++,但显然“大多数 Linux 发行版都修补了这个问题”。另一位开发人员指出,这甚至不需要补丁:“设置
STATIC_CXX=false 应该足够了(默认为 true)。"]
其次,即使在这种情况下,同时加载两个不兼容的 libstdc++.so 真的是良性的吗?
第三,这种方法(隐藏 JDK 中的符号)是否解决了所有兼容性问题?
上面引用的博客文章警告说“针对不同 ABI 编译的代码根本不兼容二进制”。后来,“语言运行时支持通常依赖于共享的某些数据,例如访问某种锁或全局数据结构(类似于 C 程序需要共享 errno)。”
这听起来似乎问题无法解决。
话又说回来,也许 ABI 不兼容不再是问题了。这篇博客文章已有六年多了。另一个 stackoverflow 问题的答案(GCC ABI 兼容性 https://stackoverflow.com/questions/2801938/gcc-abi-compatibility)断言“自 gcc-3.4.0 起,ABI 向前兼容。”那成功了吗?
如果您对这些问题有任何指导,我将不胜感激。 (嘿,感谢您阅读所有这些!)
EDITS
我的问题太长了,所以我没有给出所有细节。针对威尔的评论:
- 我只需要调用外部“C”函数。 (例如我使用javah生成C头文件。)
- 我不需要与 JVM 中的 C++ 运行时交互。 (我基本上只需要将字符串发送到 C++ 库。)