Build your own OpenJDK on macOS

Following the recent kerfuffle around the security manager deprecation, I was curious to see if a codebase I’m working on would also suffer. But how could I find out? There are no early access builds of Java 17 yet with the latest changes for this JEP. Maybe… I should set out and try to build it myself? But that’s sure going to be a lot of work… Or is it?

Well, the process is well documented, so I wanted to give it a go. To spoil the mystery a little bit, the documentation is so good, that this blog is more of a summary.

Prerequisites

To build Java 17 on a Mac, you need:

  • a Java Development Kit, at least Java 16
  • Apple Xcode - the documentation says to use at least Xcode 10, but I’ve used 12.5, the latest at this moment. The documentation used to state that installing the Xcode Command Line Utilities would be enough. Now that the New macOS Rendering Pipeline (JEP 382) is integrated, it seems you need Xcode itself.

If you also want to run the test suite, you need a few more things:

And, of course, you need the OpenJDK source tree: git clone https://github.com/openjdk/jdk.git.

If you want to experiment with features that aren’t done yet, you may want to switch to a different branch, or even add another Git remote that contains the feature.

Building

The first step is configuring the build:

bash configure \
    --with-jtreg=/Users/maarten/stuff/jtreg \
    --with-gtest=/Users/maarten/stuff/googletest

This will perform a bunch of sanity checks to see if you have all the necessary tools. In most cases, it will give you clear instructions if you lack something.

If all goes well, the script will summarise the configuration for your build, the tools it will use, and the hardware resource that the build will use:

Configuration summary:
* Name:           macosx-x86_64-server-release
* Debug level:    release
* HS debug level: product
* JVM variants:   server
* JVM features:   server: 'cds compiler1 compiler2 dtrace epsilongc g1gc jfr jni-check jvmci jvmti management nmt parallelgc serialgc services shenandoahgc vm-structs zgc' 
* OpenJDK target: OS: macosx, CPU architecture: x86, address length: 64
* Version string: 17-internal+0-adhoc.maarten.openjdk (17-internal)

Tools summary:
* Boot JDK:       openjdk version "16.0.1" 2021-04-20 OpenJDK Runtime Environment AdoptOpenJDK-16.0.1+9 (build 16.0.1+9) OpenJDK 64-Bit Server VM AdoptOpenJDK-16.0.1+9 (build 16.0.1+9, mixed mode, sharing) (at /Library/Java/JavaVirtualMachines/adoptopenjdk-16.jdk/Contents/Home)
* Toolchain:      clang (clang/LLVM from Xcode 12.5)
* C Compiler:     Version 12.0.5 (at /usr/bin/clang)
* C++ Compiler:   Version 12.0.5 (at /usr/bin/clang++)

Build performance summary:
* Cores to use:   12
* Memory limit:   16384 MB

Now on to the next step: getting that fresh Java Development Kit! After issuing make images, grab yourself a beverage of choice. On my 2018 Macbook with an Intel Core i7 CPU and 16 GB of RAM, the process took a little over 30 minutes. Of course, your mileage may vary…

When that is done, you can do a sanity check by issuing ./build/*/images/jdk/bin/java -version. If all went well, you should see something like this:

openjdk version "17-internal" 2021-09-14
OpenJDK Runtime Environment (build 17-internal+0-adhoc.maarten.openjdk)
OpenJDK 64-Bit Server VM (build 17-internal+0-adhoc.maarten.openjdk, mixed mode, sharing)

Verifying your build

This is all fun and giggles, but will this custom Java build work correctly? There’s only one way to find out… run the extensive test suite that comes with it! It’s just as easy as the previous steps: run make run-test-tier1.

Again, if all went well, you should see a report like this:

==============================
Test summary
==============================
   TEST                                              TOTAL  PASS  FAIL ERROR   
   jtreg:test/hotspot/jtreg:tier1                     1702  1702     0     0   
   jtreg:test/jdk:tier1                               2027  2027     0     0   
   jtreg:test/langtools:tier1                         4172  4172     0     0   
   jtreg:test/jaxp:tier1                                 0     0     0     0   
   jtreg:test/lib-test:tier1                             0     0     0     0   
==============================
TEST SUCCESS

Finished building target 'run-test-tier1' in configuration 'macosx-x86_64-server-release'

Running this test suite probably takes longer than building the JDK itself. On my machine, it took almost three times as long!

Troubleshooting

If you see

XCode tool 'metal' neither found in path nor with xcrun

You’re most likely building with either a very old Xcode, or the Xcode Command Line Utilities.

Wrapping up

Back to the question that triggered this interesting journey. I was able to build a JDK that contained the work-in-progress for JEP 411. Luckily, the codebase wasn’t affected, it turned out we even didn’t use the Security Manager. That means I could’ve saved myself a couple of hours… but hey, I’ve learned a few new things, and that was fun!