For example, each these jars named "native-$os-$arch.jar" contain a .dll/.so/.dylib: https://repo1.maven.org/maven2/com/aayushatharva/brotli4j/
JNA will extract the appropriate native library (using os.name and os.arch system properties), save the library to a temp file, then load it.
> JNA will extract the appropriate native library ..., save the library to a temp file, then load it.
JNA does this?FYI: JNA = Java Native Access project: https://github.com/java-native-access/jna
Because you would use ffi to interact with libraries that don't have Java wrappers yet: IE, you're writing the wrapper.
Using syscalls or libc is a way to write an example against a known library that you're probably familiar with.
[1]: Technically, this is the only distribution model because all Java runtimes as of JDK 9 are created with jlink, including the runtime included in the JDK (which many people use as-is), but I mean a custom runtime packaged with the application.
Java libraries are still obtained from Maven repositories via Maven/Gradle/Ant/Bazel/etc.
I was on the assumption that it was dynamically linking the libarary with the OS dynamic linker, which in no OS I'm aware of is capable of loading libraries inside of zip files.
Not sure where I got that notion. Maybe I was overthinking this.
Decompiled class file:
try {
var4 = File.createTempFile("libzstd-jni-1.5.0-4", "." + libExtension(), var0);
var4.deleteOnExit();Though in the example given, I do see your point now. You'd have to make sure the DLL was unloaded before the delete-on-exit happened.
https://github.com/java-native-access/jna/blob/40f0a1249b5ad...
Do NOT force the class loader to unload the native library, since
that introduces issues with cleaning up any extant JNA bits
(e.g. Memory) which may still need use of the library before shutdown.
Following the blame back to 2011, they did unload DLLs before https://github.com/java-native-access/jna/commit/71de662675b... Remove any automatically unpacked native library. Forcing the class
loader to unload it first is only required on Windows, since the
temporary native library is still "in use" and can't be deleted until
the native library is removed from its class loader. Any deferred
execution we might install at this point would prevent the Native
class and its class loader from being GC'd, so we instead force
the native library unload just a little bit prematurely.
Users reported occasional access violation errors during shutdown. Runtime.getRuntime().addShutdownHook(...)1: https://docs.oracle.com/en/java/javase/22/docs/specs/jni/inv...
You can just load as a resource. We do this internally since much of network stack is C. But we use JNI because code is older than Java 22.
Stackoverflow is full of "copy it into a temp file" solutions. ChatGPT keeps saying "sorry" but still insists on copying it into a temp file :)
[0] - https://docs.oracle.com/en%2Fjava%2Fjavase%2F22%2Fdocs%2Fapi...
new FileOutputStream(tmpFile)
Apologies.I have some extremely unwieldy off-heap operations currently implemented in Java (like quicksort for 128 bit records) that would be very nice to offload as FFI calls to the corresponding a single-line C++ function.
Stay in the swamp :)
Except if we're talking about some college student or hobbyist picking their first language and exploring the language space...
But even if it was needed, such records can be commonly represented by the same structs both at C#'s and C++'s sides without overhead.
An array of such could be passed as is as a pointer, or vice versa - a buffer of struts allocated in C/C++ can be wrapped in a Span<Record128> and transparently interact with the rest of standard library without having to touch unsafe (aside from eventually freeing it, should that be necessary).
Without it 1.6-2MiB-sized AOT binaries would not have been possible (most space is occupied by standard library/runtime bits and GC)
I’ve met many perfectly reasonable developers who do know all those steps can be done but can’t put them all together - maybe because it just hasn’t clicked that you can store a library in a jar. It feels like something tutorials should cover, but I think falls into the, “surely everyone can work it out?” category.
i wonder if there's a way to do this entirely in memory? Because some deployment scenarios might not have disk space at all.
Edit: glibc proposal which was never accepted: https://sourceware.org/bugzilla/show_bug.cgi?id=11767
actually you delete it immediately (after load) on anything that's not windows... even then but it's likely to return false.
deleteOnExit just stores the path to delete and uses a shutdownHook to actually call delete. Nothing really special about it
- Find all the shared libraries in your JARs or configured app inputs (files in your build/source tree)
- Sniff them to figure out what OS and CPU arch they are for
- Bundle them into the right package for each platform that it makes, in the right place to be found by System.loadLibrary()
- Sign them if necessary
- Delete them from the JARs now they are extracted. Optionally extract them from library JARs, sign them and then put them back if your library refuses to load the shared library from disk instead of unpacking it (most libs don't need this)
- JLink a bundled JVM for your app for each platform you target, using jdeps to figure out the right set of modules, and combine that with your shared libs.
When building Debian/Ubuntu packages it will also:
- Read the .so library dependencies, look up the packages that contain those other shared libraries and add package dependencies on those packages, so "apt install" will do the right thing.
So that makes it a lot easier to distribute Java apps that use native code.
Every ffi example I've found seem to operate on the assumption that you want to invoke syscalls or libc, which (with possibly the exception of like madvise and aioring) Java already mostly has decent facilities to interact with even without native calls.