I have been coding in Java like forever and was always intrigued about JVM implementation. Having unsuccessfully tried several times in past to dive deeper, decided to adopt a different way this time. What prompted this exploration was some mysterious production issues that were not easy to resolve without diving deeper. So, here comes the 1st step of building the JVM locally and setting up the environment locally. Finally for the motivation part, the words from Sia’s Cheap Thrills song are spot on “But I don’t need no money. As long as I can feel the beat“
For this series, I will use Java 17 as base of all exploration on macOS, unless specified. Join along the journey. In this post we shall build JDK locally and configure code base in CLion to explore further.
Setup
Following things are needed for build,
- Xcode – (version 16.2)
- autoconf
- sdkman – for managing Java versions, if you install more than one
- Java – going to use Java 17 for the purpose of this exploration, as we do need java to build java
❯ sdk use java 17.0.15-zulu
Clone the repository
The main-line development repository is at https://github.com/openjdk/jdk. However, once after release projects are maintained per release. You can find more details at JDK Update Releases.
For Java 17, we will clone https://github.com/openjdk/jdk17u
NOTE: The dev repo for JDK17 is hosted at jdk17u-dev and changes are merged to main jdk17-u repo
git clone https://github.com/openjdk/jdk17u
Building the code
Move to the cloned folder and run following commands
bash configure
make images
Once the steps are completed, we have a working JDK build and test it via command
./build/*/images/jdk/bin/java -version
Note: At this step, I ran into build issues using Xcode 16.4. The error is due to more strict checking and error message is like below. If such a issue happens follow instructions here
jdk17u/src/hotspot/os/posix/signals_posix.cpp:1673:20: error: cast from 'void (*)(int, siginfo_t *, ucontext_t *)' (aka 'void (*)(int, __siginfo *, __darwin_ucontext *)') to 'void (*)(int)' converts to incompatible function type [-Werror,-Wcast-function-type-mismatch] 1673 | act.sa_handler = (void (*)(int)) SR_handler; | ^~~~~~~~~~~~~~~~~~~~~~~~~~ 1 error generated.
Now that we have successfully built JDK, it’s time to configure the codebase in CLion for exploration.
Configuring CLion
Execute the following commands to create compilation database
make compile-commands
This will generate compile_commands.json in ./build/macosx-aarch64-server-release/ folder
Open the compile_commands.json in CLion (and open as project)
File -> Open -> compile_commands.json
We have our code configured in CLion ready to be explored. The code looks something like this

We did not configure the project for debugging in this post, as our focus is solely on code exploration and making minor updates. The IntelliJ blog has excellent steps for achieving debugging within the IDE.
Before we wrap up this post, let’s make a small, custom change to the JDK’s version string as a tangible first step.
Customizing the Version
Updating the Version String
As a simple change, I aimed to modify the version string to a custom format. While it seemed straightforward initially, it took more time than expected. During this process, I found an interesting conversation about JDK Versions. Although these settings can often be changed with build parameters (as mentioned in the JDK build documentation), I wanted to demonstrate a direct source code modification without relying on additional command-line parameters.
Updating the Patch number
The version can be modified in file make/conf/version-numbers.conf. For simplicity, only incremented patch as 1

Update Product name
I updated the product name to OpenJDK-Jarvis in make/conf/branding.conf

Update name format
I updated the name format to remove the username and add a hardcoded string in make/autoconf/jdk-version.m4

After following usual build procedure of `bash configure’make clean;make images`, we get a customized version string

References
And the final feelings
