Custom OpenJDK 9 Builds on Ubuntu 16.04
If, for some reason, you need to build OpenJDK 9 yourself, here is how to do it on Ubuntu 16.04.
All commands below are executed in this order on a freshly launched (LXD) Ubuntu 16.04 image.
First, we need mercurial (hg).
$ sudo apt-get update $ sudo apt-get install mercurial
Now, lets clone the JDK 9 repo from the OpenJDK update releases project.
$ hg clone http://hg.openjdk.java.net/jdk-updates/jdk9u
This ends very quick because this repo is like a super/meta repo, now we need to clone the actual source code. This takes around 10mins.
$ cd jdk9u $ bash ./get_source.sh
Hint: If you are inside LXD container, last command (and actually
common/bin/hgforest.sh which it calls) fails. You can set
HGFOREST_REDIRECT environment variable to a file (e.g.
export HGFOREST_REDIRECT=get_source.log) before running this, so it outputs log to this file rather than
/dev/stdout which fails inside the LXD container.
In order to build the JDK 9, you need three things:
- The native compiler collection (e.g. gcc) and build tools (make etc.)
- The previous release of JDK (so 8). The reason for this is parts of OpenJDK is written in Java, so you need a Java Compiler. This is called Boot JDK.
- External dependencies, tools and libraries etc.
Lets install the gcc compiler collection and OpenJDK 8.
$ sudo apt-get install build-essential openjdk-8-jdk
This is like 100MB download.
Now the required libraries and tools (FreeType2, CUPS, X11, ALSA, libffi, libelf, unzip, zip):
$ sudo apt-get install libfreetype6-dev libcups2-dev libx11-dev libxext-dev libxrender-dev libxtst-dev libxt-dev libasound2-dev libffi-dev libelf-dev unzip zip
Note: You also need llvm to compile zeroshark variant. However, I think it requires llvm 3.4 which is not available in default Ubuntu repos anymore. Unfortunately it is not very straightforward to build zeroshark variant. Also, Shark compiler (so I guess zeroshark variant also) will probably be removed from OpenJDK in the future.
There are some other dependencies but they are bundled with OpenJDK sources (such as libjpeg under
Now we are ready to build. As usual, we first run the configure script, it creates the build config files, then we issue make. make help gives a summary of make targets, some of them are:
make [default] # Compile all modules in langtools, hotspot, jdk # jaxws, jaxp and corba, and create a runnable # "exploded" image make images # Create complete jdk and jre images (alias # for product-images) make clean # Remove all files generated by make, but not # those generated by configure make dist-clean # Remove all files, including configuration
Now lets run configure.
Hint: If you will do such builds many time, you can install
ccache package and use
--enable-cache every time you run configure. This will speed up the builds.
$ bash configure
This should end without any error. If you see any error, either you did something wrong or I wrote something wrong in the above steps.
Lets look at the last lines of the configure output:
checking JVM features for JVM variant ‘server’… all-gcs aot cds compiler1 compiler2 fprof graal jni-check jvmci jvmti management nmt services vm-structs configure: creating /home/ubuntu/jdk9u/build/linux-x86_64-normal-server-release/configure-support/config.status config.status: creating /home/ubuntu/jdk9u/build/linux-x86_64-normal-server-release/spec.gmk config.status: creating /home/ubuntu/jdk9u/build/linux-x86_64-normal-server-release/bootcycle-spec.gmk config.status: creating /home/ubuntu/jdk9u/build/linux-x86_64-normal-server-release/buildjdk-spec.gmk config.status: creating /home/ubuntu/jdk9u/build/linux-x86_64-normal-server-release/compare.sh config.status: creating /home/ubuntu/jdk9u/build/linux-x86_64-normal-server-release/Makefile ==================================================== A new configuration has been successfully created in /home/ubuntu/jdk9u/build/linux-x86_64-normal-server-release using default settings. Configuration summary: * Debug level: release * HS debug level: product * JDK variant: normal * JVM variants: server * OpenJDK target: OS: linux, CPU architecture: x86, address length: 64 * Version string: 9.0.1-internal+0-adhoc.ubuntu.jdk9u (9.0.1-internal) Tools summary: * Boot JDK: openjdk version "1.8.0_151" OpenJDK Runtime Environment (build 1.8.0_151–8u151-b12–0ubuntu0.16.04.2-b12) OpenJDK 64-Bit Server VM (build 25.151-b12, mixed mode) (at /usr/lib/jvm/java-8-openjdk-amd64) * Toolchain: gcc (GNU Compiler Collection) * C Compiler: Version 5.4.0 (at /usr/bin/gcc) * C++ Compiler: Version 5.4.0 (at /usr/bin/g++) Build performance summary: * Cores to use: 8 * Memory limit: 31933 MB
Starting from the bottom:
- Build performance summary will be different for you, this shows it will use 8 cores and maximum 32GB memory on my computer (which is what the computer has).
- Tools summary shows it will use OpenJDK 8 as Boot JDK, and gcc compiler collection version 5.4.0 to build the OpenJDK 9.
- Configuration summary shows we are building a release version, normal JDK variant, server JVM variant, for linux x86 64-bit.
The first line in the output above is important, it shows:
checking JVM features for JVM variant ‘server’… all-gcs aot cds compiler1 compiler2 fprof graal jni-check jvmci jvmti management nmt services vm-structs
So the “server” variant of JVM to be built will include these features. It is what the variant “server” contains by default. Looking at generated
build/linux-x86_64-normal-server-release/spec.gmk file we can see:
## Which JVM variants to build (space-separated list) JVM_VARIANTS := server JVM_VARIANT_MAIN := server ## Lists of features per variant. Only relevant for the variants listed in ## JVM_VARIANTS. JVM_FEATURES_server := all-gcs aot cds compiler1 compiler2 fprof graal jni-check jvmci jvmti management nmt services vm-structs JVM_FEATURES_client := all-gcs cds compiler1 fprof jni-check jvmci jvmti management nmt services vm-structs JVM_FEATURES_core := all-gcs cds fprof jni-check jvmti management nmt services vm-structs JVM_FEATURES_minimal := compiler1 minimal JVM_FEATURES_zero := all-gcs cds fprof jni-check jvmti management nmt services vm-structs zero JVM_FEATURES_zeroshark := all-gcs cds fprof jni-check jvmti management nmt services shark vm-structs zero JVM_FEATURES_custom := ## Used for make-time verifications VALID_JVM_FEATURES := compiler1 compiler2 zero shark minimal dtrace jvmti jvmci graal fprof vm-structs jni-check services management all-gcs nmt cds static-build link-time-opt aot VALID_JVM_VARIANTS := server client minimal core zero zeroshark custom
So possible variants are: server, client, minimal, core, zero, zeroshark and custom. What features they contain is also specified here. As you guess, normally, everybody uses either server or client variant depending on the computer.
Note: Actually you cannot build the client variant easily, because the client variant is not supported in 64-bit targets anymore. So, if you try to build, you will get errors. More info and a possible workaround is here.
You can check which JVM you have:
$ java -version openjdk version "1.8.0_151" OpenJDK Runtime Environment (build 1.8.0_151–8u151-b12–0ubuntu0.16.04.2-b12) OpenJDK 64-Bit Server VM (build 25.151-b12, mixed mode)
So the OpenJDK 8 I have installed is a server variant in mixed mode (interpret + JIT compile).
The meaning of other variants are:
- minimal: a minimal build with compiler1
- core: it seems like intepreter only variant with some features
- zero: Zero assembly code, no JIT no AOT interpreter
- zeroshark: Zero assembly code but with zero-assembly Shark JIT compiler
- custom: build with no default features, you can select individual features
The features roughly mean:
- all-gcs: all garbage collectors otherwise only Serial GC is available
- aot: Ahead-Of-Time (AOT) compilation support
- cds: enables Class Data Sharing with -Xshare option
- compiler 1: JIT Compiler 1
- compiler 2: JIT Compiler 2 (used only in server variant)
- dtrace: enables dtrace support
- fprof: enables Flat Profiler, to support the JVM -Xprof option
- graal: exposes JVM functionality as API
- jni-check: enables additional JNI checks support with -Xcheck:jni option
- jvmci: JVM Compiler Interface (used by dynamic compilers like graal)
- jvmti: JVM Tool Interface
- link-time-opt: link time optimizations
- management: enables Java Management features
- minimal: it seems like only setting the VM Type to Minimal
- nmt: native memory tracking
- services: enables more serviceability features, more info here
- shark: LLVM based JIT Compiler for zero
- static-build: makes a static build as the name suggests :)
- vm-structs: used by HotSpot Serviceability Agent (SA), more info here
- zero: Zero-Assembler port of JDK
Now lets build the server variant.
This took a little longer than 4 minutes (on Intel Xeon E3 1245 v5 4-cores at 3.50 Ghz, 32GB memory, NVMe SSD).
build/linux-x86_64-normal-server-release/images we find the jdk and jre folders.
$ ./build/linux-x86_64-normal-server-release/jdk/bin/java -version openjdk version "9.0.1-internal" OpenJDK Runtime Environment (build 9.0.1-internal+0-adhoc.ubuntu.jdk9u) OpenJDK 64-Bit Server VM (build 9.0.1-internal+0-adhoc.ubuntu.jdk9u, mixed mode)
Everything is as expected, this is a server VM in mixed mode.
Now lets build the zero variant.
$ make dist-clean $ bash configure --with-jvm-variants=zero $ make
This took ~13 minutes.
$ ./build/linux-x86_64-normal-zero-release/jdk/bin/java --version openjdk 9.0.1-internal OpenJDK Runtime Environment (build 9.0.1-internal+0-adhoc.ubuntu.jdk9u) OpenJDK 64-Bit Zero VM (build 9.0.1-internal+0-adhoc.ubuntu.jdk9u, interpreted mode)
As expected, this is a pure interpreted mode JVM.
If you are very careful, you may see dtrace feature is not included in above builds. The reason is its configuration is set auto as default, meaning if the dependencies are met, then it is built into. However, we do not have the dependency so it is not built. We need:
$ sudo apt-get install systemtap-sdt-dev
Now lets run configure again.
$ make dist-clean $ bash configure
Looking at the same line in configure output:
checking JVM features for JVM variant 'server'... all-gcs aot cds compiler1 compiler2 dtrace fprof graal jni-check jvmci jvmti management nmt services vm-structs
Now dtrace feature is included as well.
As the last example, we can try the minimum possible build.
$ make dist-clean $ bash configure --with-jvm-variants=custom --enable-dtrace=no --with-jvm-features=minimal
Instead of using minimal variant, I choose custom variant and then include the minimal feature, because minimal variant also includes (JIT) compiler1 which I do not want. As far as I understand enabling the minimal feature does nothing other than defining the VM Type as Minimal (not Server, Client, Zero or Shark) to be shown in the version output. I also disabled dtrace support.
Looking at the configure output:
checking JVM features for JVM variant 'custom'... minimal
Includes only the minimal feature. Lets build it:
Lets see the version:
$ ./build/linux-x86_64-normal-custom-release/jdk/bin/java -version openjdk version "9.0.1-internal" OpenJDK Runtime Environment (build 9.0.1-internal+0-adhoc.ubuntu.jdk9u) OpenJDK 64-Bit Minimal VM (build 9.0.1-internal+0-adhoc.ubuntu.jdk9u, interpreted mode)
It is reported as Minimal VM and interpreted mode only.
Lets check some features:
$ ./build/linux-x86_64-normal-custom-release/jdk/bin/java -javaagent:a -version Instrumentation agents are not supported in this VM Error: Could not create the Java Virtual Machine. Error: A fatal exception has occurred. Program will exit. $ ./build/linux-x86_64-normal-custom-release/images/jdk/bin/java -Xprof -version Flat profiling is not supported in this VM. Error: Could not create the Java Virtual Machine. Error: A fatal exception has occurred. Program will exit.
As you see, because -javaagent and -Xprof options depend on the features that we did not include in this build, they are reported as being not supported.
As a last note, you may wonder how -client and -server options work and it is actually pretty simple. You can see there is a file called jvm.cfg in the lib folder for JDK. This file contains the configuration about which variants are supported. For example, for the openjdk-8-jdk on Ubuntu, the file contains this:
/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/jvm.cfg -server KNOWN -client IGNORE -zero KNOWN -dcevm KNOWN
It means, it supports -server, -zero and -dcevm variants and -client is recognized but ignored and default (the first one, so -server) is used. We can see this also with:
$ java -help ... -server to select the "server" VM -zero to select the "zero" VM -dcevm to select the "dcevm" VM ...
However, if you run:
$ java -zero Error: missing `zero' JVM at `/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/zero/libjvm.so'. Please install or use the JRE or JDK that contains these missing components.
you get an error. This also gives hint at how different JVMs are supported in single installation. There is a folder with the same name (zero) and
libjvm.so under that folder is used. Because I only have the server folder, only
-server works. I did not know this before, so if we search the Ubuntu repo:
$ apt-cache search jdk | grep zero openjdk-8-jre-zero - Alternative JVM for OpenJDK, using Zero/Shark
we see there is also zero variant available. If you install this, you can use
-zero option as well.
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.