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

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

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

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

一位同事向我介绍了这篇博客文章:http://www.trilithium.com/johan/2005/06/static-libstdc/ 建议不要使用动态加载的C++代码。

另一位同事向我指出了这个错误报告: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是否继续采用这种方法?

[编辑:我在OpenJDK的构建开发邮件列表中问了这个问题。答案是肯定的,HotSpot仍然静态链接libstdc ++,但显然“大多数Linux发行版都对此进行了修补”。另一位开发人员指出,这甚至不需要补丁:“设置STATIC_CXX=false应该足够了(它默认为true)。

其次,即使在这种情况下,同时加载两个不兼容的libstdc++..真的是良性的吗?

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

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

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

话又说回来,也许ABI不兼容不再是问题。这篇博客文章已有六年多的历史了。另一个堆栈溢出问题(GCC ABI兼容性)的一个答案断言“由于gcc-3.4.0,ABI是向前兼容的。成功了吗?

我非常感谢有关这些问题的任何指导。(嘿,感谢您阅读所有这些内容!

编辑

我的问题很长,所以我没有给出所有的细节。为了解决Will的评论:

  1. 我只需要调用外部“C”函数。(例如,我使用javah来生成C头文件。
  2. 我不需要在JVM中与C++运行时进行交互。(我基本上只需要将字符串发送到C++库。

答案 1

我不知道。但这从未阻止我。

首先,这取决于你想做什么。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++运行时安装的操作系统的摆布。

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


答案 2

推荐