介绍
JavaCPP提供了对Java内部本机C++的高效访问。
更具体地说,与上述或其他方法相比(CableSwig、JNIGeneratorApp、cxxwrap、JNIWrapper、平台调用、GlueGen、LWJGL生成器、JNIDirect、ctypes、JNA、JNIEasy、JniMarshall、JNative、J/Invoke、HawtJNI、JNR、BridJ、CFFI、fficxx、CppSharp、cgo、pybind11、rust bindgen、Panama Native等),它自然而有效地映射了C++语言提供的许多常见功能,通常被认为是有问题的,包括重载运算符、类和函数模板、通过函数指针的回调、函数对象(也称为函子)、虚拟函数和成员函数指针、嵌套结构定义、变长参数、嵌套名称空间、,包含任意循环、虚拟继承和多重继承、按值/引用/字符串/向量传递/返回、匿名联合、位字段、异常、析构函数和共享或唯一指针(通过尝试资源或垃圾收集)以及文档注释的大型数据结构。显然,整洁地支持整个C++将需要更多的工作(尽管有人可能会争论C++的内在整洁性),但我们在这里发布它作为概念证明。
作为一个例子,我们已经使用它生成了OpenCV、FFmpeg、libdc1394、PGR FlyCapture、OpenKinect、videoInput、ARToolKitPlus、Leptonica、Tesseract、GSL、LLVM、HDF5、MKL、CUDA、Caffe、MXNet、TensorFlow、系统API等的完整接口,作为JavaCPP预设子项目的一部分,还演示了C/C++头文件的早期解析功能,显示了有前途和有用的结果。
下载
包含JAR文件的存档可以作为发行版提供。
我们还可以通过以下软件自动下载和安装所有内容:
pom.xml
file) <dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacpp</artifactId>
<version>1.5.7</version>
</dependency>
build.gradle
file) dependencies {
implementation group: 'org.bytedeco', name: 'javacpp', version: '1.5.7'
}
project.clj
file) :dependencies [
[org.bytedeco/javacpp "1.5.7"]
]
build.sbt
file) libraryDependencies += "org.bytedeco" % "javacpp" % "1.5.7"
Gradle用户可用的另一个选项是Gradle JavaCPP,类似地,对于Scala用户,还有SBT JavaCPP。
依赖的软件
要使用JavaCPP,您需要下载并安装以下软件:
要了解JavaCPP的使用方法,首先应该了解C/C++库的映射方法,但也可以通过对基本体系结构的高级概述来了解全局。JavaCPP presets 进一步提供了复杂的示例,我们可以将其用作模板,但它还包括一个关于如何创建新预设的wiki页面,详细解释了它们的结构,以及一个小但完整的示例项目,可以从中开始试验。
访问本地APIs
最常见的用例涉及访问一些为C++编写的本机库,例如,在名为NativeLibrary的文件中。h包含此C++类:
#include <string>
namespace NativeLibrary {
class NativeClass {
public:
const std::string& get_property() { return property; }
void set_property(const std::string& property) { this->property = property; }
std::string property;
};
}
为了使用JavaCPP完成这项工作,我们可以很容易地定义这样一个Java类——尽管可以使用解析器从头文件生成它,如JavaCPP预设子项目所示,遵循C/C++库映射配方中概述的原则:
import org.bytedeco.javacpp.*;
import org.bytedeco.javacpp.annotation.*;
@Platform(include="NativeLibrary.h")
@Namespace("NativeLibrary")
public class NativeLibrary {
public static class NativeClass extends Pointer {
static { Loader.load(); }
public NativeClass() { allocate(); }
private native void allocate();
// to call the getter and setter functions
public native @StdString String get_property(); public native void set_property(String property);
// to access the member variable directly
public native @StdString String property(); public native void property(String property);
}
public static void main(String[] args) {
// Pointer objects allocated in Java get deallocated once they become unreachable,
// but C++ destructors can still be called in a timely fashion with Pointer.deallocate()
NativeClass l = new NativeClass();
l.set_property("Hello World!");
System.out.println(l.property());
}
}
在以通常的方式编译Java源代码之后,我们还需要在执行它之前使用JavaCPP进行构建,或者我们可以让它按如下方式执行所有操作:
$ java -jar javacpp.jar NativeLibrary.java -exec
Hello World!
使用复杂的C++类型
为了演示它的相对易用性,即使在面对复杂的数据类型时,想象一下我们有一个C++函数,该函数以vector<vector<void*>>作为参数。为了支持这种类型,我们可以定义如下的裸体类:
import org.bytedeco.javacpp.*;
import org.bytedeco.javacpp.annotation.*;
@Platform(include="<vector>")
public class VectorTest {
@Name("std::vector<std::vector<void*> >")
public static class PointerVectorVector extends Pointer {
static { Loader.load(); }
public PointerVectorVector() { allocate(); }
public PointerVectorVector(long n) { allocate(n); }
public PointerVectorVector(Pointer p) { super(p); } // this = (vector<vector<void*> >*)p
private native void allocate(); // this = new vector<vector<void*> >()
private native void allocate(long n); // this = new vector<vector<void*> >(n)
@Name("operator=")
public native @ByRef PointerVectorVector put(@ByRef PointerVectorVector x);
@Name("operator[]")
public native @StdVector PointerPointer get(long n);
public native @StdVector PointerPointer at(long n);
public native long size();
public native @Cast("bool") boolean empty();
public native void resize(long n);
public native @Index long size(long i); // return (*this)[i].size()
public native @Index @Cast("bool") boolean empty(long i); // return (*this)[i].empty()
public native @Index void resize(long i, long n); // (*this)[i].resize(n)
public native @Index Pointer get(long i, long j); // return (*this)[i][j]
public native void put(long i, long j, Pointer p); // (*this)[i][j] = p
}
public static void main(String[] args) {
PointerVectorVector v = new PointerVectorVector(13);
v.resize(0, 42); // v[0].resize(42)
Pointer p = new Pointer() { { address = 0xDEADBEEFL; } };
v.put(0, 0, p); // v[0][0] = p
PointerVectorVector v2 = new PointerVectorVector().put(v);
Pointer p2 = v2.get(0).get(); // p2 = *(&v[0][0])
System.out.println(v2.size() + " " + v2.size(0) + " " + p2);
v2.at(42);
}
}
使用此命令执行该程序会产生以下输出:
$ java -jar javacpp.jar VectorTest.java -exec
13 42 org.bytedeco.javacpp.Pointer[address=0xdeadbeef,position=0,limit=0,capacity=0,deallocator=null]
Exception in thread "main" java.lang.RuntimeException: vector::_M_range_check: __n (which is 42) >= this->size() (which is 13)
at VectorTest$PointerVectorVector.at(Native Method)
at VectorTest.main(VectorTest.java:44)