This example demonstrates how to compile a Java and Kotlin application ahead-of-time into a native executable, and illustrates the advantages.
1. Download or clone the repository and navigate into the
java-kotlin-aot
directory:
Note: You can use any JDK for building the application. However,
javac
from GraalVM in the build script is used to simplify
the prerequisites so another JDK does not need to be installed.
2. Download GraalVM,
unzip the archive, export the GraalVM home directory as the
$JAVA_HOME
and add $JAVA_HOME/bin
to the
PATH
environment variable: On Linux:
export JAVA_HOME=/home/${current_user}/path/to/graalvm
export PATH=$JAVA_HOME/bin:$PATH
On macOS:
export JAVA_HOME=/Users/${current_user}/path/to/graalvm/Contents/Home
export PATH=$JAVA_HOME/bin:$PATH
On Windows:
setx /M JAVA_HOME "C:\Progra~1\Java\<graalvm>"
setx /M PATH "C:\Progra~1\Java\<graalvm>\bin;%PATH%"
Note that your paths are likely to be different depending on the download location.
3. Install Native Image by running.
gu install native-image
4. Then execute:
./build.sh
Have a look at the build.sh
script which creates a
native executable from a Java class. The native-image
utility compiles the application ahead-of-time for faster startup and
lower general overhead at runtime.
$JAVA_HOME/bin/native-image --no-fallback -cp ./target/mixed-code-hello-world-1.0-SNAPSHOT-jar-with-dependencies.jar -H:Name=helloworld -H:Class=hello.JavaHello -H:+ReportUnsupportedElementsAtRuntime
It takes a few parameters: the classpath, the main class of the
application with -H:Class=...
, and the name of the
resulting executable with -H:Name=...
.
After executing the native-image
command, check the
directory. It should have produced the executable file,
helloworld
.
To run the application, you need to execute the JAR file in the
target
directory. You can run it as a normal Java
application using java
:
java -cp ./target/mixed-code-hello-world-1.0-SNAPSHOT-jar-with-dependencies.jar hello.JavaHello
Or, since we have a native executable prepared, you can run that directly.
./helloworld
The run.sh
file executes both, and times them with the
time
utility. An output close to the following should be
produced:
→ ./run.sh
+ java -cp ./target/mixed-code-hello-world-1.0-SNAPSHOT-jar-with-dependencies.jar hello.JavaHello
Hello from Kotlin!
Hello from Java!
real 0m0.589s
user 0m0.155s
sys 0m0.072s
+ ./helloworld
Hello from Kotlin!
Hello from Java!
real 0m0.053s
user 0m0.006s
sys 0m0.006s
The performance gain of the native version is largely due to the faster startup.
This sample application is taken from the JetBrains Kotlin-examples repository. It is distributed under the Apache License 2.0.