JAVA22 FFM实战之HelloWorld

前言

JDK22即将发布,Java Foreign Function & Memory API将会退出预览,是时候开始学习一波了。

FFM API介绍

FFM API由两大部分组成,一个是Foreign Function Interface,另一个是Memory API。前者是外部函数接口,简称FFI,用它来实现Java代码和外部代码之间相互操作;后者是内存接口,用于安全地管理堆外内存。

上面说这么多,可以简单的认为是jni的替代品。

本文不关注底层如何实现,一两个常用的c库为例子,重点在了解api的使用以及使用jextract生成java代码

入门

使用c语言的strlen和printf格式化打印helloworld

/*** @author authorZhao* @since 2024-03-13*/
public class FFMHelloWorld {public static void main(String[] args) {Linker linker = Linker.nativeLinker();SymbolLookup defaultLookup = linker.defaultLookup();MethodHandle strlenHandle = linker.downcallHandle(defaultLookup.find("strlen").orElseThrow(),FunctionDescriptor.of(JAVA_LONG, ADDRESS));MethodHandle printfHandler = linker.downcallHandle(defaultLookup.find("printf").orElseThrow(),FunctionDescriptor.of(JAVA_LONG, ADDRESS,JAVA_INT));try (Arena offHeap = Arena.ofConfined()) {MemorySegment pointers = offHeap.allocateUtf8String("Hello world%d!");System.out.println(strlenHandle.invoke(pointers));  //11printfHandler.invoke(pointers,8);} catch (Throwable e) {throw new RuntimeException(e);}}
}

实战级别的HelloWorld

工具准备

下载curl

下载lua

  • 注意需要下载源码最好,有条件的自行编译,编译为动态库

  • 效果如图,本文只需要dll即可没动态库名字我自己改的

