Introduction
I have a Rust library that I want to be able to call from Java through JNI. Using Maven, I can use it, but I'm stuck when I try to move to Bazel.
I run bazel run //my_lib/java:java_binary and I get the following
Exception in thread "main" java.lang.UnsatisfiedLinkError: no rust_bindings in java.library.path: [/private/var/tmp/_bazel_XXXXXXXXX/XXXXXXXXXXXXX/execroot/__main__/bazel-out/darwin-fastbuild/bin/my_lib/java/java_binary.runfiles/__main__/my_lib/rust]
at java.base/java.lang.ClassLoader.loadLibrary(ClassLoader.java:2680)
at java.base/java.lang.Runtime.loadLibrary0(Runtime.java:807)
at java.base/java.lang.System.loadLibrary(System.java:1907)
at Main.<clinit>(Main.java:8)
which means the Rust shared library library isn't available. Indeed when I tree /private/var/tmp/_bazel_XXXXXXXXX/XXXXXXXXXXXXX/execroot/__main__/bazel-out/darwin-fastbuild/bin/my_lib/java/java_binary.runfiles/__main__/my_lib, I get
└── java
├── java_binary -> /private/var/tmp/_bazel_XXXXXXXXX/XXXXXXXXXXXXX/execroot/__main__/bazel-out/darwin-fastbuild/bin/stackoverflow/java/java_binary
└── java_binary.jar -> /private/var/tmp/_bazel_XXXXXXXXX/XXXXXXXXXXXXX/execroot/__main__/bazel-out/darwin-fastbuild/bin/stackoverflow/java/java_binary.jar
How come bazel doesn't build the Rust shared library despite the fact it's a dependancy of the Java binary?
The code
$ tree .
├── java
│ ├── BUILD.bazel
│ ├── Main.class
│ └── Main.java
└── rust
├── BUILD.bazel
├── CARGO
│ └── BUILD.bazel
├── Cargo.toml
└── src
└── lib.rs
java/Main.java
public class Main {
static native void rust();
static {
System.loadLibrary("rust_bindings");
}
public static void main(String[] args) {
System.out.println("Hello from Java");
rust();
}
}
java/BUILD.bazel
package(default_visibility = ["//visibility:public"])
load("@rules_java//java:defs.bzl", "java_binary")
java_binary(
name = "java_binary",
srcs = glob(["*.java"]),
main_class = "Main",
deps = [
"//my_lib/rust:rust_bindings"
],
)
rust/Cargo.toml
[package]
name = "rust_bindings"
version = "0.1.0"
edition = "2018"
[lib]
name="rust_bindings"
crate-type = ["cdylib"]
[dependencies]
jni = "0.19.0"
rust/src/lib.rs
use jni::JNIEnv;
use jni::objects::{JClass, JString};
#[no_mangle]
pub extern "system" fn Java_Main_rust(env: JNIEnv,class: JClass)
{
println!("Hello from Rust");
}
rust/BUILD.bazel
package(default_visibility = ["//visibility:public"])
load("@rules_rust//rust:defs.bzl", "rust_shared_library")
load("//cargo:crates.bzl", "all_crate_deps")
rust_shared_library(
name = "rust_bindings",
srcs = glob(["src/**/*.rs"]),
edition = "2018",
deps = all_crate_deps(), // Import the JNI crate using Bazel
)
Edit: simplified the code