# Using jlink to cross-compile minimal JREs

DevFeed: [Using jlink to cross-compile minimal JREs](<https://devfeed.tech/articles/using-jlink-to-cross-compile-minimal-jres-20981.md>)

Original publisher: [Read original article](<https://jakewharton.com/using-jlink-to-cross-compile-minimal-jres/>)

Published: 2023-01-16T00:00:00Z

Content type: tutorial

Language: en

Sources: [Jake Wharton](<https://devfeed.tech/sources/jake-wharton.md>)

Topics: [Java](<https://devfeed.tech/topics/java.md>), [Arm](<https://devfeed.tech/topics/arm.md>), [Linux](<https://devfeed.tech/topics/linux.md>), [Containers](<https://devfeed.tech/topics/containers.md>), [compose-for-desktop](<https://devfeed.tech/topics/compose-for-desktop.md>), [ssh](<https://devfeed.tech/topics/ssh.md>)

Tags: [arm](<https://devfeed.tech/tags/arm.md>), [compose](<https://devfeed.tech/tags/compose.md>), [containers](<https://devfeed.tech/tags/containers.md>), [java](<https://devfeed.tech/tags/java.md>), [jdk](<https://devfeed.tech/tags/jdk.md>), [linux](<https://devfeed.tech/tags/linux.md>), [ssh](<https://devfeed.tech/tags/ssh.md>)

## AI overview

This tutorial demonstrates using jlink and jdeps to create minimal Java runtimes tailored to an application. It shows how to reduce a simple runtime from 136 MiB to 28 MiB and use platform-specific JDKs to cross-compile runtimes for Linux x64 and other targets.

## Source excerpt

jlink is a JDK tool to create bespoke, minimal JREs for your applications. Let's try it with a "Hello, world!" program: class Main { public static void main(String... args) { System.out.println("Hello, world!"); } } My laptop is an M1 Mac and I have downloaded the Azul Zulu JDK 19 build for it. With the JDK I can both compile Java and then run the resulting program. $ mkdir out $ zulu19.30.11-ca-jdk19.0.1-macosx_aarch64/bin/javac -d out in/Main.java $ zulu19.30.11-ca-jdk19.0.1-macosx_aarch64/bin/java -cp out Main Hello, world! Azul Zulu also provides a JRE that I can use to run compiled programs. $ zulu19.30.11-ca-jre19.0.1-macosx_aarch64/bin/java -cp out Main Hello, world! Note the slight change in folder name ("jdk" -> "jre"). If we were shipping this to end-users it would be an easy win for binary size. $ du -hs zulu* 329M zulu19.30.11-ca-jdk19.0.1-macosx_aarch64 136M zulu19.30.11-ca-jre19.0.1-macosx_aarch64 But 136MiB just for "Hello, world"? Don't tell Reddit or Hacker News! Thankfully, jlink is here to help us build a minimal JRE with only what we need. Given our program, a sibling tool, jdeps, lists the Java modules which are required. $ zulu19.30.11-ca-jdk19.0.1-macosx_aarch64/bin/jdeps \ --print-module-deps \ out/Main.class java.base Our program is so simple that it only needs the "base" module. Now with jlink we can produce a minimal JRE. $ zulu19.30.11-ca-jdk19.0.1-macosx_aarch64/bin/jlink \ --compress 2 \ --strip-debug \ --no-header-files \ --no-man-pages \ --output zulu-hello-jre \ --add-modules java.base $ du -hs zulu* 28M zulu-hello-jre 329M zulu19.30.11-ca-jdk19.0.1-macosx_aarch64 136M zulu19.30.11-ca-jre19.0.1-macosx_aarch64 28MiB won't win any language wars, but it's a massive 80% savings over the full JRE. $ zulu-hello-jre/bin/java -cp out Main Hello, world! We can ship it to our client and call it a day, right? $ tar -czf hello.tgz zulu-hello-jre out $ scp hello.tgz jw@server: hello.tgz 100% 14MB 2.0MB/s 00:07 $ ssh jw@server "tar xzf hello.tgz &&