Skip to main content
Once you have a proper configuration, building the JDK is done using GNU Make. This page covers make targets, build control variables, and advanced compilation techniques.

Running Make

Basic Usage

# Build default target (same as 'make jdk')
make

# Build default target explicitly
make default
The default target builds a minimal set of compiled output (“exploded image”) for development and testing. It’s optimized for incremental development.

Testing the Build

# Test the newly built JDK
$BUILD/jdk/bin/java -version
The exploded image at $BUILD/jdk is immediately runnable.
Make sure to use the correct version of GNU Make (3.81+, recommended 4.0+). See GNU Make section in requirements.

Common Make Targets

Primary Targets

make jdk
Builds the exploded JDK image for development. Output in $BUILD/jdk.

Testing Targets

# Run tier 1 tests (basic smoke tests)
make test-tier1

# Run tier 2 tests
make test-tier2

# Run tier 3 tests
make test-tier3
Requires JTReg framework. Configure with --with-jtreg=/path/to/jtreg.

Utility Targets

# Build twice with newly built JDK (good for testing)
make bootcycle-images

# Remove all build results (keeps configuration)
make clean

# Remove everything including configuration
make dist-clean

# Show important make targets and variables
make help

Building Specific Modules

Module Targets

All JDK source code is organized into modules (e.g., java.base, jdk.jdwp.agent).
# Build a single module and its dependencies
make java.base
make jdk.jdwp.agent

# Build multiple modules
make jdk.crypto.cryptoki jdk.crypto.ec jdk.crypto.mscapi
Module dependencies are automatically built first.

Module Phases

Each module build is divided into phases:
PhaseDescription
gensrcGenerate source code to compile
gendataGenerate non-source code artifacts
copyCopy resource artifacts
javaCompile Java code
launchersCompile native executables
libsCompile native libraries

Phase-Specific Targets

# Build a specific phase (and dependencies)
make gensrc
make java
make libs

# Build a specific phase for a module
make java.base-gensrc
make java.base-java
make jdk.jdwp.agent-libs
# This builds only the gensrc phase for java.base
# and any prerequisite phases it depends on
make java.base-gensrc
This is useful for quickly iterating on generated source code.

Cleaning Build Results

Clean Targets

# Clean everything (keep configuration)
make clean

# Clean specific output directory
make clean-support
make clean-images

# Clean specific phase
make clean-gensrc
make clean-java
make clean-libs

# Clean specific module
make clean-java.base
make clean-jdk.compiler

# Clean module + phase
make clean-java.base-java
make clean-hotspot-libs

Complete Clean and Reconfigure

# Save current configuration
make print-configuration > current-config.txt

# Complete clean
make dist-clean

# Restore configuration and build
bash configure $(cat current-config.txt)
make images

Make Control Variables

Control variables should be used carefully. Incorrect use can lead to broken builds.

General Control Variables

# Use 8 parallel jobs
make JOBS=8 images

# Use 1 job (sequential build)
make JOBS=1
Do NOT use -j flag directly. Use JOBS=N instead.
# Show command lines
make LOG=cmdlines

# Info level logging
make LOG=info

# Debug level logging (very verbose)
make LOG=debug

# Trace level logging (extremely verbose)
make LOG=trace

# Combine log levels
make LOG=info,cmdlines
Build output is always saved to $BUILD/build.log (current) and build.log.old (previous).
# Build specific configuration
make CONF=linux-x64-server-release

# Build all matching configurations (substring)
make CONF=debug

# Build all configurations
make CONF=

# Build all except matching
make CONF=!debug

# Exact name match only
make CONF_NAME=linux-x64-server-release

Advanced Control Variables

# Build using specific spec.gmk
make SPEC=$BUILD/spec.gmk
This is what the build system uses internally.
# Auto-reconfigure if needed
make CONF_CHECK=auto

# Skip reconfiguration check (risky)
make CONF_CHECK=ignore
# Only recompile files in javax/crypto package
make java.base JDK_FILTER=javax/crypto

# Pattern matching
make java.base JDK_FILTER=java/util
This was historically used for performance but is less necessary in modern builds.
# Build twice with different options and compare
make COMPARE_BUILD=CONF=--enable-new-hotspot-feature:MAKE=hotspot
See make/InitSupport.gmk for details.

Fine-Grained Build Targets

Skipping Dependency Checks

This can lead to broken builds if used incorrectly!
For rapid iterative development, you can skip dependency checking by appending -only to targets:
# Only build java phase of jdk.jdwp.agent (no dependency check)
make jdk.jdwp.agent-java-only

# Only build libs phase
make hotspot-libs-only
Recommended pattern:
1

First build - with dependencies

make jdk.jdwp.agent
2

Subsequent builds - skip dependencies

make jdk.jdwp.agent-java-only
Executes in milliseconds vs. seconds.

Building the Right Target

For best performance, build only what you need:
NeedTargetOutput Location
Development & testingmake jdk$BUILD/jdk
Shipping/distributionmake images$BUILD/images/jdk
Documentationmake docs$BUILD/images/docs
Running testsmake test-image$BUILD/images/test

Build Performance Optimization

Performance Summary

