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

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

我正在开发一个Java应用程序。 我想使用Java Native Interface(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 ++解析。所以。还有两个libstdc ++。所以同时加载,但它应该是良性的。“

我有几个问题。

首先,OpenJDK是否继续采用这种方法?

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

其次,即使在这种情况下,拥有两个不兼容的libstdc ++是否真的是良性的。所以同时加载?

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

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

这使得听起来无法解决问题。

再说一遍,也许ABI不兼容不再是问题。 博客文章已有六年多了。 另一个stackoverflow问题( GCC ABI兼容性 )的答案断言“自从gcc-3.4.0起,ABI是向前兼容的”。 那是成功的吗?

我对这些问题的任何指导表示感谢。 (嘿,谢谢阅读所有这些!)

EDITS

我的问题变得越来越长,所以我没有详细说明。 解决Will的评论:

  1. 我只需要调用extern“C”函数。 (例如,我使用javah生成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可移植性问题,因为它将动态链接,并且将受OS安装的C ++运行时的支配。

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

Interesting Posts