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

发布于 2024-12-23 23:26:39 字数 1775 浏览 1 评论 0原文

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

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

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

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

另一位同事向我指出了这个错误报告: 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 会继续采取这种做法吗?

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

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

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

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

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

话又说回来,也许 ABI 不兼容不再是问题了。这篇博客文章已经有六年多了另一个 stackoverflow 问题(GCC ABI 兼容性)的一个答案断言“自gcc-3.4.0,ABI 向前兼容。” 成功了吗?如果

您能就这些问题提供指导,我将不胜感激。 (嘿,感谢您阅读所有这些!)

编辑

我的问题很长,所以我没有提供所有细节。针对 Will 的评论:

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

Is the Java Native Interface (JNI) affected by C++ ABI compatibility issues?

I am developing a Java application. I would like to use the Java Native Interface (JNI) to call functions in a C++ library. I have access to the code for the C++ library, and I can rebuild it however I may need to. (For example, I can statically link the C++ runtime.)

I can require my users to have JRE 6 or greater, but I can't require them to have any particular C++ runtime.

A coworker pointed me to this blog article: http://www.trilithium.com/johan/2005/06/static-libstdc/ which advises against using dynamically loaded C++ code.

Another coworker pointed me to this bug report: https://bugs.java.com/bugdatabase/view_bug?bug_id=4694590 which details how these issues were addressed back in Java 1.4.2.

The gist of the problem, as I understand it, is that the binary interface of libstdc++ often changes. If a C++ application loads a C++ shared library that was built with a different compiler, two incompatible libstdc++ libraries will be loaded into memory at the same time.

The bug report explains the solution for Java 1.4.2: "We statically link the C++ runtime in JDK and enabled linker script to hide symbols from libstdc++ and other internal symbols. As the result, those symbols become invisible to JNI code, and when some native code needs to call into C++ runtime, the call will be resolved with the appropriate libstdc++.so. There are still two libstdc++.so being loaded at the same time, but it should be benign."

I have a few questions about this.

First, does OpenJDK continue to take this approach?

[EDIT: I asked this question on OpenJDK's build-dev mailing list. The answer is yes, HotSpot still statically links libstdc++, but apparently "most Linux distros patch this out". Another developer notes that this doesn't even require a patch: "Setting
STATIC_CXX=false should be enough (it defaults to true)."]

Second, even in this case, is it truly benign to have two incompatible libstdc++.so loaded at the same time?

Third, does this approach (to hide the symbols in the JDK) address all of the compatibility issues?

The blog article referenced above warns that "code compiled against different ABIs is simply not binary compatible." And later that, "the language runtime support typically rely on some data being shared, e.g. to access some kind of lock or global data structure (similar to how C programs need a shared errno)."

This makes it sound like the problem cannot be solved.

Then again, maybe ABI incompatibility isn't a problem anymore. The blog article is over six years old. One answer for another stackoverflow question ( GCC ABI compatibility ) asserts that "Since gcc-3.4.0, the ABI is forward compatible." Has that been successful?

I'd appreciate any guidance on these issues. (And hey, thanks for reading all of this!)

EDITS

My question was getting pretty long, so I didn't give all the specifics. To address Will's comments:

  1. I only need to call extern "C" functions. (For example, I use javah to generate the C header file.)
  2. I don't need to interact with the C++ runtime in the JVM. (I basically just need to send strings to a C++ library.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

这个俗人 2024-12-30 23:26:40

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

首先,这取决于您想做什么。 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++ 运行时的支配。

所以,最后,我只是试一试,看看会发生什么。

I don't know. But that never stopped me.

First, it depends on what you want to do. The premise behind the static linking of the JDK is to improve portability of the actual JDK itself. Since they can't expect users to recompile the JDK on their particular OS, they needed a mechanism to make the final binary portable. Apparently static linking fixed this problem.

Next, regarding JNI, first you'll be calling C functions and not C++, I don't believe JNI has any kind of C++ binding. So, whatever C++ you'll want to use will need to be wrapped in a C routine to talk to Java.

Next, your C++ .so will dynamically link against the OS pretty much like normal I'm guessing. It's seems pretty draconian to expect a JNI routine to not work with a dynamic linked .so, and a C++ .so should be no different. And, no doubt C++ being as popular as it is, it seems similarly draconian that you would not be able to dynamically link against a C++ .so. So, whatever shenanigans that need to have taken place to facilitate this, it's a reasonable assumption that They(tm) have done the work to allow this to happen.

That said, there should certainly be no expectation that whatever C++ you're using will have any interaction whatsoever with the C++ runtime in the Java runtime. Ideally, they'll simply peacefully co-exist.

Given that, assuming this works at all, your C++ will most certainly have the ABI portability issue, since it will be dynamically linking, and will be at the mercy of the OS'es installed C++ runtime.

So, in the end, I'd just give it a rip and see what happens.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文