当前位置:   article > 正文

通过JNA调用Rust动态库

通过JNA调用Rust动态库

1、实现Hello World
rust代码(lib.rs)
提供了两种方式调用(JNI、JNA)
JNA 使用*const c_char映射Java String,用rust的String会出现乱码
JNI使用jstring 映射Java String

extern crate jni;

use jni::JNIEnv;
use jni::objects::*;
use jni::sys::{jint, jobject, jstring};
use std::os::raw::c_char;
use std::ffi::{CStr,CString};

#[no_mangle]
pub extern fn foo(a: i32, b: i32) ->i32 {
    println!("hello : a + b = {}", a + b);
    return a+b;
}


#[no_mangle]
pub extern fn boo(input: *const c_char) -> *const c_char  {
    let owned_string: String = "hello ".to_owned();
    let name = to_string(input);
    println!("Hello from Rust, {}{}", owned_string,name);
    let r =  to_ptr(format!("{}, {}!", owned_string,name));
    return r;
}


/// Convert a native string to a Rust string
fn to_string(pointer: *const c_char) -> String {
    let slice = unsafe { CStr::from_ptr(pointer).to_bytes() };
    std::str::from_utf8(slice).unwrap().to_string()
}

/// Convert a Rust string to a native string
fn to_ptr(string: String) -> *const c_char {
    let cs = CString::new(string.as_bytes()).unwrap();
    let ptr = cs.as_ptr();
    // Tell Rust not to clean up the string while we still have a pointer to it.
    // Otherwise, we'll get a segfault.
    std::mem::forget(cs);
    ptr
}


#[no_mangle]
pub extern "system" fn Java_org_example_Main_hello<'local>(mut env: JNIEnv<'local>,class: JClass<'local>,input: JString<'local>) -> jstring  {
    let input: String =
        env.get_string(&input).expect("Couldn't get java string!").into();

    // Then we have to create a new java string to return. Again, more info
    // in the `strings` module.
    let output = env.new_string(format!("Hello, {}!", input))
        .expect("Couldn't create java string!");

    // Finally, extract the raw pointer to return.
    return output.into_raw();
}
rust代码(Cargo.toml)
[package]
name = "hello_world"
version = "0.1.0"
edition = "2021"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60

See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[lib]
name = "hello_world"
crate-type = ["cdylib"]

[dependencies]
jni = "0.21.1"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

生成DLL
cargo build --release --lib
方式一:通过JNI方式
这里调用的是rust里面的"Java_org_example_Main_hello",固定写法"Java"+“包名”+“类名”+“函数名”

package org.example;

public class Main {
    public Main() {
    }

    public static void main(String[] args) {
        System.out.println(hello("1...world...1"));
    }

    static native String hello(String var0);

