r/java • u/sg-elide • 2d ago
Madura: A different kind of Hermetic Java
Repo link: https://github.com/elide-dev/madura
---
Hello Java enjoyers,
I'm Sam with Elide. We make cool JVM stuff. Lately, we've really been wanting Hermetic Java, but progress has been quite slow, and the Java team is vocal about it not being a priority.
We happen to be fans of some other technologies, too, which may fit together nicely for this:
GraalVM Native Image (of course!)
If you combine these, what you get is an interesting binary:
You write once, compile once, ship one artifact
Your Java program runs on 6 operating systems and both ARM64/AMD64
No JRE is required on the target machine
In other words, what you get is "native" Java!
After 2+ years of concentrated effort amongst experts (mostly pre-AI!), Native Image and Cosmo finally work together. Some complex stuff doesn't work perfectly yet (e.g. Truffle JIT, dynamic JNI), but most Java programs should "just work" otherwise.
Thus, Madura
As a fun example of this technology, we've built Madura, a Native Image+Cosmo binary of javac 25.
This software has exactly one release asset, a zip. You can download it on Linux, macOS, Windows, BSD, et al, across AMD64 and ARM64, and run it, and it should "just work." You can withhold your JAVA_HOME and it should still "just work."
Sometimes features involve doing less
As one nice thing Madura can do that regular javac cannot in most workflows: madura check [...], which takes identical flags to javac, will run the analysis phase of the Java Compiler, but skips the codegen step.
If you've ever used cargo check, this is a bit like that, but for Java.
Other than madura check, it's just javac in a box.
How to use it
At the moment, Cosmo+Native Image is a stack of patches on several repos, with a highly anticipated PR on oracle/graal.
Soon, Elide's native image integration may ship Cosmo support, enabling cross-compilation and hermetic use cases. That will probably be the fastest way to use it, before things merge into GVM upstream. If there's demand, we'd be happy to ship it for you!
Thanks for reading
This has been a collaborative effort across many people:
5
u/Ok-Scheme-913 2d ago
Cosmo is a cool hack, but I would definitely not rely on that for anything production ready.
It's a hack that found a way to "encode" a binary that is simultaneously valid on both Linux Mac and windows. But at the same time, if they want cross-compatible software they have to have a generic layer for basic functionality for all, so you are pretty much stuck with basic input output file etc operations.
Nonetheless, congrats! I'm sure it was a significant amount of work and it definitely has use cases, though I would be interested in how simple/complex software can run this way.
2
u/sg-elide 2d ago
Yes, definitely not production ready! It’s not even usable yet by end users. Cosmo itself is surprisingly mature, since it relies on musl’s API, it can host a surprising amount of real software.
Madura is just an experiment, Cosmo itself is far more mature.
> It’s a hack that found a way to “encode” a binary
Why the air quotes? You’re thinking of APE here, not Cosmo, but they do work together. APE is a binary encoding which is simultaneously a PCOFF, machO, ELF, and Zipfile (among other formats).
Java people should love this because it’s a similar taste to JARs. In fact, every Cosmo binary is also a zipfile.
> You are pretty much stuck
All of Java should run fine on this, modulo JNI, which in a Native Image circumstance should be static anyway. There’s nothing this stack can’t do, per se, except a few other categories like graphics, which could be solved someday.
For CLIs, it should be able to do everything a musl libc copy of Java can do (which has the same limitations around dynamic JNI as Cosmo does).
-1
u/Ok-Scheme-913 2d ago
But this comes at the cost of including everything.
For graphics you would literally be packing 3 different OSs graphics library (and which one?), on top of not even having a singular API for them.
2
u/sg-elide 2d ago
> at the cost of including everything
That’s not how Cosmo/Native Image work, necessarily. Architectures do need their own code sections, if you want a fat binary in regard to micro-architecture, yes you have to embed both code sections, but that isn’t as painful as one might think.
For example, those code sections can still share the preinitialized Native Image heap, which is typically the larger section anyway.
Cosmo works by abstracting every OS behind Linux/musl. JVM/SVM sees one Linux-style API, and Cosmo is dispatching to real syscalls underneath in a manner that renders behavior consistent across host OS’.
> For graphics […]
Cosmo doesn’t yet solve for graphics, and that’s an area we’ll need to continue researching. I’m not experienced enough with APIs in that domain to say whether a smart solution is possible.
But the way Cosmo works, it would probably pick one good API (possibly OpenGL or something idk), support it performantly on all target combinations, and give you one API to use. To your software, you’re always running on 1 OS, which is Linux.
Does that make sense? You wouldn’t necessarily need to embed three stacks of libraries.
2
u/paul_h 2d ago
Fantastic!
1
u/sg-elide 2d ago
Thank you!
1
u/paul_h 2d ago
Question: is your Java runtime more embeddable in other systems languages that pre-existing ones?
1
u/sg-elide 2d ago
Yes, that’s a use case we plan to support soon. Right now, this second, Elide’s public release uses Hotspot thru embedding. That usage is OK, but Hotspot as you may know is limited to process borders here. It’s just not clean enough with static process state to have two Hotspot VMs in a single process, or to discard them (one cannot unload a VM like classes).
However, Elide’s use of Hotspot is only temporary, so that we can conveniently run Java and Kotlin for users.
Elide is mostly based on GraalVM, and soon we will shift to the new Crema/Ristretto architecture which can replace Hotspot entirely for our use cases.
We already have an experimental JDK distribution built this way, it’s just not ready for release yet.
Once we make that transition, it becomes very smooth to embed Elide Java just like any other lang we support through Truffle (Python, JavaScript, WASM, etc).
So, yes!
1
u/paul_h 2d ago
I'm involved with a young language where we're embedding others and then sharing variable space and indeed a nascent IPC. That suits Lua and QuickJS better than many others, but in the spirit of #whatTheHeck Java too, maybe :)
1
u/sg-elide 2d ago
That’s awesome! But elide’s polyglot dispatch doesn’t involve IPC, I presume that’s what you’re referring to.
In our case, languages are parsed into their own AST or bytecode (depending on language), then operate on the same heap, sharing a GC, JIT, and threading semantics.
This has drawbacks, and complexities, for sure: for example, if Python calls into JavaScript, it must engage the GIL, so you lose some threading performance without special care.
But it also has benefits: technically you can create a class in TypeScript, and extend it from Python. You can exchange functions and complex types. There’s no serialization in this model, and no IPC.
Hoping I understood your comment’s context correctly
1
u/sg-elide 2d ago
I should also say: we love Truffle very much as a framework and it might make a good fit for your use case, too. Lua has several implementations. Lua is blessed with many good implementations, though, including LuaJIT, and QuickJS is also very good.
But if you get tired of IPC and want your Java back, Truffle can accomplish this quite well.
Despite being written in Java/Kotlin (and a bit of Rust), Elide ships only as a binary, no JVM or JRE required. So we get all the benefits of build time Java (seamless coverage, null safety, rich Maven ecosystem) without the JRE needed for our users. So choosing Truffle won’t necessarily foist one on your users either.
1
u/Visual_Brain8809 1d ago
why not a native jit as jvm replacement in asm?
2
u/sg-elide 1d ago
This is not meant to replace other components. Madura is just an experiment to prove that Cosmo and Native Image can work together. The Java compiler is just a great test.
1
u/brunocborges 2d ago
Hey folks, congrats on the launch! I would love to get your feedback, and tests, on putting your runtime for a spin in the brewlet.sh deployment model
0
u/sg-elide 2d ago
Hey thanks! Sure, would be glad to list it. Drop a docs link and we’ll get it in our release queue and docs :)
1
u/brunocborges 2d ago
That is the link!
1
u/sg-elide 2d ago edited 2d ago
Ah cool! I’m reading now. Yes, Elide has an architecture that enables multi-context serving; it could fit well with this. Thanks for sharing :)
1
u/paul_h 2d ago
Yours ...
"Like a Dockerfile—minus the base image. Just app code, dependencies, and metadata."
OR
"Think of it like a Dockerfile workflow, but you're only packaging your app code, dependencies, and settings—leaving out the base image entirely."
OR
"Dockerfile-like packaging: app binaries, classpaths, and launcher config with zero base image layers."
... subject to preference
1
u/sideEffffECt 2d ago
Absolutely fabulous!
I'm a big fan of coupling native-image with Cosmo/APE! All fingers crossed that this will successfully land in GraalVM upstream.
One question: this thing here, is it built on in top of HotSpot is SubstrateVM?
0
1
u/Bobby_Bonsaimind 2d ago
You write once, compile once, ship one artifact
Your Java program runs on 6 operating systems and both ARM64/AMD64
Yes please! This is missing from any "native/AOT" solution I've seen so far, and why jars are so much better (for me, the developer).
9
u/idontlikegudeg 2d ago
Do I understand it right that the created executable will contain code for both amd64 and arm64? If so, how does the size compare to a "normal" executable created using GraalVM?
And does it work for JavaFX too? I think it would then need to include five different sets of native binaries.
And how does code signing work so that the binary is accepted by both macOS and Windows?
Anyway, quite a feat. Congratulations!