Installer GraalVM sur Debian et Ubuntu

On a vu dans un billet précédent comment installer Java sur Debian ou Ubuntu en utilisant le plus possible les paquets fournis par le système, et ce sans avoir recours à d’autres outils ou installeurs qui changent le PATH de notre système.

On souhaiterait faire de même avec GraalVM, malheureusement Oracle ne fournit pas de dépôt Debian ni Ubuntu pour GraalVM, et il semble qu’AdoptOpenJDK ou Azul ne le fasse pas non plus 🙁 Du moins pas pour l’instant.

1. Installer GraalVM

Les livrables de GraalVM se trouvent sur GitHub dans dépôt graalvm-ce-builds.

On va commencer par télécharger l’archive de GraalVM dans sa dernière version 21.0.0.2:

$ wget https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-21.0.0.2/graalvm-ce-java11-linux-amd64-21.0.0.2.tar.gz

Et on va extraire cette archive là où on installe les JDKs du système, à savoir dans /usr/lib/jvm:

$ sudo tar -xvf graalvm-ce-java11-linux-amd64-21.0.0.2.tar.gz -C /usr/lib/jvm

Ils seront ainsi accessibles par tous les utilisateurs du système.

 $ ls -l /usr/lib/jvm/
total 20
drwxr-xr-x 10 root root 4096 mars  20 11:14 graalvm-ce-java11-21.0.0.2
lrwxrwxrwx  1 root root   21 nov.  10 05:18 java-1.11.0-openjdk-amd64 -> java-11-openjdk-amd64
lrwxrwxrwx  1 root root   21 juil. 21  2020 java-1.13.0-openjdk-amd64 -> java-13-openjdk-amd64
drwxr-xr-x  9 root root 4096 févr. 10 17:54 java-11-openjdk-amd64
drwxr-xr-x  9 root root 4096 déc.  16 20:30 java-13-openjdk-amd64

2. Configurer GraalVM

Si on modifie notre variable d’environnement PATH:

$ export JAVA_HOME=/usr/lib/jvm/graalvm-ce-java11-21.0.0.2
$ export PATH=$JAVA_HOME/bin:$PATH

On utilise bien le binaire java fourni par GraalVM:

$ java -version
openjdk version "11.0.10" 2021-01-19
OpenJDK Runtime Environment GraalVM CE 21.0.0.2 (build 11.0.10+8-jvmci-21.0-b06)
OpenJDK 64-Bit Server VM GraalVM CE 21.0.0.2 (build 11.0.10+8-jvmci-21.0-b06, mixed mode, sharing)

Il en est de même des autres binaires javac, etc …

A ce stade GraalVM pour Java 11 est installé. Si vous n’aviez pas encore de JDK 11 installé, vous pouvez tout à fait utiliser cette installation de GraalVM comme JDK 11.

3. Installer native-image

Si l’on souhaite installer GraalVM, c’est en particulier pour pouvoir compiler du code Java en natif avec l’utilitaire native-image.

Cet utilitaire n’est pas fourni dans la distribution de GraalVM. On va donc l’installer, ce qui se fait avec l’utilitaire gu (GraalVM updater) qui lui fait partie de la distribution que l’on vient d’installer:

$ sudo env PATH=$PATH gu install native-image
Downloading: Component catalog from www.graalvm.org
Processing Component: Native Image
Downloading: Component native-image: Native Image  from github.com
Installing new component: Native Image (org.graalvm.native-image, version 21.0.0.2)

Vous noterez la façon de passer le PATH courant à sudo qui lui n’a pas GraalVM dans son PATH.

On dispose maintenant de la commande native-image:

$ native-image --help

GraalVM native-image building tool

This tool can be used to generate an image that contains ahead-of-time compiled Java code.

Usage: native-image [options] class [imagename] [options]
           (to build an image for a class)
   or  native-image [options] -jar jarfile [imagename] [options]
           (to build an image for a jar file)
where options include:
...

3.1 Installer les dépendances de native-image

native-image compile en code natif votre application écrite en Java et a besoin pour cela des dépendances suivantes:

$ sudo apt-get install build-essential libz-dev zlib1g-dev

4. Premier programme Java compilé en natif

On va prendre un exemple très simple de programme Java:

$ cat HelloWorld.java 
public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello World");
    }

Le compiler:

$ javac HelloWorld.java

Une fois compilé, on va pouvoir générer une version native de notre programme HelloWorld:

$ native-image HelloWorld HelloWorld.native

Cette dernière opération est très lente, 8 secondes sur ma machine (Core i7).

Voyons maintenant ce qu’on a généré:

$ file HelloWorld.native
HelloWorld.native: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=cee9a397347e78326db66a8bc9ab47186a17001d, for GNU/Linux 3.2.0, with debug_info, not stripped

On a bien un exécutable que l’on pourra lancer comme suit:

$ ./HelloWorld.native 
Hello World

Et qui se lance beaucoup plus vite que son homologue Java (0.24s):

$ java HelloWorld

5. Conclusion

On vient de voir comment installer simplement GraalVM, native-image ainsi que les dépendances nécessaires à son utilisation, et ce uniquement avec les commandes wget, sudo, tar et apt-get. Ensuite on a vu comment transformer un programme Java en code natif.

Nous verrons dans un prochain billet comment utiliser un plugin Maven pour automatiser la génération en code natif dans nos builds.