Here are my notes for getting a trivial Java program to call a Rust library:
- Install Java 19 Early Access (recommended: sdk install java 19.ea.29-open)
- Install jextract (it's not part of openJDK, instead look here: https://github.com/openjdk/jextract)
- Create the Rust program (TODO details, cargo init --lib)
Cargo.toml
[package] name ="myrustlibrary" version = "0.1.0" edition = "2021" [dependencies] [lib] crate_type = ["cdylib"] [build-dependencies] cbindgen = "0.20.0"
Add a build.rs file, we want to use cbindgen to create the lib.h file we'll use with jextract.
extern crate cbindgen; use std::env; fn main() { let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); cbindgen::Builder::new() .with_crate(crate_dir) .with_language(cbindgen::Language::C) .generate() .expect("Unable to generate bindings") .write_to_file("lib.h"); }
Add the src/lib.rs contents, for simplicity we'll just echo the PID
use std::process; #[no_mangle] pub extern "C" fn rust_get_pid() -> u32 { return process::id(); }
Now build it: cargo build
Important, keep track of where Cargo built your lib. 'lib.h' will be in the base folder, and the lib itself will be in the 'target/debug' folder (libmyrustlibrary.d libmyrustlibrary.dylib if you're on a Mac)
Run jextract on the lib.h file
./jextract -t org.rust -l myrustlibrary --output classes ./lib.h
Now there will be a bunch of class files in the classes/org/rust dir
Write a Java program to make use of the header file we created from rust (lib.h)
import static org.rust.lib_h.*; // notice this is the target package we specified when running jextract public class Main { public static void main(String[] args){ System.out.println("🦀 process id = " + rust_get_pid()); } }
And finally, tie it all together
./java --enable-preview --source 19 --enable-native-access=ALL-UNNAMED -Djava.library.path=./target/debug -cp classes Main.java 🦀 process id = 5526
No comments:
Post a Comment