Java本机接口(JNI)是否受到c++ ABI兼容性问题的影响



Java Native Interface (JNI)是否受到c++ ABI兼容性问题的影响?

我正在开发一个Java应用程序。我想使用Java本机接口(JNI)来调用c++库中的函数。我可以访问c++库的代码,我可以重建它,但我可能需要。(例如,我可以静态地链接c++运行时。)

我可以要求我的用户有JRE 6或更高版本,但我不能要求他们有任何特定的c++运行时。

一个同事给我看了这篇博客文章:http://www.trilithium.com/johan/2005/06/static-libstdc/,里面建议不要使用动态加载的c++代码。

另一位同事给我指了这个bug报告:http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4694590,其中详细说明了这些问题是如何在Java 1.4.2中解决的。

问题的要点,据我所知,是libstdc++的二进制接口经常改变。如果一个c++应用程序加载了一个用不同编译器构建的c++共享库,那么两个不兼容的libstdc++库将同时加载到内存中。

错误报告解释了Java 1.4.2的解决方案:"我们静态地链接JDK中的c++运行时,并启用链接器脚本来隐藏libstdc++和其他内部符号的符号。因此,这些符号对JNI代码是不可见的,当一些本地代码需要调用到c++运行时时,调用将使用适当的libstdc++.so进行解析。仍然有两个libstdc++。所以同时加载,但应该是良性的。"

我有几个问题。

首先,OpenJDK会继续采用这种方法吗?

[EDIT:我在OpenJDK的build-dev邮件列表中问了这个问题。答案是肯定的,HotSpot仍然静态地链接libstdc++,但显然"大多数Linux发行版都修补了这个问题"。另一位开发者指出,这甚至不需要补丁:"设置STATIC_CXX=false应该就足够了(默认为true)。"]

第二,即使在这种情况下,拥有两个不兼容的libstdc++真的是良性的吗?同时装载?

第三,这种方法(隐藏JDK中的符号)解决了所有的兼容性问题吗?

上面引用的博客文章警告说:"针对不同abi编译的代码根本不兼容二进制。"后来,"语言运行时支持通常依赖于共享的一些数据,例如访问某种锁或全局数据结构(类似于C程序需要共享errno)。"

这听起来好像这个问题无法解决。

然后,也许ABI不兼容不再是一个问题了。这篇博客已经写了六年多了。另一个stackoverflow问题(GCC ABI兼容性)的一个答案断言:"从GCC -3.4.0开始,ABI是向前兼容的。"成功了吗?

我很感激在这些问题上的任何指导。(嘿,谢谢你读这一切!)

编辑

我的问题很长,所以我没有给出所有的细节。回复Will的评论:

  1. 我只需要打电话给外面的"C"功能。(例如,我使用java生成C头文件。)
  2. 我不需要与JVM中的c++运行时交互。(我基本上只需要发送字符串到c++库。)

我不知道。但这从来没有阻止过我。

首先,这取决于你想做什么。JDK的静态链接背后的前提是提高实际JDK本身的可移植性。因为他们不能指望用户在他们特定的操作系统上重新编译JDK,所以他们需要一种机制来使最终的二进制文件可移植。显然静态链接修复了这个问题。

接下来,关于JNI,首先你将调用C函数而不是c++,我不相信JNI有任何类型的c++绑定。因此,无论你想使用什么c++,都需要封装在C例程中,以便与Java对话。

接下来,你的c++ .so将动态链接到操作系统,就像我猜的那样。期望JNI例程不能与动态链接的。so一起工作似乎是相当苛刻的,而c++的。so应该没有什么不同。而且,毫无疑问,c++像现在这样流行,你不能动态地链接到一个c++ .so,这似乎也很苛刻。因此,无论需要采取什么诡计来促进这一点,都可以合理地假设,他们(tm)已经做了允许这一切发生的工作。

也就是说,当然不应该期望您使用的任何c++都将与Java运行时中的c++运行时进行任何交互。理想情况下,他们会和平共处。

考虑到这一点,假设这是有效的,你的c++肯定会有ABI可移植性问题,因为它将是动态链接的,并且将受操作系统安装的c++运行时的支配。

所以,最后,我只是给它一个撕裂,看看会发生什么

最新更新