News for hackers. Stuff that matters.
Re:How to Use the Foreign Function API in Java 22 to Call C ... by marginalia_nu on Wednesday May 08, 2024 @12:59PM (#40300347)
What I'm missing is a model for building/distributing those C libraries with a java application.

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.

Re:How to Use the Foreign Function API in Java 22 to Call C ... by sedro on Wednesday May 08, 2024 @02:02PM (#40301123)
Native libraries are typically packaged inside a jar so that everything works over the existing build and dependency management systems.

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.

Re:How to Use the Foreign Function API in Java 22 to Call C ... by throwaway2037 on Wednesday May 08, 2024 @10:10PM (#40304602)

    > 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

Re:How to Use the Foreign Function API in Java 22 to Call C ... by sedro on Wednesday May 08, 2024 @11:29PM (#40305045)
Re:How to Use the Foreign Function API in Java 22 to Call C ... by okr on Thursday May 09, 2024 @08:56PM (#40314509)
Examples of JARs, that transport such libraries: snappy, sqlite...
Re:How to Use the Foreign Function API in Java 22 to Call C ... by gwbas1c on Wednesday May 08, 2024 @03:00PM (#40301718)
> Every ffi example I've found seem to operate on the assumption that you want to invoke syscalls or libc ... Java already mostly has decent facilities to interact with even without native calls.

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.

Re:How to Use the Foreign Function API in Java 22 to Call C ... by pron on Wednesday May 08, 2024 @01:28PM (#40300722)
The recommended distribution model for Java applications is a jlinked runtime image [1], which supports including native libraries in the image.

[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.

Re:How to Use the Foreign Function API in Java 22 to Call C ... by maksut on Wednesday May 08, 2024 @02:27PM (#40301398)
Is that still true when distributing libraries?
Re:How to Use the Foreign Function API in Java 22 to Call C ... by brabel on Wednesday May 08, 2024 @04:12PM (#40302347)
Absolutely not. jlink is used to distribute applications (it includes your code, the Java libs you use, i.e. their jars, and the trimmed-down JVM with the modules you're using so that your distribution is not so big - typically around 30MB).

Java libraries are still obtained from Maven repositories via Maven/Gradle/Ant/Bazel/etc.

Re:How to Use the Foreign Function API in Java 22 to Call C ... by pron on Wednesday May 08, 2024 @03:24PM (#40301918)
If you distribute libraries as jmod files, which few libraries do (in that case, jlink would automatically extract the native libraries and place them in the appropriate location).
Re:How to Use the Foreign Function API in Java 22 to Call C ... by pjmlp on Wednesday May 08, 2024 @01:27PM (#40300693)
You do it the standard way, package them inside the jar file.
Re:How to Use the Foreign Function API in Java 22 to Call C ... by marginalia_nu on Wednesday May 08, 2024 @01:32PM (#40300783)
Oh, does this actually work?

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.

Re:How to Use the Foreign Function API in Java 22 to Call C ... by brabel on Wednesday May 08, 2024 @04:15PM (#40302373)
I remember using Sqlite Java and not having to install sqlite on the image. Then I looked inside the Sqlite-java's jar and they just packed the sqlite binaries for the different OSs in the jar!!
Re:How to Use the Foreign Function API in Java 22 to Call C ... by DannyB2 on Wednesday May 08, 2024 @04:32PM (#40302495)
I once (2016 ish) used a serial-port library for Java. Needed to be cross platform desktop app for Linux, Windows and Mac (in that order, all on x86/64). And it was. I have forgotten the name of the library project I included, but it included DLL binaries for the platforms we were targeting.
Re:How to Use the Foreign Function API in Java 22 to Call C ... by dehrmann on Thursday May 09, 2024 @01:38AM (#40305579)
Not sure if this is still the case, but one of the Java Sqlite driver used something called NestedVM to run Sqlite in the JVM when a native library wasn't available. It worked by cross-compiling the code to mips, then transpiling the mips assembly to Java byte code. I can't remember if it bridged system calls or libc calls to Java for things like file IO.
Re:How to Use the Foreign Function API in Java 22 to Call C ... by KptMarchewa on Thursday May 09, 2024 @05:55AM (#40306658)
That's a common solution. I do the same.
Re:How to Use the Foreign Function API in Java 22 to Call C ... by zten on Wednesday May 08, 2024 @01:36PM (#40300836)
Yes. Check out a library like zstd-jni. You'll find native libraries inside it. It'll load from the classpath first, and then ask the OS linker to find it.
Re:How to Use the Foreign Function API in Java 22 to Call C ... by maksut on Wednesday May 08, 2024 @02:03PM (#40301137)
I'd like to learn how they do it. Because last time I've looked at this, the suggested solution was to copy the binaries from claspath (eg: the jar) into a temporary folder then load it from there. It feels icky :)
Re:How to Use the Foreign Function API in Java 22 to Call C ... by zten on Wednesday May 08, 2024 @03:39PM (#40302053)
Yep, you're right, they do exactly that. Apologies for the confusion.

Decompiled class file:

    try {
        var4 = File.createTempFile("libzstd-jni-1.5.0-4", "." + libExtension(), var0);
        var4.deleteOnExit();
Re:How to Use the Foreign Function API in Java 22 to Call C ... by sedro on Wednesday May 08, 2024 @08:42PM (#40304154)
This wouldn't work on Windows, because you can't delete a DLL while it's in use
Re:How to Use the Foreign Function API in Java 22 to Call C ... by BenjiWiebe on Wednesday May 08, 2024 @09:57PM (#40304544)
Couldn't you: Extract DLL Load DLL Unload DLL Delete DLL ?

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.

Re:How to Use the Foreign Function API in Java 22 to Call C ... by sedro on Wednesday May 08, 2024 @11:18PM (#40304991)
According to JNA it's not safe to unload the DLL:

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.
Re:How to Use the Foreign Function API in Java 22 to Call C ... by tadfisher on Wednesday May 08, 2024 @10:58PM (#40304881)
You can install a shutdown hook to do cleanup like this.

    Runtime.getRuntime().addShutdownHook(...)
Re:How to Use the Foreign Function API in Java 22 to Call C ... by sedro on Wednesday May 08, 2024 @11:22PM (#40305010)
That's how java.io.File#deleteOnExit works under the hood. The DLL is still loaded at that point and can't be deleted.
Re:How to Use the Foreign Function API in Java 22 to Call C ... by tadfisher on Thursday May 09, 2024 @03:51PM (#40312275)
Ah, looking through the docs [1]; you have to use your own ClassLoader (so it can be garbage-collected), and statically-link with a JNI library which is unloaded when the ClassLoader is garbage-collected.

1: https://docs.oracle.com/en/java/javase/22/docs/specs/jni/inv...

Re:How to Use the Foreign Function API in Java 22 to Call C ... by electrum on Thursday May 09, 2024 @12:30AM (#40305316)
You might be able to use FILE_FLAG_DELETE_ON_CLOSE, but this would likely require calling the Windows API functions directly.
Re:How to Use the Foreign Function API in Java 22 to Call C ... by zten on Thursday May 09, 2024 @12:27PM (#40309870)
Hmm, interesting. They do have DLLs in the JAR...
Re:How to Use the Foreign Function API in Java 22 to Call C ... by renewiltord on Wednesday May 08, 2024 @02:26PM (#40301387)
EDIT: Disregard. I am wrong. Original below.

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.

Re:How to Use the Foreign Function API in Java 22 to Call C ... by maksut on Wednesday May 08, 2024 @02:55PM (#40301671)
You made me search it again. And still I don't see how that's possible. `Runtime.load` requires a regular file with an absolute path[0].

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...

Re:How to Use the Foreign Function API in Java 22 to Call C ... by renewiltord on Wednesday May 08, 2024 @03:03PM (#40301749)
Embarrassing of me to give you wrong answer. I went and checked my old code and:

     new FileOutputStream(tmpFile)
Apologies.
Re:How to Use the Foreign Function API in Java 22 to Call C ... by marginalia_nu on Wednesday May 08, 2024 @01:41PM (#40300891)
Sounds promising.

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.

Re:How to Use the Foreign Function API in Java 22 to Call C ... by neonsunset on Wednesday May 08, 2024 @02:10PM (#40301219)
Why not give C# a try instead? It has everything you ask for and then some.
Re:How to Use the Foreign Function API in Java 22 to Call C ... by neonsunset on Thursday May 09, 2024 @01:47AM (#40305619)
Wow, you all are sure mad enough to go out of your way and downvote my comments elsewhere.

Stay in the swamp :)

Re:How to Use the Foreign Function API in Java 22 to Call C ... by coldtea on Thursday May 09, 2024 @05:17AM (#40306496)
Because "some inconvenience/unmet requirement" from a language is not an invitation to "throw out the whole platform and your existing code and tooling, and learn/adopt/use an entirely different, single-vendor platform".

Except if we're talking about some college student or hobbyist picking their first language and exploring the language space...

Re:How to Use the Foreign Function API in Java 22 to Call C ... by imtringued on Thursday May 09, 2024 @10:02AM (#40308341)
He would still have to call out to the C++ function.
Re:How to Use the Foreign Function API in Java 22 to Call C ... by neonsunset on Thursday May 09, 2024 @10:46AM (#40308773)
Assuming it is "sort for 128bit records", that's something C# does really well - writing optimized code with structs / Vector128<T> / pointer arithmetic when really needed without going through FFI and having to maintain separate build step and project parts for a different platform.

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).

Re:How to Use the Foreign Function API in Java 22 to Call C ... by saagarjha on Wednesday May 08, 2024 @08:03PM (#40303955)
Android knows how to do this, actually.
Re:How to Use the Foreign Function API in Java 22 to Call C ... by fire_lake on Wednesday May 08, 2024 @02:13PM (#40301261)
Is there a solution when the binaries are 500mb+ per platform?
Re:How to Use the Foreign Function API in Java 22 to Call C ... by pjmlp on Wednesday May 08, 2024 @05:56PM (#40303097)
People seem pretty happy when Go and Rust do the same with static linking, advocating how great it happens to be.
Re:How to Use the Foreign Function API in Java 22 to Call C ... by yw3410 on Wednesday May 08, 2024 @07:40PM (#40303831)
You can't be as aggressive at removing functions in Java than in Rust though since it's dynamic dispatch (e.g., if you use toString once in your code, you need to keep all implementations of toString which are reachable even if users don't use reflection).
Re:How to Use the Foreign Function API in Java 22 to Call C ... by neonsunset on Thursday May 09, 2024 @05:05AM (#40306446)
.NET's trimmer/linker deals with this quite well, only referenced or otherwise observable .ToString() implementations are rooted.

Without it 1.6-2MiB-sized AOT binaries would not have been possible (most space is occupied by standard library/runtime bits and GC)

Re:How to Use the Foreign Function API in Java 22 to Call C ... by pjmlp on Thursday May 09, 2024 @07:20AM (#40307025)
Except that is what jlinker, and GraalVM/OpenJ9 (among other AOT toolchains) do in practice.
Re:How to Use the Foreign Function API in Java 22 to Call C ... by cesarb on Wednesday May 08, 2024 @07:02PM (#40303578)
Static linking in Go and Rust includes compiled code only for the target platform. It does not include compiled code for every possible architecture, including 32-bit MacOS and Solaris on PowerPC.
Re:How to Use the Foreign Function API in Java 22 to Call C ... by SJC_Hacker on Wednesday May 08, 2024 @08:34PM (#40304110)
Solaris... now thats a name I have not heard in a long time. A long time.
Re:How to Use the Foreign Function API in Java 22 to Call C ... by pjmlp on Thursday May 09, 2024 @07:22AM (#40307040)
Hence why you end up with 300MB x platforms, and tricks like upx.
Re:How to Use the Foreign Function API in Java 22 to Call C ... by fire_lake on Thursday May 09, 2024 @01:43AM (#40305601)
In Java libraries are shared precompiled so the package manager either needs to be platform aware or distribute fat bundles.
Re:How to Use the Foreign Function API in Java 22 to Call C ... by pjmlp on Thursday May 09, 2024 @07:21AM (#40307030)
Only for those that are yet to learn how to use jlinker.
Re:How to Use the Foreign Function API in Java 22 to Call C ... by mike_hearn on Thursday May 09, 2024 @03:49AM (#40306174)
Libraries like JCEF have support tools to download the libraries either at runtime or during the build, to offload from Maven Central.
Re:How to Use the Foreign Function API in Java 22 to Call C ... by ruslan_talpa on Wednesday May 08, 2024 @01:26PM (#40300675)
Put them in a jar?
Re:How to Use the Foreign Function API in Java 22 to Call C ... by aardvark179 on Wednesday May 08, 2024 @07:04PM (#40303594)
So, other people have already answered this, but this does seem to be a gap where many developers lack some piece of knowledge to chain the whole solution together. You normally package this sort of thing by putting the native library in a jar, extracting it to a tmp file that will be deleted on exit, and opening that dynamic library.

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.

Re:How to Use the Foreign Function API in Java 22 to Call C ... by chii on Wednesday May 08, 2024 @08:40PM (#40304140)
> extracting it to a tmp file

i wonder if there's a way to do this entirely in memory? Because some deployment scenarios might not have disk space at all.

Re:How to Use the Foreign Function API in Java 22 to Call C ... by MobiusHorizons on Wednesday May 08, 2024 @08:52PM (#40304199)
/tmp is often a RAM disk in such cases
Re:How to Use the Foreign Function API in Java 22 to Call C ... by xxs on Thursday May 09, 2024 @01:34AM (#40305566)
not with java - it needs a path. Of course if you have a ram disk (e.g. /tmp) it'd do the job.
Re:How to Use the Foreign Function API in Java 22 to Call C ... by rwmj on Thursday May 09, 2024 @07:45AM (#40307193)
Technically memfd_create will let you create a file descriptor backed by a memory region. However in Linux I don't believe there's a way to dlopen that. (Maybe dlopen /dev/fd/... might work?) In FreeBSD there's a fdlopen library function.

Edit: glibc proposal which was never accepted: https://sourceware.org/bugzilla/show_bug.cgi?id=11767

Re:How to Use the Foreign Function API in Java 22 to Call C ... by sedro on Wednesday May 08, 2024 @08:54PM (#40304213)
You would also need to learn about Maven profiles and activation. And for other build tools, you'll be delighted to know they have partial support.
Re:How to Use the Foreign Function API in Java 22 to Call C ... by xxs on Thursday May 09, 2024 @01:28AM (#40305539)
>exract it to a tmp file that will be deleted on exit,

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

Re:How to Use the Foreign Function API in Java 22 to Call C ... by mike_hearn on Thursday May 09, 2024 @11:48AM (#40309437)
If your app is open source, or you're willing to buy a commercial tool, then you could try Conveyor from my company [1]. It will:

- 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.

[1] https://www.hydraulic.dev/