使用 Java 来包装 C++

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3356200/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 01:27:42  来源:igfitidea点击:

Using Java to wrap over C++

javac++user-interfacewrapper

提问by sparkFinder

I have a project written in C++ and I'm looking to write a Java GUI as an interface to it. The choice of Java is fixed so I'd need to learn how to be able to call the C++ code from Java. Rewriting the C++ code is not an option. I'd like input on:

我有一个用 C++ 编写的项目,我希望编写一个 Java GUI 作为它的接口。Java 的选择是固定的,所以我需要学习如何能够从 Java 调用 C++ 代码。重写 C++ 代码不是一种选择。我想输入:

  1. What tools can I use to achieve this wrapping.
  2. How much of the C++ code would I have to necessarily modify, if any.
  3. Any other insights/follow up questions that you'd have.
  1. 我可以使用什么工具来实现这种包装。
  2. 如果有的话,我必须修改多少 C++ 代码。
  3. 您有任何其他见解/后续问题。

Thanks.

谢谢。

采纳答案by Victor

You should look for JNI - Java Native Interface

您应该寻找 JNI - Java 本机接口

回答by Matt Crinklaw-Vogt

I recently worked on a project in which we had to do exactly the same thing. We had a data model written in C++ and needed to put a Java GUI on top. What we ended up doing was identifying the C++ classes that we needed to access from the GUI and used SWIG to generate plain old java classes which wrapped the C++ objects.

我最近参与了一个项目,我们必须在其中做完全相同的事情。我们有一个用 C++ 编写的数据模型,需要在上面放置一个 Java GUI。我们最终做的是识别我们需要从 GUI 访问的 C++ 类,并使用 SWIG 生成包装 C++ 对象的普通旧 Java 类。

http://www.swig.org/

http://www.swig.org/

The Java classes generated by SWIG have identical interfaces to the C++ classes they are wrapping which means that communicating with the C++ objects, from Java, involves only working with Java objects.

SWIG 生成的 Java 类与它们包装的 C++ 类具有相同的接口,这意味着与来自 Java 的 C++ 对象通信只涉及使用 Java 对象。

Here is an example:

下面是一个例子:

Given two C++ classes:

给定两个 C++ 类:

class SomeClass {
public:
  void foo(SomeOtherClass bar);
  SomeOtherClass baz();
}

class SomeOtherClass {
public:
  void do();
}

SWIG will generate two Java classes:

SWIG 将生成两个 Java 类:

public class SomeClass {
  public void foo(SomeOtherClass bar);
  public SomeOtherClass baz();
}

public class SomeOtherClass {
  public void do();
}

Calling C++ objects, from Java, is just like writing regular Java:

从 Java 调用 C++ 对象就像编写常规 Java 一样:

SomeClass sc = new SomeClass();
SomeOtherClass soc = sc.baz();
sc.foo(soc);

Line 1: The Java wrapper of SomeClass is instantiated as well as a C++ object of type SomeClass.

第 1 行:SomeClass 的 Java 包装器和 SomeClass 类型的 C++ 对象被实例化。

Line 2: Calls to the sc instance of SomeClass are forwarded to the C++ instance of SomeClass. The return value of the C++ instance is passed to the Java wrapper and returned by the Java wrapper.

第 2 行:对 SomeClass 的 sc 实例的调用被转发到 SomeClass 的 C++ 实例。C++ 实例的返回值传递给 Java 包装器并由 Java 包装器返回。

Line 3: SWIG handles converting from the Java wrapper types (or java primitive types) to the underlying C++ types.

第 3 行:SWIG 处理从 Java 包装器类型(或 Java 原始类型)到底层 C++ 类型的转换。

SWIG will take care of converting to/from Java/C++ types during method invocations and all the JNI details are hidden away from view :)

SWIG 将负责在方法调用期间转换为 Java/C++ 类型,并且所有 JNI 详细信息都隐藏在视图之外:)

The SWIG interface code needed to generate a Java wrapper for a C++ class can be as simple as:

为 C++ 类生成 Java 包装器所需的 SWIG 接口代码可以很简单:

