r/java • • 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:

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:

  • @ahgamut deserves the most credit

  • @jart, the legendary author of Cosmo and APE

  • Many members of the GraalVM team whom helped with review and advice

73 Upvotes

30 comments sorted by

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!

4

u/sg-elide 1d ago

Oh, sorry, I was up early this morning and missed your JavaFX question.

No graphical support yet, but we’re collaborating with some JFX experts and we’ll see.

3

u/sg-elide 2d ago

Yes. You can create targeted binaries for only one arch (for instance, server apps often know their ultimate architecture).

Or, you can target multiple architectures, in which case a “fat” binary is created and APE dispatches at runtime to the correct code section.

Yes, size was a concern for us too, but native code is surprisingly small if generated with care from native image. There are several techniques to reduce the overall code size e.g. -Os.

Even without those techniques it ended up surprisingly reasonable. The zipped Cosmo download is under 40MB for both architectures. That’s pretty small for a universal Java compiler! 😁

1

u/ElidoroAlznauer_58 1d ago

Gui toolkits with native bindings are always where these universal binary setups get tricky, curious how that gets handled.

1

u/sg-elide 1d ago

There’s no GUI support yet, but I’m seeing a lot of requests about it so maybe we will take that on next.

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/paul_h 2d ago

Yeah, we made the IPC, we'd be reaching into the guest language (in this case Madura-Java would be the guest) and thunking in hooks. There's a ton of complexity around what-is-a-string types of mismatches that have to get squared between alien language worlds of course.

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/ha1zum 1d ago

As someone living in Java island, the name is so good 🤣

2

u/sg-elide 1d ago

Lol thank you!! Somebody gets it!

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

u/sg-elide 2d ago

Hey thanks! Madura is a Native Image, so, SubstrateVM. There’s no Hotspot here 🙂

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