graalvm把java编译为c/c++能够使用的动态库(dll/so)

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官网连接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java可以通过Java Native Interface(JNI)调用C或C++编写的动态链接库(也就是Windows下的.dll文件,Linux下的.so文件)。以下是一些简单的步骤: 1. 编写C或C++代码并将其编译为动态链接库文件(.dll或.so文件)。 2. 在Java使用JNI接口声明与C或C++代码中的函数对应的Java本地方法,并将其实现为Java本地方法。 3. 编译Java代码并将其打包成jar文件。 4. 将生成的动态链接库文件放到Java程序能够访问到的目录下。 5. 运行Java程序。 以下是一个简单的示例: 1. 编写C代码 ```c #include <stdio.h> #include "jni.h" JNIEXPORT void JNICALL Java_com_example_Test_print(JNIEnv *env, jobject obj, jstring str) { const char *c_str = (*env)->GetStringUTFChars(env, str, NULL); printf("%s\n", c_str); (*env)->ReleaseStringUTFChars(env, str, c_str); } ``` 函数名必须以Java_开头,并加上Java类的完整路径和方法名。 2. 编译动态链接库文件 假设我们已经将上述代码保存为test.c文件,可以使用以下命令将其编译为动态链接库文件: - Windows:gcc -shared -o test.dll test.c -I"%JAVA_HOME%\include" -I"%JAVA_HOME%\include\win32" - Linux:gcc -shared -o libtest.so test.c -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/linux" 注意:这里需要将JDK的include目录和平台相关的include目录添加到编译选项中。 3. 在Java中声明本地方法 ```java public class Test { static { System.loadLibrary("test"); // 加载动态链接库文件 } public static native void print(String str); } ``` 4. 实现Java本地方法 ```java Test.print("Hello, world!"); // 调用本地方法 ``` 这样就可以在Java中调用C代码了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值