interface.i: { #include "ClassDefinition.h" } %include "ClassDefinition.h"

interface.i: { #include "ClassDefinition.h" } %include "ClassDefinition.h"

SWIG is very powerful. Anything you need to do you can do either with the basic features, typemaps, javacode type maps, or directors.

SWIG 非常强大。您需要做的任何事情都可以使用基本功能、类型映射、javacode 类型映射或导演来完成。

SWIG also allows your C++ code to call your Java objects without any modification to your existing C++ code. This is a feature called "cross language polymorphism." cross language polymorphism essentially lets you create Java classes that subclass C++ classes. You can then pass instances of those Java classes as parameters to C++ method calls. Any invocations, from C++, on the passed in instance will be forwarded back to your Java object. I won't get into the details here, but it isn't terribly complicated once you get over the initial shock of the idea.

SWIG 还允许您的 C++ 代码调用您的 Java 对象,而无需对您现有的 C++ 代码进行任何修改。这是一个称为“跨语言多态性”的特性。跨语言多态本质上允许您创建子类化 C++ 类的 Java 类。然后,您可以将这些 Java 类的实例作为参数传递给 C++ 方法调用。来自 C++ 的对传入实例的任何调用都将转发回您的 Java 对象。我不会在这里详细介绍,但是一旦您克服了最初对这个想法的震惊,它就不会非常复杂。

回答by josefx

JNI

JNI

  • If your code is c++
  • JNI is part of the java runtime
  • declare native functions and generate a c/c++ header with javah
  • write c/c++ code to glue your code to the java methods
  • 如果你的代码是 C++
  • JNI 是 java 运行时的一部分
  • 声明本机函数并使用 javah 生成 ac/c++ 头文件
  • 编写 c/c++ 代码将您的代码粘合到 java 方法

JNA

JNA

  • If you have a c api for your code
  • does not work with c++ classes
  • JNA is not part of the java runtime, jna.jar is 300kb
  • declare a java interface with the c methods you use
  • write java code to glue your dll to java
  • need to create a java copy of c structures used by the dll functions
  • 如果您的代码有 ac api
  • 不适用于 C++ 类
  • JNA 不是 java 运行时的一部分,jna.jar 是 300kb
  • 使用您使用的 c 方法声明一个 java 接口
  • 编写java代码将你的dll粘到java上
  • 需要创建 dll 函数使用的 c 结构的 java 副本

Both of them are platform independent. I prefer jna myself since it is easy to mess up jni code. There are several platform dependent solutions around, too - but I don't know them that well.

它们都是独立于平台的。我自己更喜欢 jna,因为它很容易弄乱 jni 代码。周围也有几个依赖于平台的解决方案 - 但我不太了解它们。

  • JACOB: java COM bridge (windows)
  • ...
  • JACOB:java COM 桥(windows)
  • ...

回答by Andy

I'd go for some form of IPC (pipes, maybe even sockets). This way, your code is reduced to copying to and from byte arrays in C++, and using InputStreams and OutputStreams in Java.

我会选择某种形式的 IPC(管道,甚至可能是套接字)。这样,您的代码就简化为在 C++ 中与字节数组相互复制,并在 Java 中使用 InputStreams 和 OutputStreams。

I've recently worked on a project where we had a library distributed by a third party, which was written in C++. But every system we have that might use this library was written in Java.

我最近在一个项目上工作,我们有一个由第三方分发的库,它是用 C++ 编写的。但是我们拥有的每个可能使用这个库的系统都是用 Java 编写的。

We went down the route of wrapping the library as a native executable, that reads input from stdin, translating it to function calls to the library. Correspondingly, results from the library were converted and printed to stdout.

我们沿着将库包装为本地可执行文件的路线,从标准输入读取输入,将其转换为对库的函数调用。相应地,库的结果被转换并打印到标准输出。

This also meant that the wrapper was easy to test, since all I had to do was invoke it on the command line. Spotted a lotof bugs and problems because of this. Thoroughly recommend it.

这也意味着包装器很容易测试,因为我所要做的就是在命令行上调用它。因此发现了很多错误和问题。彻底推荐它。

The next problem was 'How do I invoke the C++ wrapper' and 'How do I package it with the Java app'? We actually avoided the answers to these questions, by exposing the executable via inetd. So our java applications invoked the C code by opening a socket. Because I'd coded the wrapper to communicate via stdout and stdin, I didn't have to modify it at allto expose it via TCP (Read up on inetdif you're puzzled). The neatest little bit of programming I've ever done... :-)

下一个问题是“如何调用 C++ 包装器”和“如何将它与 Java 应用程序一起打包”?实际上,我们通过 inetd 公开了可执行文件,从而避免了这些问题的答案。因此,我们的 Java 应用程序通过打开一个套接字来调用 C 代码。因为我已经编码包装通过标准输出和标准输入进行沟通,我没有修改它在所有通过TCP揭露它(阅读上的inetd如果你感到困惑)。我做过的最简洁的一点点编程... :-)

Sorry I went off on a tangent up there. I was trying to illustrate the flexibility you can get if you decide to separate the C++ code into a separate process. The point is, you've done the work of marshalling your data structures up front. So initially, you might keep your other process local and communicate to it via a pipe. The thing is, if you ever decide that you need to send the requests to a remote TCP server, it wouldn't take a lot of effort to change the java program. You've already done the bulk of the work. It may be worth considering. Whether it's actually suitable for you, I don't know.

对不起,我在那里的一个切线上走了。我试图说明如果您决定将 C++ 代码分成一个单独的进程,您可以获得的灵活性。关键是,您已经完成了预先编组数据结构的工作。因此,最初,您可能会将其他进程保留在本地并通过管道与它通信。问题是,如果您决定需要将请求发送到远程 TCP 服务器,则更改 java 程序不会花费太多精力。您已经完成了大部分工作。可能值得考虑。它是否真的适合你,我不知道。

I haven't coded with JNI, but we do have apps that use it at work, and they all suffer memory management issues:

我没有用 JNI 编码,但我们确实有在工作中使用它的应用程序,它们都遇到内存管理问题:

1) If the C/C++ code makes a mistake with pointer arithmetic, your Java app's screwed as well. It'll probably die with a SIGSEGV. So your C/C++ code better be solid, well tested and worth your trust. With the project I was working on, most of the Java apps were server processes, that are supposed to work 24/7. We didn't trust this third party library thatmuch, useful as it may be.

