java - 如何使用 jdk.incubator.foreign 从 JDK 18 调用 C 函数

标签 java c ffi java-18

这类似于 How to call a C function from Java 17 using JEP 412: Foreign Function & Memory API

但是 API 在从 JDK 17 到 18 的过程中发生了变化。

再次问问题:有人有一个关于如何从 Java 18 调用 C 函数的简单示例吗?我一直在尝试翻译 Java 17 问题中接受的答案。

最佳答案

来自此邮件列表消息: https://mail.openjdk.java.net/pipermail/panama-dev/2022-April/016764.html

我找到了这个链接: https://github.com/openjdk/panama-foreign/blob/foreign-jextract/doc/panama_ffi.md

其中包括以下示例:

import jdk.incubator.foreign.Addressable;
import jdk.incubator.foreign.CLinker;
import jdk.incubator.foreign.FunctionDescriptor;
import jdk.incubator.foreign.SymbolLookup;
import jdk.incubator.foreign.MemoryAddress;
import jdk.incubator.foreign.MemorySegment;
import jdk.incubator.foreign.NativeSymbol;
import jdk.incubator.foreign.ResourceScope;
import jdk.incubator.foreign.SegmentAllocator;
import jdk.incubator.foreign.VaList;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.Arrays;

import static jdk.incubator.foreign.ValueLayout.*;

public class Examples {

    static CLinker LINKER = CLinker.systemCLinker();

    public static void main(String[] args) throws Throwable {
        strlen();
        strlen_virtual();
        qsort();
        printf();
        vprintf();
    }

    public static void strlen() throws Throwable {
        MethodHandle strlen = LINKER.downcallHandle(
                LINKER.lookup("strlen").get(),
                FunctionDescriptor.of(JAVA_LONG, ADDRESS)
        );

        try (ResourceScope scope = ResourceScope.newConfinedScope()) {
            SegmentAllocator malloc = SegmentAllocator.nativeAllocator(scope);
            MemorySegment hello = malloc.allocateUtf8String("Hello");
            long len = (long) strlen.invoke(hello); // 5
            System.out.println(len);
        }
    }

    public static void strlen_virtual() throws Throwable {
        MethodHandle strlen_virtual = LINKER.downcallHandle(
                FunctionDescriptor.of(JAVA_LONG, ADDRESS)
        );

        try (ResourceScope scope = ResourceScope.newConfinedScope()) {
            SegmentAllocator malloc = SegmentAllocator.nativeAllocator(scope);
            MemorySegment hello = malloc.allocateUtf8String("Hello");
            long len = (long) strlen_virtual.invoke(
                LINKER.lookup("strlen").get(),
                hello); // 5
            System.out.println(len);
        }
    }

    static class Qsort {
        static int qsortCompare(MemoryAddress addr1, MemoryAddress addr2) {
            return addr1.get(JAVA_INT, 0) - addr2.get(JAVA_INT, 0);
        }
    }

    public static void qsort() throws Throwable {
        MethodHandle qsort = LINKER.downcallHandle(
                LINKER.lookup("qsort").get(),
                FunctionDescriptor.ofVoid(ADDRESS, JAVA_LONG, JAVA_LONG, ADDRESS)
        );
        FunctionDescriptor comparDesc = FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS);
        MethodHandle comparHandle = MethodHandles.lookup()
                                         .findStatic(Qsort.class, "qsortCompare",
                                                     CLinker.upcallType(comparDesc));

        try (ResourceScope scope = ResourceScope.newConfinedScope()) {
            NativeSymbol comparFunc = LINKER.upcallStub(
                comparHandle, comparDesc, scope);

            SegmentAllocator malloc = SegmentAllocator.nativeAllocator(scope);
            MemorySegment array = malloc.allocateArray(JAVA_INT, new int[] { 0, 9, 3, 4, 6, 5, 1, 8, 2, 7 });
            qsort.invoke(array, 10L, 4L, comparFunc);
            int[] sorted = array.toArray(JAVA_INT); // [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
            System.out.println(Arrays.toString(sorted));
        }
    }

    public static void printf() throws Throwable {
        MethodHandle printf = LINKER.downcallHandle(
                LINKER.lookup("printf").get(),
                FunctionDescriptor.of(JAVA_INT, ADDRESS).asVariadic(JAVA_INT, JAVA_INT, JAVA_INT)
        );
        try (ResourceScope scope = ResourceScope.newConfinedScope()) {
            SegmentAllocator malloc = SegmentAllocator.nativeAllocator(scope);
            MemorySegment s = malloc.allocateUtf8String("%d plus %d equals %d\n");
            printf.invoke(s, 2, 2, 4);
        }
    }

    public static void vprintf() throws Throwable {

        MethodHandle vprintf = LINKER.downcallHandle(
                LINKER.lookup("vprintf").get(),
                FunctionDescriptor.of(JAVA_INT, ADDRESS, ADDRESS));

        try (ResourceScope scope = ResourceScope.newConfinedScope()) {
            SegmentAllocator malloc = SegmentAllocator.nativeAllocator(scope);
            MemorySegment s = malloc.allocateUtf8String("%d plus %d equals %d\n");
            VaList vlist = VaList.make(builder ->
                     builder.addVarg(JAVA_INT, 2)
                            .addVarg(JAVA_INT, 2)
                            .addVarg(JAVA_INT, 4), scope);
            vprintf.invoke(s, vlist);
        }
    }
}

运行为:java --add-modules jdk.incubator.foreign --enable-native-access=ALL-UNNAMED Examples.java

关于java - 如何使用 jdk.incubator.foreign 从 JDK 18 调用 C 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72010907/

相关文章:

javascript - Java 服务器 JavaScript 客户端 WebSockets

c - xlC 和类型 "vector unsigned int"和 "int"之间的操作是不允许的

C读取文本文件并将内容放入结构中

python - 在 Racket 中使用 Python 库

java - 在 Vaadin 上播放视频

java - 为什么 Collections.copy 仍然复制引用,它不克隆复制的对象?

c++ - 为什么 C++ 与 C 兼容?

ruby-on-rails - 超时、系统超时和终止符不适用于基于 FFI 的功能

c - 如何使用ImageMagick C API的MagickGetImageHistogram

java - JPA:JPARepository 中的 ORDER BY 在 GROUP BY 之前