At the end of a build with LOG=info, you get a build time summary:
make LOG=info images
Output:
## Build times summary:
Phase           Duration  Percentage
--------------------------------------  
javac           00:03:12      25.6%
hotspot         00:05:30      43.9%
images          00:00:45       6.0%
...
Total           00:12:32     100.0%

Build Performance Tips

  • Put source code on local SSD (not network share)
  • Put build output on local SSD
  • Put build tools (Boot JDK, toolchain) on local disk
Network shares can make builds extremely slow.
On Windows, virus checking can significantly slow down builds.
  • Disable virus checking software during builds
  • Or exclude the JDK source directory from on-the-fly checking
# Configure with ccache
bash configure --enable-ccache

# Build
make images
Can radically speed up native code recompilation.
# Configure with icecc
bash configure --enable-icecc

# Build using multiple machines
make images
Requires icecc network setup.
# Adjust cores and memory
bash configure --with-num-cores=16 --with-memory-size=32768

# Or control jobs at make time
make JOBS=16
Find the right balance for your system.
# For development (fastest)
make jdk

# For testing only hotspot changes
make hotspot

# Only when you need distribution images
make images

Analyzing Build Performance

# Build with trace logging and single job
make JOBS=1 LOG=trace

# Check build trace
cat $BUILD/build-trace-time.log
This shows exactly where build time is spent.

Incremental Builds

The build system tracks dependencies and rebuilds only what’s changed.

How Incremental Builds Work

# Initial build
make images

# Edit a Java file in java.base
vim src/java.base/share/classes/java/lang/String.java

# Rebuild - only affected parts rebuild
make images
Incremental builds are optimized for developer productivity. In most cases, only changed files and their dependents are recompiled.

When Incremental Builds May Fail

Sometimes complex interdependencies cause incorrect incremental builds. Solutions (in order of increasing time):
1

Update repository

git pull origin master
make images
2

Clean build results

make clean
make images
Removes build results but keeps configuration.
3

Complete clean

make print-configuration > current-config.txt
make dist-clean
bash configure $(cat current-config.txt)
make images
4

Re-clone repository

# Save local changes
git format-patch -o /tmp/patches origin/master

# Re-clone
cd ..
mv jdk jdk.old
git clone https://git.openjdk.org/jdk
cd jdk

# Reapply patches
git am /tmp/patches/*.patch

Testing Builds

Running Tests

# Tier 1 tests (basic smoke tests, ~5-10 minutes)
make test-tier1

# Tier 2 tests (more comprehensive, ~30 minutes)
make test-tier2

# Tier 3 tests (extensive, hours)
make test-tier3

Test Control Variables

These variables are used when running tests:
# Specify which tests to run
make test TEST="tier1"

# Control test parallelism
make test TEST=tier1 TEST_JOBS=8

# Pass options to test framework
make test TEST=tier1 TEST_OPTS="-verbose"

# Pass VM options
make test TEST=tier1 TEST_VM_OPTS="-Xmx2g"
For complete testing documentation, see the Testing the JDK guide.

Cross-Compilation Builds

When cross-compiling, the build process is more complex.

Build JDK

Cross-compilation requires a “Build JDK” (runs on build platform, not target platform).
# The build system creates a minimal Build JDK automatically
# Or provide a pre-built one for speed:
bash configure --openjdk-target=aarch64-linux-gnu \
               --with-build-jdk=/path/to/build-jdk
The Build JDK must exactly match current sources, or the build may break in subtle ways.

Cross-Compilation Example

# Configure for cross-compilation
bash configure \
  --openjdk-target=aarch64-linux-gnu \
  --with-sysroot=/path/to/aarch64-sysroot \
  --with-toolchain-path=/opt/cross/bin \
  --with-boot-jdk=/usr/lib/jvm/java-21-openjdk

# Build
make images

# Output is in build/linux-aarch64-server-release/images/jdk
# Copy to target system and test:
# ./bin/java -version

Specialized Build Modes

Bootcycle Build

Builds JDK twice - second time using the just-built JDK as Boot JDK.
make bootcycle-images
Good for testing that the JDK can build itself.

Comparison Builds

Automatically build two versions and compare them:
make COMPARE_BUILD=CONF=--enable-new-feature:MAKE=hotspot

# Compare two existing builds manually
$BUILD1/compare.sh -o $BUILD2

Reproducible Builds

# Set fixed source date before configure
export SOURCE_DATE_EPOCH=946684800
bash configure --with-version-opt=adhoc
make images

# Build again - should be byte-for-byte identical
make dist-clean
bash configure --with-version-opt=adhoc
make images

Build System Utilities

# Show current configure command line
make print-configuration

# Show build performance summary
make print-configuration | grep -A 10 "performance"

Doctor (Diagnostics)

# Run build diagnostics
make doctor
Checks for:
  • Configure warnings
  • Left-over core files
  • Untracked files with illegal names
  • Other common build problems

Reconfigure

# Re-run configure with same arguments
make reconfigure

# Auto-reconfigure when needed
export CONF_CHECK=auto
make images  # Automatically reconfigures if configure changed

Build docs developers (and LLMs) love