You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Is your feature request related to a problem? Please describe.
The Java bindings (#1524) have no installation path. Nothing is published — no jar, no libcuopt_jni.so — so a user must build the JNI shim from source. That needs libcuopt, its headers, a C++20 compiler, CMake, Ninja, Maven and a JDK.
Conda is effectively mandatory, and not by choice: the JNI build needs the exact rmm and raft headers libcuopt was compiled against, because rmm encodes its version in an inline namespace (rmm::_RMM_26_10). A mismatched copy links cleanly and then fails at dlopen with an undefined symbol. Those headers only ship as conda packages, so a pip wheel is not sufficient.
Verified end to end in a clean nvidia/cuda:13.0.3-base-ubuntu24.04 container: miniforge -> conda env -> build_native.sh -> mvn package -> compile and run a user program. It works, but that is the floor for "hello world".
Describe the solution you'd like
Adopt the cuDF model: publish self-contained per-classifier JARs that bundle a statically linked native library, so a user needs only a Maven dependency and a driver.
Link against a static libcudf built from source per CUDA version rather than a conda shared libcudf.
It builds with -DBUILD_SHARED_LIBS=OFF and splits the work into three composable stages — static native build, per-classifier JAR packaging, Maven-repo gather.
The result is genuinely self-contained. libcudf.so inside the published jar has these DT_NEEDED entries and nothing else:
For cuOpt this would also defuse #1703 as a distribution hazard. libcuopt_jni.so currently reaches through the private pdlp/cuopt_c_internal.hpp and is coupled to a specific libcuopt build. That is only dangerous because the user supplies libcuopt independently; if both halves are built and shipped together, a cuOpt point release cannot break the jar. It does not remove the need for #1703, but it removes the failure mode.
Describe alternatives you've considered
The cuVS model — a pure-Java jar.com.nvidia.cuvs:cuvs-java is 1.4 MB, ships a NativeDependencyLoader, and expects libcuvs from conda/pip/system. Simpler and far smaller, but it leaves the user to supply and match the native library, which is exactly the fragile configuration given #1703.
Reasonable as a stopgap; poor as an end state.
Additional context
Size is the open risk, and it is specific to cuOpt.libcuopt.so is 554 MB shared with 29 DT_NEEDED entries:
dependency
size
libcublas
517 MB
libnccl
279 MB
libcusparse
155 MB
libcudss
67 MB
libgrpc / protobuf / abseil
~25 MB
A naive static build would likely exceed cuDF's 708 MB. Maven Central documents a 1 GB limit per uploaded bundle ("You can upload an archive up to 1GB in size"), applying to the whole archive rather than a single file.
The scoping work needed is already in flight, and this issue depends on it:
NCCL (distributed multi-GPU PDLP) and the gRPC server stack are not needed by a Java jar at all, which is ~300 MB of the total.
Publishing infrastructure is being rebuilt upstream and we should adopt it rather than write our own:
rapidsai/build-infra#379 — cuDF Java release pipeline migration to ADI-owned GitHub Actions. Its stated goal is that "other ADI Java projects (cuVS, cuvs-lucene, etc.) can adopt the same pattern."
Worth noting when planning: cuDF's java-publish job is currently skipped in every recent build.yaml run (gated on release builds) and #385 is not started, so that pipeline has not yet run for a real release. The 26.08.1 artifacts on Central came from the legacy Spark RAPIDS Jenkins process. Its assemble_maven_repo.sh gathers all classifiers into a single Maven repo tree published as one bundle, which for 26.08.1 totals 2.69 GB against the documented 1 GB ceiling — unresolved, and raised upstream.
Is your feature request related to a problem? Please describe.
The Java bindings (#1524) have no installation path. Nothing is published — no jar, no
libcuopt_jni.so— so a user must build the JNI shim from source. That needslibcuopt, its headers, a C++20 compiler, CMake, Ninja, Maven and a JDK.Conda is effectively mandatory, and not by choice: the JNI build needs the exact rmm and raft headers
libcuoptwas compiled against, because rmm encodes its version in an inline namespace (rmm::_RMM_26_10). A mismatched copy links cleanly and then fails atdlopenwith an undefined symbol. Those headers only ship as conda packages, so a pip wheel is not sufficient.Verified end to end in a clean
nvidia/cuda:13.0.3-base-ubuntu24.04container: miniforge -> conda env ->build_native.sh->mvn package-> compile and run a user program. It works, but that is the floor for "hello world".Describe the solution you'd like
Adopt the cuDF model: publish self-contained per-classifier JARs that bundle a statically linked native library, so a user needs only a Maven dependency and a driver.
cuDF did this in rapidsai/cudf#23261 (merged 2026-07-21):
It builds with
-DBUILD_SHARED_LIBS=OFFand splits the work into three composable stages — static native build, per-classifier JAR packaging, Maven-repo gather.The result is genuinely self-contained.
libcudf.soinside the published jar has theseDT_NEEDEDentries and nothing else:No
libcudart, nolibrmm, no conda. Published classifiers on Maven Central forai.rapids:cudf:26.08.1:For cuOpt this would also defuse #1703 as a distribution hazard.
libcuopt_jni.socurrently reaches through the privatepdlp/cuopt_c_internal.hppand is coupled to a specificlibcuoptbuild. That is only dangerous because the user supplieslibcuoptindependently; if both halves are built and shipped together, a cuOpt point release cannot break the jar. It does not remove the need for #1703, but it removes the failure mode.Describe alternatives you've considered
The cuVS model — a pure-Java jar.
com.nvidia.cuvs:cuvs-javais 1.4 MB, ships aNativeDependencyLoader, and expectslibcuvsfrom conda/pip/system. Simpler and far smaller, but it leaves the user to supply and match the native library, which is exactly the fragile configuration given #1703.Reasonable as a stopgap; poor as an end state.
Additional context
Size is the open risk, and it is specific to cuOpt.
libcuopt.sois 554 MB shared with 29DT_NEEDEDentries:A naive static build would likely exceed cuDF's 708 MB. Maven Central documents a 1 GB limit per uploaded bundle ("You can upload an archive up to 1GB in size"), applying to the whole archive rather than a single file.
The scoping work needed is already in flight, and this issue depends on it:
libcuoptintocuopt_base/cuopt_routing/cuopt_lp. The Java bindings expose no routing, so a Java jar should carry only the LP components.libcuopt.sobinary size.NCCL (distributed multi-GPU PDLP) and the gRPC server stack are not needed by a Java jar at all, which is ~300 MB of the total.
Publishing infrastructure is being rebuilt upstream and we should adopt it rather than write our own:
Worth noting when planning: cuDF's
java-publishjob is currentlyskippedin every recentbuild.yamlrun (gated on release builds) and #385 is not started, so that pipeline has not yet run for a real release. The 26.08.1 artifacts on Central came from the legacy Spark RAPIDS Jenkins process. Itsassemble_maven_repo.shgathers all classifiers into a single Maven repo tree published as one bundle, which for 26.08.1 totals 2.69 GB against the documented 1 GB ceiling — unresolved, and raised upstream.Proposed scope
libcuoptbuild (BUILD_SHARED_LIBS=OFF), LP-only where build(cmake): split libcuopt into cuopt_base / cuopt_routing / cuopt_lp component libs #1622 allows, excluding routing, NCCL and the gRPC server.cuda12/cuda13xx86_64/arm64.Contributes to #1535.