CratonVM

Building CratonVM

Building CratonVM

This guide consolidates the build, test, lint, and benchmark workflow for CratonVM in one place. For a project overview see README.md; for contribution guidelines see CONTRIBUTING.md; for binary installation see docs/INSTALL.md.

Prerequisites

  • Rust 1.80+ — install via rustup.rs.
  • JDK 17+ (optional) — only needed to compile the Java test classes and to boot against a real java.base. CratonVM runs standalone (synthetic JDK) without one.
  • Visual Studio Build Tools (Windows only) — for the MSVC toolchain/linker.

Building

git clone https://github.com/craton-co/cratonvm.git
cd cratonvm
cargo build --release -p cratonvm-cli

The package is cratonvm-cli, but the binary it produces is cratonvm, so the executable lands at target/release/cratonvm (or cratonvm.exe on Windows).

To build the whole workspace (all member crates and their targets):

cargo build --workspace --all-targets

Optional java binary alias

CratonVM does not install a java binary by default — that would shadow the system JDK launcher. If you need a java[.exe] launcher (e.g. for Maven Surefire's -Djvm=... validation, which requires the binary basename to be java), opt in with the java-bin-alias feature:

cargo build --release -p cratonvm-cli --features java-bin-alias
# now both target/release/cratonvm and target/release/java exist

Building with GPU offload

GPU offload is entirely opt-in and gated behind Cargo features on cratonvm-cli. There are three build levels; the exact feature chain lives in vm-cli/Cargo.toml:

CommandFeature chainWhat you get
cargo build --release -p cratonvm-cli(default)CPU-only. No GPU code linked, no --gpu* flags — byte-identical to a build of a tree that never had the feature.
cargo build --release -p cratonvm-cli --features gpugpu = ["dep:cuda-bridge", "cratonvm-vm/gpu-offload"]Stub mode. Links cuda-bridge (its no-driver backend_stub.rs) and exposes the --gpu* CLI flags, but every device probe returns DeviceError::NoDriver. Lets you exercise the GPU plumbing — CLI parsing, the analyze/cache/dispatch code paths, tests — on a machine with no NVIDIA hardware.
cargo build --release -p cratonvm-cli --features gpu-drivergpu-driver = ["gpu", "cuda-bridge/cuda"]Real CUDA. Compiles cuda-bridge's backend_cuda.rs against cudarc 0.13 (features = ["driver", "cuda-12060"], see cuda-bridge/Cargo.toml).

The gpu-driver build needs the CUDA Toolkit's headers/import libs available at build time. At run time it does not statically link a CUDA runtime — cudarc dynamically loads the NVIDIA driver (nvcuda.dll on Windows, libcuda.so on Linux) the first time the device is probed, so the binary it produces only works on a machine with a current NVIDIA driver installed.

Because gpu-driver compiles a different feature set than a plain build, building it into the default target/ directory would invalidate the incremental-build cache for cratonvm-vm, cratonvm-gc, and friends every time you switched between a CPU build and a GPU build. This repo avoids that by pointing the GPU build at its own target directory — scripts/build-gpu.bat:

set "CARGO_TARGET_DIR=C:\craton\CratonVM\target-gpu"
cargo build --release -p cratonvm-cli --bin cratonvm --features gpu-driver

(non-Windows equivalent: CARGO_TARGET_DIR=target-gpu cargo build --release -p cratonvm-cli --features gpu-driver). The GPU binary then lands at target-gpu/release/cratonvm[.exe], and an ordinary cargo build's target/release/cratonvm is left untouched — you can rebuild either one without invalidating the other's cache.

Runtime prerequisites (gpu-driver binary only): an NVIDIA GPU with a current driver on the system search path. No CUDA Toolkit install is required on the machine that runs the binary — only on the machine that builds it. In-repo validation used an RTX 2060 (sm_75) on Windows 11 with driver 591.86.

Smoke test:

target-gpu/release/cratonvm --gpu-info

probes the device, prints its name / compute capability / memory, and exits without booting the JVM. If --gpu is requested (on any build) and no driver is found, the flag is silently demoted and the JVM runs on CPU instead.

See bench-gpu/run-gpu-comparison.sh for the CratonVM-CPU vs. CratonVM-GPU vs. HotSpot vs. TornadoVM benchmark suite, and docs/gpu/README.md for the full architecture and CLI reference.

Running tests

# All tests
cargo test --all

# With increased stack for deep-recursion tests
RUST_MIN_STACK=8388608 cargo test --all -- --test-threads=4

Tests that require javac skip gracefully when no JDK is on the PATH.

Demanding that those skips did not happen

Most of vm/tests drives a real cratonvm binary, and a few also need a real JDK. When a prerequisite is missing, those tests print a note and return — and cargo then reports test ... ok, which is indistinguishable from a real pass. A whole suite can report green having asserted nothing. This is not hypothetical: a build cut off mid-link once left two JIT tests reporting ok ... finished in 0.00s with zero coverage, and the duration was the only tell.

Set CRATONVM_REQUIRE_E2E=1 to turn every such skip into a failure naming what was missing:

cargo build --release -p cratonvm-cli
CRATONVM_REQUIRE_E2E=1 cargo test -p cratonvm-vm

Leave it unset for ordinary development — default behaviour is unchanged, so a contributor with no JDK and no build is never blocked. 0 and the empty string also read as unset. See vm/tests/common/mod.rs.

Linting and formatting

These are the same checks CI is configured to run (.github/workflows/ci.yml, on ubuntu-latest and windows-latest):

cargo fmt --all --check
cargo clippy --all-targets --workspace -- -D warnings

Note: the workspace [lints] table in the root Cargo.toml allows dead_code/unused_* and a few rustdoc lints, so this command measures the repository's configured lint policy, not the full default lint set.

Benchmarking

CratonVM is benchmarked against HotSpot (JDK 25 C2). A representative result set (QuickBench, Binary Trees) and the methodology live in the README Benchmark section and the full 26-round JIT optimization write-up in docs/PRESENTATION.md. Profiling guidance is in docs/PROFILING.md.

A typical run compiles the benchmark's Java sources with javac, then runs the class under both java and the release cratonvm binary, comparing wall-clock time. Use --Xmx to give larger benchmarks more heap (e.g. --Xmx 8g for the binary-trees workload) and --nojit to isolate interpreter-only timings.

Workspace layout

The workspace has 22 member crates (including libcratonvm, cratonvm-embed, and cratonvm-difftest); the fuzz harness is a separate, standalone workspace, not a member. See ARCHITECTURE.md for the detailed structure and CONTRIBUTING.md for the per-crate purpose table.