    static {
        System.load("D:\\IdeaProjects\\RustDemo\\src\\main\\resources\\hello_world.dll");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

方式二:通过JNA方式
通过JNA方式函数稍微简单一些,不用按照固定的格式,不用写JNIEnv、JClass等参数,但是需要转换String

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.example;

import com.sun.jna.Library;
import com.sun.jna.Native;

public class Hello {

    public Hello() {
    }

    public static void main(String[] args) {
        System.setProperty("jna.encoding", "UTF-8");
        System.out.println(Hello.DLL.INSTANCE.boo("1...world...1"));
        System.out.println(Hello.DLL.INSTANCE.boo("1...world...1"));
        System.out.println(Hello.DLL.INSTANCE.boo("world"));
        System.out.println(Hello.DLL.INSTANCE.boo("1world1"));
        System.out.println(Hello.DLL.INSTANCE.boo("world"));
        System.out.println(Hello.DLL.INSTANCE.foo(1, 2));
        System.out.println(Hello.DLL.INSTANCE.boo("world"));
    }

    public interface DLL extends Library {
        DLL INSTANCE = (DLL)Native.load("hello_world", DLL.class);

        String boo(String var1);

        int foo(int var1, int var2);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

jna依赖(maven)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>RustDemo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>net.java.dev.jna</groupId>
            <artifactId>jna</artifactId>
            <version>5.12.1</version>
        </dependency>
    </dependencies>

    <build>
        <sourceDirectory>java</sourceDirectory>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.4</version>
                <configuration>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

2、实现JNA加载多个动态库
虽然说JNA可以加载resource下动态库及其依赖,但是达成Jar包后就无法加载
按照JNA官方的说法,可以采取以下方式处理:
https://github.com/java-native-access/jna/blob/master/www/GettingStarted.md
Make your target library available to your Java program. There are several ways to do this:
The preferred method is to set the jna.library.path system property to the path to your target library. This property is similar to java.library.path, but only applies to libraries loaded by JNA.
Change the appropriate library access environment variable before launching the VM. This is PATH on Windows, LD_LIBRARY_PATH on Linux, and DYLD_LIBRARY_PATH on OSX.
Make your native library available on your classpath, under the path {OS}-{ARCH}/{LIBRARY}, where {OS}-{ARCH} is JNA’s canonical prefix for native libraries (e.g. win32-x86, linux-amd64, or darwin). If the resource is within a jar file it will be automatically extracted when loaded.
通过复制Jar中Resource中动态库并设置jna.library.path环境变量,实现对动态资源的加载
通过以下代码可实现调试和发布均正常使用JNA

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.example;

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Optional;
import java.util.jar.JarFile;

public class ConvertUtils {
    private static final String JAVA_IO_TMPDIR = "java.io.tmpdir";
    private static final String TEMP_DIR = System.getProperty("java.io.tmpdir");
    private static final String JNA_LIBRARY_PATH = "jna.library.path";
    private static final String SPRING_JAR = "BOOT-INF/classes";
    
    public ConvertUtils() {
    }

    public static void main(String[] args) throws URISyntaxException, IOException {
        System.setProperty("jna.encoding", "UTF-8");
        String jnaLibraryPath = getJnaLibraryPath();
        System.out.println("jnaLibraryPath = " + jnaLibraryPath);
        System.out.println(ConvertUtils.DLL.INSTANCE.foo(1, 2));
        System.out.println(ConvertUtils.DLL.INSTANCE.boo("1...world...1"));
        System.out.println(ConvertUtils.DLL.INSTANCE.boo("world"));
        System.out.println(ConvertUtils.DLL.INSTANCE.boo("1world1"));
        System.out.println(ConvertUtils.DLL.INSTANCE.boo("world"));
    }

    private static String getJnaLibraryPath() throws URISyntaxException, IOException {
        URL current_jar_dir = ConvertUtils.class.getProtectionDomain().getCodeSource().getLocation();
        System.out.println("current_jar_dir = " + current_jar_dir);
        Path jar_path;
        String path = Platform.RESOURCE_PREFIX;
        if (current_jar_dir.getPath().contains(SPRING_JAR)) {
            jar_path = Paths.get(current_jar_dir.toString().substring(10, current_jar_dir.toString().indexOf(SPRING_JAR) - 2));
            path = SPRING_JAR + "/" + Platform.RESOURCE_PREFIX;
        } else {
            jar_path = Paths.get(current_jar_dir.toURI());
        }
        String folderContainingJar = jar_path.getParent().toString();
        ResourceCopy r = new ResourceCopy();
        Optional<JarFile> jar = r.jar(ConvertUtils.class);
        if (jar.isPresent()) {
            try {
                System.out.println("JAR detected");
                File target_dir = new File(folderContainingJar);
                System.out.println(String.format("Trying copy from %s %s to %s", jar.get().getName(), path, target_dir));
                // perform dir copy
                r.copyResourceDirectory(jar.get(), path, target_dir);
                // add created folders to JNA lib loading path
                System.setProperty(JNA_LIBRARY_PATH, target_dir.getCanonicalPath());
                return target_dir.getCanonicalPath();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return Thread.currentThread().getContextClassLoader().getResource("").getPath().substring(1) + Platform.RESOURCE_PREFIX;
    }

    public interface DLL extends Library {
        DLL INSTANCE = (DLL)Native.load("_3dtile", DLL.class);

        String boo(String var1);

        int foo(int var1, int var2);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号