1) 如果 C/C++ 代码在指针运算方面犯了错误,那么您的 Java 应用程序也会被搞砸。它可能会因 SIGSEGV 而死亡。所以你的 C/C++ 代码最好是可靠的、经过充分测试的并且值得你信任。在我从事的项目中,大多数 Java 应用程序都是服务器进程,应该 24/7 全天候工作。我们不太信任这个第三方库尽管它可能很有用。

2) Passing data structures between the Java and C++ can be troublesome. Especially if you pass Java objects into the C functions. You usually have to perform some sort of conversion, which raises such issues like 'should I copy this data structure? When should I destroy it?' It's especially bad if you inadvertently call 'free' on some object that was allocated in the Java program.

2) 在 Java 和 C++ 之间传递数据结构可能很麻烦。特别是当您将 Java 对象传递给 C 函数时。您通常必须执行某种转换,这会引发诸如“我应该复制此数据结构吗?我什么时候应该销毁它?如果您无意中在 Java 程序中分配的某个对象上调用了“free”,那将尤其糟糕。

3) I've seen some JNI code. It just looks ugly... [barf]

3) 我看过一些 JNI 代码。它看起来很丑...... [barf]

Sorry for the long post.

抱歉,帖子太长了。

回答by KeithB

Depending on how tightly coupled the interface needs to be to the C++ code, the easiest thing to do might be to run the GUI and the C++ code as separate programs that communicate via some kind of IPC (sockets, named pipes on Unix, etc.)

根据接口需要与 C++ 代码的紧密耦合程度,最简单的方法可能是将 GUI 和 C++ 代码作为单独的程序运行,这些程序通过某种 IPC(套接字、Unix 上的命名管道等)进行通信。 )

The other alternative that I have heard about, but never done, is to create a JNI (Java Native Interface) wrapper around your C++ code. From what I have head, this isn't a straight forward exercise.

我听说过但从未做过的另一种选择是围绕 C++ 代码创建一个 JNI(Java 本机接口)包装器。据我所知,这不是一个直接的练习。

回答by Ken Bloom

Compile the GUI using GCJ, and use the CNI to wrap the C++ code. See http://gcc.gnu.org/java/faq.html#6_2for some comparative examples of using CNI versus JNI (what you'd use with all other Java runtimes.)

使用 GCJ 编译 GUI,并使用 CNI 包装 C++ 代码。请参阅http://gcc.gnu.org/java/faq.html#6_2以获取使用 CNI 与 JNI 的一些比较示例(您将与所有其他 Java 运行时一起使用。)

The CNI is supposed to be a lot simpler than JNI.

CNI 应该比 JNI 简单得多。