JavaCPP
libai 发布于 2022-08-14

介绍

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文件的存档可以作为发行版提供。

我们还可以通过以下软件自动下载和安装所有内容:

  • Maven (inside the pom.xml file)
  <dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>javacpp</artifactId>
    <version>1.5.7</version>
  </dependency>
  • Gradle (inside the build.gradle file)
  dependencies {
    implementation group: 'org.bytedeco', name: 'javacpp', version: '1.5.7'
  }
  • Leiningen (inside the project.clj file)
  :dependencies [
    [org.bytedeco/javacpp "1.5.7"]
  ]
  • sbt (inside the 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)

 

李白
关注 私信
文章
12
关注
0
粉丝
0