gpu4j

Contributing to gpu4j

Thanks for your interest in contributing! This document describes how to build, test, and submit changes.

Repository layout

The root POM aggregates two modules and is deliberately not a parent:

modulewhat it is
gpu4j-corethe GPU offload API; published, currently 0.4.0
gpu4j-sidecarsupervises a local inference server; 0.1.0-SNAPSHOT

Neither inherits from the root, so neither picks up a version, a dependency set or a release cycle it did not ask for. mvn verify at the root builds and tests both.

The cost of that decision is that both module POMs spell out the versions of the test dependencies and plugins they share, and nothing in Maven stops the two drifting apart. ci/check-dependency-drift.sh fails the build when they disagree; run it locally with bash ci/check-dependency-drift.sh.

The one constraint worth knowing before you move anything

CratonVM's craton-gpu4j/build.rs compiles gpu4j-core/src/main/java during cargo build, locating it by path. Moving those sources without updating that script is silent on this side: it degrades to an empty annotations jar with only a cargo:warning, and the resulting VM recognises no @GpuKernel at all.

It probes every layout this repository has had — <repo>/gpu4j-core/src/main/java, the 2026-08-28 <repo>/craton-gpu/src/main/java, and the pre-0.3.0 flat <repo>/src/main/java — under both the current checkout name (gpu4j) and the old one (craton-gpu-java), plus the Windows install paths C:/craton/gpu4j, C:/craton/gpu-java and C:/craton/craton-gpu-java. $CRATON_GPU_JAVA_SRC overrides all of them.

The Java package names are a wire contract too. CratonVM's native-builtin registry binds by exact string: craton/gpu/internal/Native, craton/gpu/internal/{GpuExecutorImpl,GpuFutureImpl,GpuStreamImpl}, and descriptors naming Lcraton/gpu/GpuExecutor;, GpuFuture, GpuStream, GpuCallable, GpuRunnable, GpuArray, GpuKernel, EnableGpuAsync, GpuExclude and AdmissionHint. That is why the 2026-09-06 gpu4j rename changed the repository, the modules and the artifacts but not the packages: renaming those needs a coordinated change in native-builtins/src/craton_gpu.rs. Everything else — GpuBlas, Half, Transpose, PreparedKernel, GpuDevice, and everything in craton.gpu.internal bar Native — is free to rename.

Quick build

JDK 17 or newer is required.

mvn -q verify                              # both modules, tests and coverage
mvn -q -pl gpu4j-core package              # just the offload API
mvn -q -pl gpu4j-sidecar package           # just the sidecar

Both modules accept -Dbuild.qualifier=-something, appended to the artifact file name. Use it when building from a worktree alongside the main checkout so the jars cannot be confused. It is empty by default, so release output is unchanged.

Tests

mvn test                                   # both modules
mvn -pl gpu4j-core test                    # one of them

Two groups are excluded by default:

  • gpu — needs a real CUDA device behind a CratonVM built with --features gpu-driver, and for the sidecar, downloaded model weights. Run them with -Pgpu-tests; they self-skip via JUnit assumptions when no bridge is present.
  • slowHalfTest's exhaustive pass over all 2^32 floats, ~14 s. CI runs it on one matrix cell; run it locally with mvn -pl gpu4j-core test -Dsurefire.excludedGroups=gpu -Dgroups=slow.

gpu4j-core/examples/Demo.java is not under a Maven source root, so neither command compiles it. CI does, because it drifted out of compilation once already and shipped broken. If you change the public surface, check it:

mvn -q -DskipTests package
javac -d gpu4j-core/target/example-classes -cp gpu4j-core/target/classes     gpu4j-core/examples/Demo.java
java -cp "gpu4j-core/target/classes:gpu4j-core/target/example-classes" Demo

(On Windows the classpath separator is ;, not :.)

Code coverage

mvn verify runs a JaCoCo coverage gate in both modules. The build fails if the module bundle drops below 93% instructions / 90% lines in gpu4j-core, or 90% instructions in gpu4j-sidecar, or if any single class in gpu4j-core drops below 75% instructions.

The per-class rule exists because the bundle average hid the two classes that were actually thin behind a dozen at 100%: a whole feature (graph capture and replay) once landed with no tests at all and the gate did not notice.

A few classes are excluded from the gate but not from the report: craton.gpu.internal.Native and NativeImpl are pure delegation to native methods no stock JVM can execute, and craton.sidecar.LocalModelServer and SidecarProcess exist to launch and supervise an OS process. Add tests for the code you changed rather than lowering a threshold or extending that list.

Code style

  • Keep changes minimal and surgical. Avoid unrelated refactors in the same PR.
  • Match the existing Javadoc style on public types and methods.
  • No formatter is enforced. Mirror the surrounding code's indentation and brace style.

Branch strategy

  • dev is the integration branch; main holds releases.
  • Work on a feature branch off dev (e.g. feature/my-change, fix/issue-123).
  • Pull requests are squash-merged into dev. Keep your branch focused on one logical change.

Pull request process

  1. Open your PR against dev.
  2. Link the issue it addresses (e.g. Fixes #123).
  3. Fill out the PR template (summary, test plan, checklist).
  4. Request review from a maintainer. Address feedback by pushing additional commits — the squash-merge will collapse them.

Releasing to Maven Central

Maintainers: see docs/MAVEN_CENTRAL.md for namespace setup, GPG signing, GitHub secrets, and tag-based releases.

Code of conduct

This project adheres to the Contributor Covenant Code of Conduct. By participating, you agree to abide by its terms.