graalvm把java编译为c/c++能够使用的动态库(dll/so)
1.安装graalvm
oracle官方企业版
github的openjdk版本
1.1 下载对应系统版本,配置环境变量
本人环境
1.
win10
openjdk 17.0.5 2022-10-18
OpenJDK Runtime Environment GraalVM CE 22.3.0 (build 17.0.5+8-jvmci-22.3-b08)
OpenJDK 64-Bit Server VM GraalVM CE 22.3.0 (build 17.0.5+8-jvmci-22.3-b08, mixed mode, sharing)
2.deepin v23 oracle的需要邮箱验证,随便搞一下就行
java 17.0.7 2023-04-18 LTS
Java(TM) SE Runtime Environment GraalVM EE 22.3.2 (build 17.0.7+8-LTS-jvmci-22.3-b15)
Java HotSpot(TM) 64-Bit Server VM GraalVM EE 22.3.2 (build 17.0.7+8-LTS-jvmci-22.3-b15, mixed mode, sharing)
1.2 安装c/c++开发工具
win10需要安装 Visual Studio
1.2下载对应工具
1.cmd命令使用 其中gu是graalvm提供的工具
gu available 查看可用的工具
安装native-image 、llvm、llvm-toolchain
espresso
js
llvm
llvm-toolchain 使用动态库的话要安装这个和llvm
native-image 直接把java便以为可执行文件必须安装
nodejs
visualvm
wasm
2.编写代码
2.1 HelloWorld.java
编写限制
1.必须有一个入口函数,默认可以是main方法,可以在c或者c++调用
2.方法必须是静态(公开私有好像无所谓,没研究)
3.导出的方法要使用@CEntryPoint注解标记
4.方法第一个参数必须是IsolateThread,这个是c/c++的线程上下文
5.方法返回值可以是指针(graalvm里面有指针类型)和基本类型,不能是包装类型
import org.graalvm.nativeimage.IsolateThread;
import org.graalvm.nativeimage.c.function.CEntryPoint;
import org.graalvm.nativeimage.c.type.CCharPointer;
import org.graalvm.nativeimage.c.type.CTypeConversion;
public class HelloWorld{
public static void main(String[] args){
System.out.println("Hello World");
}
@CEntryPoint(name = "add")
public static int add(IsolateThread thread, int a, int b) {
//这里测试修改动态库把+换成*
return a * b;
}
}
2.2 编写c代码
2.2编译生成头文件和动态库
1.javac HelloWorld.java 这里的javac必须是graalvm提供的
2.native-image HelloWorld 这里直接生成pe或者elf文件(相当于静态连接) win10最好是在x64里面进入命令行
3.native-image -H:Name=libhelloworld --shared
这里会生成几个头文件
libhelloworld_dynamic.h graal_isolate_dynamic.h HelloWorld.java graal_isolate.h libhelloworld.build_artifacts.txt libhelloworld.so libhelloworld.dll
2.3 编写c代码
注意libhelloworld.h文件里面有引用graal_isolate.h 可以把尖括号换成双引号
#include <stdio.h>
#include <stdlib.h>
#include "libhelloworld.h"
int main(int argc, char **argv) {
if (argc < 3) {
fprintf(stderr, "请输入两个数字\n", argv[0]);
exit(1);
}
graal_isolate_t *isolate = NULL;
graal_isolatethread_t *thread = NULL;
if (graal_create_isolate(NULL, &isolate, &thread) != 0) {
fprintf(stderr, "initialization error\n");
return 1;
}
int num1 = 0;
int num2 = 0;
sscanf_s(argv[1], "%d", &num1);
sscanf_s(argv[2], "%d", &num2);
int result = add(thread, num1, num2);
printf("%d+%d=%d\n", num1, num2, result);
graal_tear_down_isolate(thread);
return 0;
}
2.4 编译代码
4.使用clang编译并且动态连接
win10
%JAVA_HOME%/languages/llvm/native/bin/gcc -I ./ -L ./ -l libhelloworld -o main main.c
deepin
$JAVA_HOME/languages/llvm/native/bin/gcc -I ./ -L ./ -l helloworld -Wl,-rpath ./ -o main main.c
3.执行代码
这个功能的作用
1.一些现成的java工具类或者算法可以直接搬到c/c++
2.这个生成的动态库在java侧也能使用,增加反编译复杂程度
3.java和c/c++的桥梁进一步扩宽
打完收工
参考文章 oracle官网连接