从Java 18开始,孵化的外部函数接口似乎没有很好地处理C++代码的方法。我正在开发一个需要绑定C++的项目,并且想知道如何避免在C中创建thunk库。
其中一个C++类大致如下:
namespace library {
typedef uint8_t byte;
class CppClass {
public:
static oncstexpr const char* DefaultArgument = "default";
CppClass(const std::string& argument = DefaultArgument);
virtual ~CppClass();
bool doStuff();
bool handleData(std::vector<byte>* data);
private:
std::unique_ptr<InternalType> internalState;
};
}
我希望创建一个类似以下Java类的东西来反映它(省略了错误检查):
public final class CppClass implements AutoCloseable {
public static final String DefaultArgument = "default";
private static final MethodHandle NEW;
private static final MethodHandle FREE;
private static final MethodHandle DO_STUFF;
private static final MethodHandle HANDLE_DATA;
static{
var binder = Natives.getBinder();
NEW = binder.bind("(manged constructor)", ValueLayout.ADDRESS, ValueLayout.ADDRESS);
FREE = binder.bindVoid("(manged deconstructor)", ValueLayout.ADDRESS);
DO_STUFF = binder.bind("(manged doStuff)", ValueLayout.JAVA_BYTE, ValueLayout.ValueLayout.ADDRESS);
HANDLE_DATA = binder.bind("manged handleData)", ValueLayout.JAVA_BYTE, ValueLayout.ADDRESS, ValueLayout.ADDRESS, ValueLayout.JAVA_LONG);
}
private final MemorySegment pointer;
public CppClass() {
this(DefaultArgument);
}
public CppClass(String argument) {
try(var scope = MemoryScope.newConfinedScope()) {
var allocator = MemoryAllocator.nativeAllocator(scope);
pointer = (MemoryAddress)NEW.invokeExact(
allocator.allocateUtf8String(argument)
);
}
}
@Override
public void close() {
FREE.invokeExact(pointer);
}
public boolean doStuff() {
return (byte)DO_STUFF.invokeExact(pointer) != 0;
}
public boolean handleData(MemorySegment segment) {
return (byte)HANDLE_DATA.invokeEact(pointer, segment.address(), segment.byteSize()) != 0;
}
}
Binder
大致如下:
public interface Binder {
MethodHandle bind(String name, FunctionDescriptor desc);
MethodHandle bind(String name, MemoryLayout result, MemoryLayout... args);
MethodHandle bindVoid(String name, MemoryLayout... args);
}
我不确定其中哪些部分是正确的。我的最大实现问题是:
- 调用构造函数和析构函数的正确方式是什么?
- 调用方法的正确方式是什么?
- 处理std类型(如std::string、std::vector)的正确方式是什么?
- C++编译器会在编译时添加默认参数值,还是会生成多个方法?
Linker
。那只是用于在JDK中公开实现的接口。但是,没有API需要提供Linker
实例。因此,它被封闭并不重要。 - Jorn Vernee