Getting started with GraalVM development
Introduction
The aim of this tutorial is to guide you through the process of setting up your working environment for editing, building, and testing GraalVM.
Prerequisites
This tutorial assumes that you will be working on Linux and you will be using IntelliJ IDEA as your IDE.
Bootstrapping the development environment
In order to work with GraalVM's source code you will need mx
. To get
a copy of it run:
git clone https://github.com/graalvm/mx.git
Don't forget to include the cloned repository in your PATH
environment
variable in order to be able to execute mx
without specifying its
absolute or relative path:
export PATH=$PATH:$PWD/mx
As expected you will also need to clone the GraalVM repository itself:
git clone https://github.com/oracle/graal.git
Now that you have both mx
and the GraalVM repository cloned locally,
you can start running mx
commands that will help you complete the
setup.
In order to build GraalVM you will also need to get a bootstrap JDK. To get a supported version you need to run:
mx fetch-jdk
This will prompt you to choose which supported JDK version you would like to use as the bootstrap JDK for your build, e.g.:
[1]* labsjdk-ce-11 | ce-11.0.15+2-jvmci-22.1-b01
[2] labsjdk-ce-11-debug | ce-11.0.15+2-jvmci-22.1-b01
[3] labsjdk-ce-17 | ce-17.0.3+2-jvmci-22.1-b01
[4] labsjdk-ce-17-debug | ce-17.0.3+2-jvmci-22.1-b01
[5] Other version
Select JDK>
By default mx
will install the fetched JDK under ~/.mx/jdks
, if you
want to install it in a different location you may use the --to
or
--alias
flags:
--to <dir> location where JDK will be installed. Specify <system>
to use the system default location. (default:
~/.mx/jdks)
--alias <path> name under which the extracted JDK should be made
available (e.g. via a symlink). A relative path will
be resolved against the value of the --to option.
Note, that mx
will only fetch and install the JDK. It will not
automatically set it as the current JDK. To do so, as prompted by mx
,
you will need to run the following to set JAVA_HOME
in your shell:
export JAVA_HOME=~/.mx/jdks/labsjdk-ce-11-jvmci-22.1-b01
Now that JAVA_HOME
is set we may run mx intellijinit
to create the
necessary files for IntelliJ IDEA to understand the project structure
and resolve dependencies. mx intellijinit
, however, may not be run
from the root directory of the source code, so you will need to define a
primary suit path for it to work, e.g.:
mx --primary-suite-path substratevm intellijinit
In general, most mx
commands will require you to set the primary suite
path. So depending on which part of GraalVM you are working on you will
need to set the primary suite path accordingly. For native-image work
you will need to set it to substratevm
, for compiler to compiler
,
for truffle to truffle
, and so forth.
Building GraalVM
To build the full GraalVM CE you need to run:
mx --primary-suite=vm --env=ce build
But it's highly unlikely you would need to build all the components that
come with it, unless you want to release your build as a GraalVM
distribution. For development and testing purposes you would probably
need to build only a few of it's components. To see which components a
command is going to build you can use graalvm-show
, e.g.:
mx --primary-suite=vm --env=ce graalvm-show
Which will print something like the following:
GraalVM distribution: GRAALVM_B00B87AA07_JAVA11
Version: 22.1.0-dev
Config name: None
Components:
- Component installer ('gu', /installer)
- LLVM.org toolchain ('llp', /llvm)
- Polyglot Launcher ('poly', /polyglot)
- Native Image JUnit ('nju', /junit)
- LibGraal ('lg', /False)
- Native Image licence files ('nil', /svm)
- GraalVM license files ('gvm', /.)
- Truffle Macro ('tflm', /truffle)
- Native Image Configure Tool ('nic', /svm)
- Truffle ('tfl', /truffle)
- Truffle NFI LIBFFI ('nfi-libffi', /nfi-libffi)
- Native Image ('ni', /svm)
- SubstrateVM LLVM ('svml', /svm)
- Polyglot Native API ('polynative', /polyglot)
- SVM Truffle NFI Support ('svmnfi', /nfi)
- Native Image JUnit with image-builder on classpath ('njucp', /junitcp)
- Graal SDK ('sdk', /graalvm)
- SubstrateVM ('svm', /svm)
- ICU4J ('icu4j', /truffle)
- Truffle NFI ('nfi', /nfi)
- GraalVM compiler ('cmp', /graal)
- PolyBench Instruments ('pbi', /pbi)
- Disassembler ('dis', /graal)
- Polyglot Library ('libpoly', /polyglot)
Launchers:
- gu (bash)
- polyglot (bash)
- native-image-configure (bash)
- native-image (bash)
Libraries:
- libjvmcicompiler.so (skipped)
- libnative-image-agent.so (skipped)
- libnative-image-diagnostics-agent.so (skipped)
- libpolyglot.so (skipped)
Installables:
- NATIVE_IMAGE_INSTALLABLE_SLIBNATIVE-IMAGE-AGENT.SO_SLIBNATIVE-IMAGE-DIAGNOSTICS-AGENT.SO_JAVA11
- LLVM_TOOLCHAIN_INSTALLABLE_JAVA11
No standalone
So for instance in order to build a minimal substratevm (i.e., be able to generate native images) you can run:
mx --primary-suite-path substratevm --components='Native Image',nju build
which will build the following components:
$ mx --primary-suite-path substratevm --components='Native Image',nju graalvm-show
GraalVM distribution: GRAALVM_7B5A7CFCCC_JAVA17
Version: 22.1.0-dev
Config name: None
Components:
- Native Image ('ni', /svm)
- Native Image JUnit ('nju', /junit)
- SubstrateVM ('svm', /svm)
- Native Image licence files ('nil', /svm)
- GraalVM compiler ('cmp', /graal)
- Truffle Macro ('tflm', /truffle)
- SVM Truffle NFI Support ('svmnfi', /nfi)
- Truffle ('tfl', /truffle)
- Truffle NFI ('nfi', /nfi)
- Graal SDK ('sdk', /graalvm)
Launchers:
- native-image (bash)
Libraries:
- libnative-image-agent.so (skipped)
- libnative-image-diagnostics-agent.so (skipped)
No installable
No standalone
The resulting build will be accessible under
./sdk/latest_graalvm_home
, so to generate a native image one can run:
./sdk/latest_graalvm_home/bin/native-image Main
Now that you have bootstrapped your development environment and have successfully built GraalVM (or at least its substratevm) you are ready to open IntelliJ IDEA and start coding.
Testing your code
Once you are done coding, you will need to check whether your code breaks any of the existing tests or any of the ones you added in order to test your new code.
The easiest way to run the tests that come with GraalVM is by using the
gate
command. E.g.:
mx --primary-suite-path substratevm gate
Note that in order for gate
to test your build (with the components
you are interested in) instead of the default build, you will need to
pass to mx
the same parameters that you passed to it while
building. E.g.:
mx --primary-suite-path substratevm --components='Native Image',nju gate
Style checks
Once you are done testing your code, you will need to check your code conforms to GraalVM's coding style. GraalVM is using two approaches to ensure the code is properly formatted. First there is checkstyle, which checks the code for style errors, and then there is eclipseformat which uses Eclipse to format the code.
checkstyle
To run checkstyle on your local workspace you need to run:
mx --primary-suite-path substratevm checkstyle
eclipseformat
To run checkstyle on your local workspace you need to run:
mx --primary-suite-path substratevm eclipseformat -e ~/.mx/eclipse/eclipse
eclipseformat
doesn't always work with the eclipse version provided by
the package manager of the system we are working on. As a result in some
cases you will need to download and install the right Eclipse version
and let mx
know about its location through the -e
parameter. E.g.:
mx --primary-suite-path substratevm eclipseformat -e ~/.mx/eclipse/eclipse
For more info about GraalVM please refer to the reference manual.