  • 头文件目录

在这里插入图片描述
在这里插入图片描述
这里的cjson已经被移动到同级目录的dll目录下面

下载jextract 本文选择jdk22的版本

打开jextract的github链接

一、CURL

打开curl的例子 https://github.com/openjdk/jextract/tree/master/samples/libcurl

windows脚本如下

param([Parameter(Mandatory=$true, HelpMessage="The path to the lib curl installation")][string]$curlpath
)jextract `-I "$curlpath\include" `-I "$curlpath\include\curl" `--dump-includes 'includes_all.conf' `"$curlpath\include\curl\curl.h"Select-String -Path 'includes_all.conf' -Pattern '(curl|sockaddr )' | %{ $_.Line } | Out-File -FilePath 'includes_filtered.conf' -Encoding asciijextract `--output src `-t org.jextract `-I "$curlpath\include" `-I "$curlpath\include\curl" `-llibcurl `'@includes_filtered.conf' `"$curlpath\include\curl\curl.h"javac -d classes (ls -r src/*.java)

本人以自己的curl为例

生成脚本

本人的curlpath = E:/tool/curl-8.6.0_6-win64-mingw/curl-8.6.0_6-win64-mingw我按照github执行了两次命令1. 这个执行完毕得到一个includes_filtered.conf文件
jextract --output src -t org.jextract -I "E:/tool/curl-8.6.0_6-win64-mingw/curl-8.6.0_6-win64-mingw/include" -I "E:/tool/curl-8.6.0_6-win64-mingw/curl-8.6.0_6-win64-mingw/include/curl" -llibcurl '@includes_filtered.conf' "E:/tool/curl-8.6.0_6-win64-mingw/curl-8.6.0_6-win64-mingw/include/curl/curl.h"2.这个执行完毕直接得到生成的java代
jextract --output src -t org.jextract -I "E:/tool/curl-8.6.0_6-win64-mingw/curl-8.6.0_6-win64-mingw/include" -I "E:/tool/curl-8.6.0_6-win64-mingw/curl-8.6.0_6-win64-mingw/include/curl" "E:/tool/curl-8.6.0_6-win64-mingw/curl-8.6.0_6-win64-mingw/include/curl/curl.h"

拷贝生成java代码(好家伙52M)到idea

生成的工具有一个方法和我本地jdk有点不一致(可能是版本原因,本地jdk21,工具依赖的jdk是22), ctrl+shift+r 全局替换一下getUtf8String

arena.allocateFrom(urlStr); 替换为  arena.getUtf8String(urlStr);

启动

import java.lang.foreign.Arena;import static java.lang.foreign.MemorySegment.NULL;
import static org.jextract.curl_h.*;public class CurlMain {static {System.load("E:\\tool\\curl-8.6.0_6-win64-mingw\\curl-8.6.0_6-win64-mingw\\bin\\libcurl-x64.dll");}public static void main(String[] args) {var urlStr = "https://www.baidu.com";curl_global_init(CURL_GLOBAL_DEFAULT());var curl = curl_easy_init();//curl_easy_setoptif (!curl.equals(NULL)) {try (var arena = Arena.ofConfined()) {var url = arena.allocateUtf8String(urlStr);//忽略ssl忽略证书检查curl_easy_setopt.makeInvoker(C_LONG_LONG).apply(curl, CURLOPT_SSL_VERIFYPEER(), 0);curl_easy_setopt.makeInvoker(C_LONG_LONG).apply(curl, CURLOPT_URL(), url.address());int res = curl_easy_perform(curl);if (res != CURLE_OK()) {String error = curl_easy_strerror(res).getUtf8String(0);System.out.println("Curl error: " + error);curl_easy_cleanup(curl);}}}curl_global_cleanup();}
}

curl的java执行结果

在这里插入图片描述

二、LUA

lua源代码

print("package.cpath=" .. package.cpath)
-- 注意cjson不在lua.exe同级目录,再下一级别
package.cpath = package.cpath .. ';E:/tool/lua5.4-zhao/dll/?.dll'
local cjson = require("cjson")function test()local map = {}map["a"] = "张三"map["b"] = "李四"for k,v in pairs(map) doprint(k .. '=' .. v)endprint(cjson.encode(map))return 100
end
test()

lua源代码的直接执行结果

在这里插入图片描述

生成命令

生成代码并,拷贝代码到idea

jextract --output src -t com.lua -I "E:/tool/lua-5.4.4/src" "E:/tool/lua-5.4.4/src/lua.h" -l :E:/tool/lua5.4-zhao/liblua5.4.0.dlljextract --output src -t com.lua -I "E:/tool/lua-5.4.4/src" "E:/tool/lua-5.4.4/src/lualib.h" -l :E:/tool/lua5.4-zhao/liblua5.4.0.dlljextract --output src -t com.lua -I "E:/tool/lua-5.4.4/src" "E:/tool/lua-5.4.4/src/lauxlib.h" -l :E:/tool/lua5.4-zhao/liblua5.4.0.dll

在这里插入图片描述

idea导入生成的java代码

/*** @author authorZhao*/
public class LuaMain {static {//这里不适用load,生成代码使用-l指定动态库的位置,生成的代码直接包含了,但是这种方式用的是绝对路径,使用SymbolLookup.libraryLookup//System.load("E:/tool/lua5.4-zhao/liblua5.4.0.dll");}public static void main(String[] args) {var lua_State = luaL_newstate();if (lua_State == NULL) {return;}//打开内置库luaL_openlibs(lua_State);try (var arena = Arena.ofConfined()) {var code = arena.allocateUtf8String("print(\"渣渣辉\") return \"嘿嘿\"");//加载而不执行int i = luaL_loadstring(lua_State, code);if (i != 0) {return;}// pcalllua_h.lua_pcallk(lua_State, 0, 1, 0, 0L, NULL);var data2 = lua_h.lua_tolstring(lua_State, -1,NULL);System.out.println("data2 = " + data2.getUtf8String(0L));//这里的utf-8可能对中文路径有问题,英文影响应该不大int loadResult = luaL_loadfilex(lua_State, arena.allocateUtf8String("E:/tool/lua5.4-zhao/test2.lua"), NULL);System.out.println("loadResult = " + loadResult);// pcallint iRet = lua_h.lua_pcallk(lua_State, 0, 1, 0, 0L, NULL);if (iRet==0){var data = lua_h.lua_tointegerx(lua_State, -1,NULL);System.out.println("data = " + data);}}//关闭lua虚拟机lua_h.lua_close(lua_State);}}

执行结果

在这里插入图片描述

本文运行环境

本文系统win10 运行jdk21,jextract工具是jdk22的版本,lua5.4

使用总结

  • curl本身就3M生成的代码文件有55M,编译的class有2万多个(可能是姿势不对,跟多类都没用到)
  • 体验还行,但是如果不了解这个c库,可能很多api都不会用,例如图上的ssl证书,不处理https都报错,lua的capi
  • 该工具目前无法识别c++的语法,以qt为例目前使用失败(有可能是使用姿势不对),理论上是要支持的
  • 以lua为例,一些宏无法识别
  • lua里面使用别的dll或者so,搜索路径是jdk下面开头的,这个需要注意
  • System.load是以前的jni加载动态库的方式,在这里照样可以这么用,网上查了一下SymbolLookup.libraryLookup会忽略jni_onload等函数
  • 生成代码的时候如果使用绝对路径指定动态库的位置,可能会造成跨平台问题,这里需要注意

参考

jextract的github地址 https://github.com/openjdk/jextract

lua5.4文档 https://www.lua.org/manual/5.4/

lua5.3中文文档(这里面对capi翻译的很详细) https://www.runoob.com/manual/lua53doc/manual.html#lua_tolstring

openjdk的jextract下载地址 https://jdk.java.net/jextract/

本文为原创,转载请申明

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/748547.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

对模型性能进行评估(Machine Learning 研习十五)

在上一篇我们已然训练了一个用于对数字图像识别的模型,但我们目前还不知道该模型在识别数字图像效率如何?所以,本文将对该模型进行评估。 使用交叉验证衡量准确性 评估模型的一个好方法是使用交叉验证,让我们使用cross_val_score…

机器学习-04-分类算法-02贝叶斯算法

总结 本系列是机器学习课程的系列课程,主要介绍机器学习中分类算法,本篇为分类算法与贝叶斯算法部分。 本门课程的目标 完成一个特定行业的算法应用全过程: 懂业务会选择合适的算法数据处理算法训练算法调优算法融合 算法评估持续调优工程…

MySQL大小写敏感、MySQL设置字段大小写敏感

文章目录 一、MySQL大小写敏感规则二、设置数据库及表名大小写敏感2.1、查询库名及表名是否大小写敏感2.2、修改库名及表名大小写敏感 三、MySQL列名大小写不敏感四、lower_case_table_name与校对规则4.1、验证校对规则影响大小写敏感4.1、验证校对规则影响排序 五、设置字段内…

Selenium控制已运行的Edge和Chrome浏览器——在线控制 | 人机交互(详细启动步骤和bug记录)

文章目录 前期准备1. 浏览器开启远程控制指令(1)Edge(2)Chrome 2. 执行python代码(1)先启动浏览器后执行代码(2)通过代码启动浏览器(3)Bug问题记录1&#xff…

蓝桥杯决赛2023 RE CyberChef2

思路很清晰,爆IV 但是题目出的有点屎,六位字符串,62的6次方,要我爆到猴年马月? 就当练习脚本吧 #Cyber2 wp from Crypto.Cipher import DES, AES from Crypto.Util.Padding import pad, unpad key_des b0a0b0c0…

PHP异世界云商系统开源源码

系统更新与修复列表 1. 基于彩虹的二次开发 - 对彩虹系统进行了二次开发,增强了系统的功能和性能。2. 新增自定义输入框提示内容(支持批量修改) - 用户可以自定义输入框的提示内容,并支持批量修改,提升用户体验。3. 新…

TCP相关特性

协议段格式 • 源/⽬的端⼝号:表⽰数据是从哪个进程来,到哪个进程去; • 32位序号/32位确认号:后⾯详细讲; • 4位TCP报头⻓度:表⽰该TCP头部有多少个32位bit(有多少个4字节);所以TCP头部最⼤⻓度是15*460 • 6位标志位: ◦ URG:紧急指针是否有效 ◦ ACK:确认号是否有效…

ARMv8架构特殊寄存器介绍-0

一、zero 寄存器 零寄存器用作源寄存器时读取零,用作目标寄存器时丢弃结果。您可以在大多数指令中使用零寄存器,但不是所有指令。二、sp寄存器 在ARMv8架构中,要使用的堆栈指针的选择在某种程度上与Exception级别。默认情况下,异…

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:ScrollBar)

滚动条组件ScrollBar,用于配合可滚动组件使用,如List、Grid、Scroll。 说明: 该组件从API Version 8开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。 子组件 可以包含单个子组件。 接口 ScrollBar(val…

6、Design Script之列表

Range 在DesignScript中,Range是从起点到终点的一系列数字,使用指定的步距(间距类型),并有以下的初始化方法: start..end..step; start..end..#amount; start..end..~approximate; Range可以是数字的,也可以是字母的。 字母范围因大小写而异。 开始,结束. .#数量范围(…

springboot276基于JS的个人云盘管理系统的设计与实现

个人云盘管理系统设计与实现 摘 要 传统办法管理信息首先需要花费的时间比较多,其次数据出错率比较高,而且对错误的数据进行更改也比较困难,最后,检索数据费事费力。因此,在计算机上安装个人云盘管理系统软件来发挥其…

P6技巧:导出XER设置老版本/新版本

前言 在一个大型的项目中,虽然业主方已要求承包商必须使用P6格式来提交计划,但实际情况是承包商会给到你多种不同版本的XER文件,使得得在Oracle Primavera P6 之间导入或导出。 如果收到的 XER 文件不适合你使用的 Primavera P6 版本&#x…

java学习之路-程序逻辑控制

目录 1.分支结构 1.1 if语句 栗子 判断奇数还是偶数 判断一个年份是否为闰年 1.2switch语句 栗子 2. 循环结构 2.1while 循环 栗子 2.2break和continue break continue 2.3for循环 基本语法 栗子 2.4 do while 循环 3.输入输出 3.1输出 3.2从键盘输入 栗子…

南大通用数据库-Gbase-8a-学习-43-SQL长时间处于Writing to net状态排查

目录 一、问题截图 二、排查思路 1、Gbase8a SQL有几种状态 2、问题导致原因猜想 3、观察服务端(集群端)网络情况 4、观察客户端网络情况 5、排查客户端程序处理数据慢 5.1、send (1)声明 (2)作用…

数据库不应放在容器中?- B站Kubernetes有状态服务实践(Elasticsearch/Clickhouse)

本期作者 前言 云原生时代下, Kubernetes已成为容器技术的事实标准, 使得基础设施领域应用下自动化运维管理与编排成为可能。对于无状态服务而言, 业界早已落地数套成熟且较完美的解决方案。可对于有状态的服务, 方案的复杂度就以…

精简版 Obsidian 图床配置 PicGo+ gitee

精简版 Obsidian 图床配置 PicGo gitee 图床的作用 图床(Image Hosting Service)是一种在线服务,用于存储和托管用户上传的图片文件。用户可以将图片上传到图床服务器,并获得一个可访问的图片链接,然后可以在网页、博…

模板进阶:非类型模板参数,特化

一、非类型模板参数 非类型模板参数&#xff0c;就是用一个常量作为 类/函数 的模板参数&#xff0c;在 类/函数 中可以被当成常量使用。 template<class T, size_t N>// N 为一个非类型模板参数 class Stack { public:Stack(){_a new T[N];} protected:T* _a; };int m…

GAMMA数据处理(六)

最近进行Sentinel-1数据处理,需要用到拼接三个iw的命令,找了一下 但是这样大的数据提取进来,处理速度很慢,后面可能要进行研究区的裁剪,除了开始用的方法,直接在生成的burst_tab文件里面修改参数:删去自己不需要的iw,也就是下面说的这种方法 在指导手册上面看到了其他的…

前端接口防止重复请求实现方案

虽然大部分的接口处理我们都是加了loading的&#xff0c;但又不能确保真的是每个接口都加了的&#xff0c;可是如果要一个接口一个接口的排查&#xff0c;那这维护了四五年的系统&#xff0c;成百上千的接口肯定要耗费非常多的精力&#xff0c;根本就是不现实的&#xff0c;所以…

使用OpenCV实现人脸特征点检测与实时表情识别

引言&#xff1a; 本文介绍了如何利用OpenCV库实现人脸特征点检测&#xff0c;并进一步实现实时表情识别的案例。首先&#xff0c;通过OpenCV的Dlib库进行人脸特征点的定位&#xff0c;然后基于特征点的变化来识别不同的表情。这种方法不仅准确度高&#xff0c;而且实时性好&am…