kud1ing / rucaja

Calling the JVM from Rust via JNI
https://docs.rs/rucaja
Apache License 2.0
31 stars 7 forks source link

Determining linkage to `libjvm` is less than perfect, doesn't work on certain Linux distros #23

Open treyzania opened 6 years ago

treyzania commented 6 years ago

This won't work properly my machine as I don't have $JAVA_HOME set and I'm not on macOS.

On my system (Xubuntu 16.04), libjvm.so lives in /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server. But there's a symlink to the java-8-openjdk-amd64 directory at /usr/lib/jvm/default-java/jre/lib/amd64/server. Different Linux distributions do things different ways so this might not work 100% the same outside of Debian-land.

My /etc/os-release is:

NAME="Ubuntu"
VERSION="16.04.3 LTS (Xenial Xerus)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 16.04.3 LTS"
VERSION_ID="16.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
VERSION_CODENAME=xenial
UBUNTU_CODENAME=xenial

The problem is that not all Linux distributions have an OS release file like this, so it's actually really hard to figure out where libjvm.so is supposed to live. But worse-case scenario we can just search through /usr/lib/jvm until we find a directory with libjvm.so in it, as most people don't have enough JVMs installed to make that unreasonably slow.

I might make a pull request soon with a fix in build.rs that'll probably work on Debians, but I don't really have anything to test it with beyond cargo test.

treyzania commented 6 years ago

Aaaand I'm just now realizing that I made an comment on an issue not unlike this a while back, except I was advocating for doing it dynamically at runtime using libloading. In retrospect it is a bit faster/easier to do it at link-time, and it's more unixy. This time I'll actually do something to fix it.

kud1ing commented 6 years ago

I remember, you've commented in https://github.com/kud1ing/rucaja/issues/12. I am open to it, but i don't see clearly yet how to do cross-platform FFI in Rust at runtime. Compile time fixes are very much appreciated.

treyzania commented 6 years ago

Well I would design some kind of LibJvm struct that contains &Fns from symbols extracted from the library. But again, this is slower and more complicated than doing the "normal" linkages with extern "C". Really the only option here is to just be really clever on build.rs, as that's the closest thing that we have to a configure script with Cargo right now.

treyzania commented 6 years ago

Made some progress on this in #29. Still need to run

export LD_PRELOAD=/usr/lib/jvm/default-java/jre/lib/amd64/server/libjvm.so

which is a huge pain in the ass.

There's a way to get around this by using the rpath ELF variable, but (1) I'm not sure that's available on Windows, and (2) there isn't a way to specify that in build.rs.

We could potentially use #[link_args = ...], but that's not recommended. Worst-case scenario, we use OpenJDK as a submodule and build a static library at build-time.