From 396f8e3538d064aacd7f36900803b9649a683679 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 6 Oct 2026 21:09:45 +0000 Subject: [PATCH 1/4] build: switch cuOpt link packaging to modular 26.10 wheels Re-applies 8edd916 (reverted in 4855ada) now that the split wheels (libcuopt-mathopt-cuXX, libcuopt-client, libcuopt-routing-cuXX) are published on the rapidsai nightly index, starting with 26.10.0a248. Changes against the original attempt: - Pin libcuopt-mathopt-cuXX and libcuopt-client directly instead of the libcuopt-cuXX umbrella. The umbrella only requires its parts as ==26.10.*, so pinning it no longer fixes the solver build that gets packaged. - Drop the copies from libcuopt_client_cu12.libs / _cu13.libs. The client wheel carries no CUDA suffix and only ships libcuopt_client.libs, so those cp lines would fail the job. Pinned to 26.10.0a250.post261006201351 (cuOpt main f123643). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01ALHyZUW9bDK51TntcQG4cg --- .github/workflows/main-arm64.yml | 48 +++++++++++++++++-------------- .github/workflows/main-x86_64.yml | 48 +++++++++++++++++-------------- build-link.sh | 27 +++++++++-------- 3 files changed, 67 insertions(+), 56 deletions(-) diff --git a/.github/workflows/main-arm64.yml b/.github/workflows/main-arm64.yml index 4673fea..ba6980a 100644 --- a/.github/workflows/main-arm64.yml +++ b/.github/workflows/main-arm64.yml @@ -28,9 +28,9 @@ jobs: run: | mkdir -p venvs uv venv venvs/cu12 - uv pip install --python venvs/cu12 --prerelease=allow --index-strategy unsafe-best-match --extra-index-url=https://pypi.anaconda.org/rapidsai-wheels-nightly/simple --extra-index-url=https://pypi.nvidia.com 'libcuopt-cu12==26.10.0a224.post261002130525' -qq + uv pip install --python venvs/cu12 --prerelease=allow --index-strategy unsafe-best-match --extra-index-url=https://pypi.anaconda.org/rapidsai-wheels-nightly/simple --extra-index-url=https://pypi.nvidia.com 'libcuopt-mathopt-cu12==26.10.0a250.post261006201351' 'libcuopt-client==26.10.0a250.post261006201351' -qq uv venv venvs/cu13 - uv pip install --python venvs/cu13 --prerelease=allow --index-strategy unsafe-best-match --extra-index-url=https://pypi.anaconda.org/rapidsai-wheels-nightly/simple --extra-index-url=https://pypi.nvidia.com 'libcuopt-cu13==26.10.0a224.post261002130525' -qq + uv pip install --python venvs/cu13 --prerelease=allow --index-strategy unsafe-best-match --extra-index-url=https://pypi.anaconda.org/rapidsai-wheels-nightly/simple --extra-index-url=https://pypi.nvidia.com 'libcuopt-mathopt-cu13==26.10.0a250.post261006201351' 'libcuopt-client==26.10.0a250.post261006201351' -qq # Get GAMS (ARM64 version) - name: Download and extract latest GAMS distribution @@ -44,23 +44,25 @@ jobs: - name: Compile GAMS/cuOpt-link binary "gmscuopt.out" for CUDA 12 and then for CUDA 13 run: | export GAMSCAPI="gamsdist/apifiles/C/api" - export CUOPT="venvs/cu12/lib/python3.13/site-packages/libcuopt" + export CUOPT="venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt" export JITLINK="venvs/cu12/lib/python3.13/site-packages/nvidia/nvjitlink/lib" export CUOPT_VERSION="`cat "$CUOPT/VERSION"`" export CUOPT_HASH="`cat "$CUOPT/GIT_COMMIT"`" gcc -Wall gmscuopt.c -o gmscuopt-cu12.out \ -DCUOPT_VERSION=\"$CUOPT_VERSION\" -DCUOPT_HASH=\"$CUOPT_HASH\" \ -I $GAMSCAPI $GAMSCAPI/gmomcc.c $GAMSCAPI/optcc.c $GAMSCAPI/gevmcc.c \ - -I $CUOPT/include $JITLINK/libnvJitLink.so.12 -L $CUOPT/lib64 -lcuopt_mathopt + -I $CUOPT/include -I venvs/cu12/lib/python3.13/site-packages/libcuopt_client/include $JITLINK/libnvJitLink.so.12 -L $CUOPT/lib64 -lcuopt_mathopt \ + -L venvs/cu12/lib/python3.13/site-packages/libcuopt_client/lib64 -lcuopt_client patchelf --set-rpath \$ORIGIN gmscuopt-cu12.out - export CUOPT="venvs/cu13/lib/python3.13/site-packages/libcuopt" + export CUOPT="venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt" export JITLINK="venvs/cu13/lib/python3.13/site-packages/nvidia/cu13/lib" export CUOPT_VERSION="`cat "$CUOPT/VERSION"`" export CUOPT_HASH="`cat "$CUOPT/GIT_COMMIT"`" gcc -Wall gmscuopt.c -o gmscuopt-cu13.out \ -DCUOPT_VERSION=\"$CUOPT_VERSION\" -DCUOPT_HASH=\"$CUOPT_HASH\" \ -I $GAMSCAPI $GAMSCAPI/gmomcc.c $GAMSCAPI/optcc.c $GAMSCAPI/gevmcc.c \ - -I $CUOPT/include $JITLINK/libnvJitLink.so.13 -L $CUOPT/lib64 -lcuopt_mathopt + -I $CUOPT/include -I venvs/cu13/lib/python3.13/site-packages/libcuopt_client/include $JITLINK/libnvJitLink.so.13 -L $CUOPT/lib64 -lcuopt_mathopt \ + -L venvs/cu13/lib/python3.13/site-packages/libcuopt_client/lib64 -lcuopt_client patchelf --set-rpath \$ORIGIN gmscuopt-cu13.out # Collect dependencies for link and runtime convenience archive @@ -69,13 +71,14 @@ jobs: mkdir release-cu12 cp gmscuopt-cu12.out release-cu12/gmscuopt.out cp assets/* release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt/lib64/libcuopt_mathopt.so release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt/lib64/libcuopt_client.so release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libgomp-*.so* release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libtbb-*.so* release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libtbbmalloc-*.so* release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt/lib64/libcudss_mtlayer_cuopt.so release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libcudart-*.so* release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt/lib64/libcuopt_mathopt.so release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_client/lib64/libcuopt_client.so release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt_cu12.libs/libgomp-*.so* release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_client.libs/libgomp-*.so* release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt_cu12.libs/libtbb-*.so* release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt_cu12.libs/libtbbmalloc-*.so* release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt/lib64/libcudss_mtlayer_cuopt.so release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt_cu12.libs/libcudart-*.so* release-cu12/ cp venvs/cu12/lib/python3.13/site-packages/rapids_logger/lib64/librapids_logger.so release-cu12/ cp venvs/cu12/lib/python3.13/site-packages/librmm/lib64/librmm.so release-cu12/ cp venvs/cu12/lib/python3.13/site-packages/nvidia/nccl/lib/libnccl.so* release-cu12/ @@ -87,17 +90,18 @@ jobs: cp venvs/cu12/lib/python3.13/site-packages/nvidia/nvjitlink/lib/libnvJitLink.so* runtime-cu12/ cp venvs/cu12/lib/python3.13/site-packages/nvidia/curand/lib/libcurand.so* runtime-cu12/ cp venvs/cu12/lib/python3.13/site-packages/nvidia/cusparse/lib/libcusparse.so* runtime-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libcares-*.so* runtime-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_client.libs/libcares-*.so* runtime-cu12/ mkdir release-cu13 cp gmscuopt-cu13.out release-cu13/gmscuopt.out cp assets/* release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt/lib64/libcuopt_mathopt.so release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt/lib64/libcuopt_client.so release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libgomp-*.so* release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libtbb-*.so* release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libtbbmalloc-*.so* release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt/lib64/libcudss_mtlayer_cuopt.so release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libcudart-*.so* release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt/lib64/libcuopt_mathopt.so release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_client/lib64/libcuopt_client.so release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt_cu13.libs/libgomp-*.so* release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_client.libs/libgomp-*.so* release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt_cu13.libs/libtbb-*.so* release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt_cu13.libs/libtbbmalloc-*.so* release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt/lib64/libcudss_mtlayer_cuopt.so release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt_cu13.libs/libcudart-*.so* release-cu13/ cp venvs/cu13/lib/python3.13/site-packages/rapids_logger/lib64/librapids_logger.so release-cu13/ cp venvs/cu13/lib/python3.13/site-packages/librmm/lib64/librmm.so release-cu13/ cp venvs/cu13/lib/python3.13/site-packages/nvidia/nccl/lib/libnccl.so* release-cu13/ @@ -109,7 +113,7 @@ jobs: cp venvs/cu13/lib/python3.13/site-packages/nvidia/cu13/lib/libcurand.so* runtime-cu13/ cp venvs/cu13/lib/python3.13/site-packages/nvidia/cu13/lib/libcusolver.so* runtime-cu13/ cp venvs/cu13/lib/python3.13/site-packages/nvidia/cu13/lib/libcusparse.so* runtime-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libcares-*.so* runtime-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_client.libs/libcares-*.so* runtime-cu13/ # Upload artifacts - name: Upload CUDA 12 link artifact to GitHub Actions (always) diff --git a/.github/workflows/main-x86_64.yml b/.github/workflows/main-x86_64.yml index 13ba24e..7d17fda 100644 --- a/.github/workflows/main-x86_64.yml +++ b/.github/workflows/main-x86_64.yml @@ -28,9 +28,9 @@ jobs: run: | mkdir -p venvs uv venv venvs/cu12 - uv pip install --python venvs/cu12 --prerelease=allow --index-strategy unsafe-best-match --extra-index-url=https://pypi.anaconda.org/rapidsai-wheels-nightly/simple --extra-index-url=https://pypi.nvidia.com 'libcuopt-cu12==26.10.0a224.post261002130525' -qq + uv pip install --python venvs/cu12 --prerelease=allow --index-strategy unsafe-best-match --extra-index-url=https://pypi.anaconda.org/rapidsai-wheels-nightly/simple --extra-index-url=https://pypi.nvidia.com 'libcuopt-mathopt-cu12==26.10.0a250.post261006201351' 'libcuopt-client==26.10.0a250.post261006201351' -qq uv venv venvs/cu13 - uv pip install --python venvs/cu13 --prerelease=allow --index-strategy unsafe-best-match --extra-index-url=https://pypi.anaconda.org/rapidsai-wheels-nightly/simple --extra-index-url=https://pypi.nvidia.com 'libcuopt-cu13==26.10.0a224.post261002130525' -qq + uv pip install --python venvs/cu13 --prerelease=allow --index-strategy unsafe-best-match --extra-index-url=https://pypi.anaconda.org/rapidsai-wheels-nightly/simple --extra-index-url=https://pypi.nvidia.com 'libcuopt-mathopt-cu13==26.10.0a250.post261006201351' 'libcuopt-client==26.10.0a250.post261006201351' -qq # Get GAMS - name: Download and extract latest GAMS distribution @@ -44,23 +44,25 @@ jobs: - name: Compile GAMS/cuOpt-link binary "gmscuopt.out" for CUDA 12 and then for CUDA 13 run: | export GAMSCAPI="gamsdist/apifiles/C/api" - export CUOPT="venvs/cu12/lib/python3.13/site-packages/libcuopt" + export CUOPT="venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt" export JITLINK="venvs/cu12/lib/python3.13/site-packages/nvidia/nvjitlink/lib" export CUOPT_VERSION="`cat "$CUOPT/VERSION"`" export CUOPT_HASH="`cat "$CUOPT/GIT_COMMIT"`" gcc -Wall gmscuopt.c -o gmscuopt-cu12.out \ -DCUOPT_VERSION=\"$CUOPT_VERSION\" -DCUOPT_HASH=\"$CUOPT_HASH\" \ -I $GAMSCAPI $GAMSCAPI/gmomcc.c $GAMSCAPI/optcc.c $GAMSCAPI/gevmcc.c \ - -I $CUOPT/include $JITLINK/libnvJitLink.so.12 -L $CUOPT/lib64 -lcuopt_mathopt + -I $CUOPT/include -I venvs/cu12/lib/python3.13/site-packages/libcuopt_client/include $JITLINK/libnvJitLink.so.12 -L $CUOPT/lib64 -lcuopt_mathopt \ + -L venvs/cu12/lib/python3.13/site-packages/libcuopt_client/lib64 -lcuopt_client patchelf --set-rpath \$ORIGIN gmscuopt-cu12.out - export CUOPT="venvs/cu13/lib/python3.13/site-packages/libcuopt" + export CUOPT="venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt" export JITLINK="venvs/cu13/lib/python3.13/site-packages/nvidia/cu13/lib" export CUOPT_VERSION="`cat "$CUOPT/VERSION"`" export CUOPT_HASH="`cat "$CUOPT/GIT_COMMIT"`" gcc -Wall gmscuopt.c -o gmscuopt-cu13.out \ -DCUOPT_VERSION=\"$CUOPT_VERSION\" -DCUOPT_HASH=\"$CUOPT_HASH\" \ -I $GAMSCAPI $GAMSCAPI/gmomcc.c $GAMSCAPI/optcc.c $GAMSCAPI/gevmcc.c \ - -I $CUOPT/include $JITLINK/libnvJitLink.so.13 -L $CUOPT/lib64 -lcuopt_mathopt + -I $CUOPT/include -I venvs/cu13/lib/python3.13/site-packages/libcuopt_client/include $JITLINK/libnvJitLink.so.13 -L $CUOPT/lib64 -lcuopt_mathopt \ + -L venvs/cu13/lib/python3.13/site-packages/libcuopt_client/lib64 -lcuopt_client patchelf --set-rpath \$ORIGIN gmscuopt-cu13.out # Collect dependencies for link and runtime convenience archive @@ -69,13 +71,14 @@ jobs: mkdir release-cu12 cp gmscuopt-cu12.out release-cu12/gmscuopt.out cp assets/* release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt/lib64/libcuopt_mathopt.so release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt/lib64/libcuopt_client.so release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libgomp-*.so* release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libtbb-*.so* release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libtbbmalloc-*.so* release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt/lib64/libcudss_mtlayer_cuopt.so release-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libcudart-*.so* release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt/lib64/libcuopt_mathopt.so release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_client/lib64/libcuopt_client.so release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt_cu12.libs/libgomp-*.so* release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_client.libs/libgomp-*.so* release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt_cu12.libs/libtbb-*.so* release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt_cu12.libs/libtbbmalloc-*.so* release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt/lib64/libcudss_mtlayer_cuopt.so release-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_mathopt_cu12.libs/libcudart-*.so* release-cu12/ cp venvs/cu12/lib/python3.13/site-packages/rapids_logger/lib64/librapids_logger.so release-cu12/ cp venvs/cu12/lib/python3.13/site-packages/librmm/lib64/librmm.so release-cu12/ cp venvs/cu12/lib/python3.13/site-packages/nvidia/nccl/lib/libnccl.so* release-cu12/ @@ -87,17 +90,18 @@ jobs: cp venvs/cu12/lib/python3.13/site-packages/nvidia/nvjitlink/lib/libnvJitLink.so* runtime-cu12/ cp venvs/cu12/lib/python3.13/site-packages/nvidia/curand/lib/libcurand.so* runtime-cu12/ cp venvs/cu12/lib/python3.13/site-packages/nvidia/cusparse/lib/libcusparse.so* runtime-cu12/ - cp venvs/cu12/lib/python3.13/site-packages/libcuopt_cu12.libs/libcares-*.so* runtime-cu12/ + cp venvs/cu12/lib/python3.13/site-packages/libcuopt_client.libs/libcares-*.so* runtime-cu12/ mkdir release-cu13 cp gmscuopt-cu13.out release-cu13/gmscuopt.out cp assets/* release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt/lib64/libcuopt_mathopt.so release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt/lib64/libcuopt_client.so release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libgomp-*.so* release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libtbb-*.so* release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libtbbmalloc-*.so* release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt/lib64/libcudss_mtlayer_cuopt.so release-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libcudart-*.so* release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt/lib64/libcuopt_mathopt.so release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_client/lib64/libcuopt_client.so release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt_cu13.libs/libgomp-*.so* release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_client.libs/libgomp-*.so* release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt_cu13.libs/libtbb-*.so* release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt_cu13.libs/libtbbmalloc-*.so* release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt/lib64/libcudss_mtlayer_cuopt.so release-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_mathopt_cu13.libs/libcudart-*.so* release-cu13/ cp venvs/cu13/lib/python3.13/site-packages/rapids_logger/lib64/librapids_logger.so release-cu13/ cp venvs/cu13/lib/python3.13/site-packages/librmm/lib64/librmm.so release-cu13/ cp venvs/cu13/lib/python3.13/site-packages/nvidia/nccl/lib/libnccl.so* release-cu13/ @@ -109,7 +113,7 @@ jobs: cp venvs/cu13/lib/python3.13/site-packages/nvidia/cu13/lib/libcurand.so* runtime-cu13/ cp venvs/cu13/lib/python3.13/site-packages/nvidia/cu13/lib/libcusolver.so* runtime-cu13/ cp venvs/cu13/lib/python3.13/site-packages/nvidia/cu13/lib/libcusparse.so* runtime-cu13/ - cp venvs/cu13/lib/python3.13/site-packages/libcuopt_cu13.libs/libcares-*.so* runtime-cu13/ + cp venvs/cu13/lib/python3.13/site-packages/libcuopt_client.libs/libcares-*.so* runtime-cu13/ # Upload artifacts - name: Upload CUDA 12 link artifact to GitHub Actions (always) diff --git a/build-link.sh b/build-link.sh index bbdc987..c3d7ef7 100755 --- a/build-link.sh +++ b/build-link.sh @@ -6,8 +6,7 @@ set -e # Users can export these before running the script, otherwise defaults are used. GAMSDIST="${GAMSDIST:-$HOME/gamsdist}" WORKSPACE="${WORKSPACE:-$(pwd)}" -CUOPT_VERSION="${CUOPT_VERSION:-26.08}" -CUOPT_HASH="${CUOPT_HASH:-12345}" +# Read build provenance from the mathopt wheel unless explicitly overridden below. # 2. Dynamically find the site-packages directory to avoid hardcoding the Python version # or the venv directory name (some setups use "venv", others "uv"-style ".venv"). @@ -27,8 +26,10 @@ fi # 3. Export specific build paths export GAMSCAPI="$GAMSDIST/apifiles/C/api" -export CUOPT="$SITE_PACKAGES/libcuopt" +export CUOPT="$SITE_PACKAGES/libcuopt_mathopt" export JITLINK="$SITE_PACKAGES/nvidia/cu13/lib" +CUOPT_VERSION="${CUOPT_VERSION:-$(<"$CUOPT/VERSION")}" +CUOPT_HASH="${CUOPT_HASH:-$(<"$CUOPT/GIT_COMMIT")}" echo "Building GAMS cuOpt solver link..." echo "Using GAMSDIST: $GAMSDIST" @@ -39,8 +40,9 @@ gcc -g3 -O0 -Wall gmscuopt.c -o gmscuopt-cu13.out \ -DCUOPT_VERSION=\"$CUOPT_VERSION\" \ -DCUOPT_HASH=\"$CUOPT_HASH\" \ -I "$GAMSCAPI" "$GAMSCAPI/gmomcc.c" "$GAMSCAPI/optcc.c" "$GAMSCAPI/gevmcc.c" \ - -I "$CUOPT/include" "$JITLINK/libnvJitLink.so.13" \ - -L "$CUOPT/lib64" -lcuopt_mathopt + -I "$CUOPT/include" -I "$SITE_PACKAGES/libcuopt_client/include" "$JITLINK/libnvJitLink.so.13" \ + -L "$CUOPT/lib64" -lcuopt_mathopt \ + -L "$SITE_PACKAGES/libcuopt_client/lib64" -lcuopt_client # 5. Patch RPATH patchelf --set-rpath \$ORIGIN gmscuopt-cu13.out @@ -54,12 +56,13 @@ mkdir -p "$GAMSDIST" mv gmscuopt-cu13.out "$GAMSDIST/gmscuopt.out" cp "$CUOPT/lib64/libcuopt_mathopt.so" "$GAMSDIST/" -cp "$CUOPT/lib64/libcuopt_client.so" "$GAMSDIST/" -cp "$SITE_PACKAGES"/libcuopt_cu13.libs/libgomp-*.so* "$GAMSDIST/" -cp "$SITE_PACKAGES"/libcuopt_cu13.libs/libtbb-*.so* "$GAMSDIST/" -cp "$SITE_PACKAGES"/libcuopt_cu13.libs/libtbbmalloc-*.so* "$GAMSDIST/" -cp "$SITE_PACKAGES"/libcuopt/lib64/libcudss_mtlayer_cuopt.so "$GAMSDIST/" -cp "$SITE_PACKAGES"/libcuopt_cu13.libs/libcudart-*.so* "$GAMSDIST/" +cp "$SITE_PACKAGES/libcuopt_client/lib64/libcuopt_client.so" "$GAMSDIST/" +cp "$SITE_PACKAGES"/libcuopt_mathopt_cu13.libs/libgomp-*.so* "$GAMSDIST/" +cp "$SITE_PACKAGES"/libcuopt_client.libs/libgomp-*.so* "$GAMSDIST/" +cp "$SITE_PACKAGES"/libcuopt_mathopt_cu13.libs/libtbb-*.so* "$GAMSDIST/" +cp "$SITE_PACKAGES"/libcuopt_mathopt_cu13.libs/libtbbmalloc-*.so* "$GAMSDIST/" +cp "$CUOPT/lib64/libcudss_mtlayer_cuopt.so" "$GAMSDIST/" +cp "$SITE_PACKAGES"/libcuopt_mathopt_cu13.libs/libcudart-*.so* "$GAMSDIST/" cp "$SITE_PACKAGES"/rapids_logger/lib64/librapids_logger.so "$GAMSDIST/" cp "$SITE_PACKAGES"/librmm/lib64/librmm.so "$GAMSDIST/" cp "$SITE_PACKAGES"/nvidia/cu13/lib/libcudss.so* "$GAMSDIST/" @@ -69,7 +72,7 @@ cp "$SITE_PACKAGES"/nvidia/cu13/lib/libcublasLt.so* "$GAMSDIST/" cp "$SITE_PACKAGES"/nvidia/cu13/lib/libcurand.so* "$GAMSDIST/" cp "$SITE_PACKAGES"/nvidia/cu13/lib/libcusolver.so* "$GAMSDIST/" cp "$SITE_PACKAGES"/nvidia/cu13/lib/libcusparse.so* "$GAMSDIST/" -cp "$SITE_PACKAGES"/libcuopt_cu13.libs/libcares-*.so* "$GAMSDIST/" +cp "$SITE_PACKAGES"/libcuopt_client.libs/libcares-*.so* "$GAMSDIST/" cp "$SITE_PACKAGES"/nvidia/nccl/lib/libnccl.so* "$GAMSDIST/" # Copy assets (suppress errors if directory is empty or missing) From 7e96a9e100fbf4bd2d352d89ea4d8a71cbc31d65 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 6 Oct 2026 21:50:15 +0000 Subject: [PATCH 2/4] ci: track latest 26.10 cuOpt nightly instead of an exact build Nightly builds drop off the rapidsai index after a few days, so an exact nightly pin breaks CI regularly. Constrain libcuopt-mathopt and libcuopt-client to 26.10.* instead: CI follows the newest 26.10 nightly, cannot jump to 26.12 nightlies from main, and picks up 26.10.0 final once it is published. The exact cuOpt version and commit stay embedded in the built link. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01ALHyZUW9bDK51TntcQG4cg --- .github/workflows/main-arm64.yml | 4 ++-- .github/workflows/main-x86_64.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main-arm64.yml b/.github/workflows/main-arm64.yml index ba6980a..ffbd339 100644 --- a/.github/workflows/main-arm64.yml +++ b/.github/workflows/main-arm64.yml @@ -28,9 +28,9 @@ jobs: run: | mkdir -p venvs uv venv venvs/cu12 - uv pip install --python venvs/cu12 --prerelease=allow --index-strategy unsafe-best-match --extra-index-url=https://pypi.anaconda.org/rapidsai-wheels-nightly/simple --extra-index-url=https://pypi.nvidia.com 'libcuopt-mathopt-cu12==26.10.0a250.post261006201351' 'libcuopt-client==26.10.0a250.post261006201351' -qq + uv pip install --python venvs/cu12 --prerelease=allow --index-strategy unsafe-best-match --extra-index-url=https://pypi.anaconda.org/rapidsai-wheels-nightly/simple --extra-index-url=https://pypi.nvidia.com 'libcuopt-mathopt-cu12==26.10.*' 'libcuopt-client==26.10.*' -qq uv venv venvs/cu13 - uv pip install --python venvs/cu13 --prerelease=allow --index-strategy unsafe-best-match --extra-index-url=https://pypi.anaconda.org/rapidsai-wheels-nightly/simple --extra-index-url=https://pypi.nvidia.com 'libcuopt-mathopt-cu13==26.10.0a250.post261006201351' 'libcuopt-client==26.10.0a250.post261006201351' -qq + uv pip install --python venvs/cu13 --prerelease=allow --index-strategy unsafe-best-match --extra-index-url=https://pypi.anaconda.org/rapidsai-wheels-nightly/simple --extra-index-url=https://pypi.nvidia.com 'libcuopt-mathopt-cu13==26.10.*' 'libcuopt-client==26.10.*' -qq # Get GAMS (ARM64 version) - name: Download and extract latest GAMS distribution diff --git a/.github/workflows/main-x86_64.yml b/.github/workflows/main-x86_64.yml index 7d17fda..f900c4b 100644 --- a/.github/workflows/main-x86_64.yml +++ b/.github/workflows/main-x86_64.yml @@ -28,9 +28,9 @@ jobs: run: | mkdir -p venvs uv venv venvs/cu12 - uv pip install --python venvs/cu12 --prerelease=allow --index-strategy unsafe-best-match --extra-index-url=https://pypi.anaconda.org/rapidsai-wheels-nightly/simple --extra-index-url=https://pypi.nvidia.com 'libcuopt-mathopt-cu12==26.10.0a250.post261006201351' 'libcuopt-client==26.10.0a250.post261006201351' -qq + uv pip install --python venvs/cu12 --prerelease=allow --index-strategy unsafe-best-match --extra-index-url=https://pypi.anaconda.org/rapidsai-wheels-nightly/simple --extra-index-url=https://pypi.nvidia.com 'libcuopt-mathopt-cu12==26.10.*' 'libcuopt-client==26.10.*' -qq uv venv venvs/cu13 - uv pip install --python venvs/cu13 --prerelease=allow --index-strategy unsafe-best-match --extra-index-url=https://pypi.anaconda.org/rapidsai-wheels-nightly/simple --extra-index-url=https://pypi.nvidia.com 'libcuopt-mathopt-cu13==26.10.0a250.post261006201351' 'libcuopt-client==26.10.0a250.post261006201351' -qq + uv pip install --python venvs/cu13 --prerelease=allow --index-strategy unsafe-best-match --extra-index-url=https://pypi.anaconda.org/rapidsai-wheels-nightly/simple --extra-index-url=https://pypi.nvidia.com 'libcuopt-mathopt-cu13==26.10.*' 'libcuopt-client==26.10.*' -qq # Get GAMS - name: Download and extract latest GAMS distribution From d0c97dd8c1fa39796233ab3215b51586c237c280 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 6 Oct 2026 22:31:26 +0000 Subject: [PATCH 3/4] tests: add Colab notebook to run the GPU tests against a branch The CI runners have no GPU, so the gamslib regression test only runs on developer machines. tests/colab-gpu-test.ipynb builds the link from a chosen branch by running the run steps of main-x86_64.yml unchanged, installs it into the downloaded GAMS system (picking CUDA 12 or 13 from the driver), reads an optional GAMS license from the Colab secret GAMS_LICENSE, and runs a trnsport smoke test that aborts on a non-optimal solve, followed by tests/test-gamslib-cuopt.py. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01ALHyZUW9bDK51TntcQG4cg --- CONTRIBUTING.md | 2 + README.md | 2 + tests/colab-gpu-test.ipynb | 184 +++++++++++++++++++++++++++++++++++++ 3 files changed, 188 insertions(+) create mode 100644 tests/colab-gpu-test.ipynb diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 43e886b..2638fae 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -32,6 +32,8 @@ New or changed cuOpt options go into `assets/optcuopt.def` and have to be passed The GPU tests use the GAMS system found in your `PATH`, with the link installed. +Without a local GPU, open `tests/colab-gpu-test.ipynb` in Google Colab with a GPU runtime: it builds the link from a branch the same way as CI, installs it into a fresh GAMS system and runs a `trnsport` smoke test and `tests/test-gamslib-cuopt.py`. + ## Pull requests - Keep each pull request focused on one change and describe how you tested it. diff --git a/README.md b/README.md index 20caf86..23e939e 100644 --- a/README.md +++ b/README.md @@ -168,3 +168,5 @@ python3 tests/test-gamslib-cuopt.py -g -j 2 # -g defau ``` Use `-r` to change the time limit per model (default 120s; an optional fourth column in `tests/baseline.txt` sets a model-specific time limit instead), `-t` for the relative tolerance (default 1e-6) and pass model names to run only a subset. The exit code is 1 if any model mismatches or fails to produce a solution. + +To run it on a Colab GPU against a branch of this repository, use [`tests/colab-gpu-test.ipynb`](tests/colab-gpu-test.ipynb). diff --git a/tests/colab-gpu-test.ipynb b/tests/colab-gpu-test.ipynb new file mode 100644 index 0000000..3954eb3 --- /dev/null +++ b/tests/colab-gpu-test.ipynb @@ -0,0 +1,184 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# cuOpt link GPU test on Colab\n", + "\n", + "Builds the GAMS/cuOpt link from a branch of this repository exactly like the x86_64 CI workflow, installs it into a fresh GAMS distribution and runs the GPU-dependent tests: a `trnsport` smoke test and `tests/test-gamslib-cuopt.py`.\n", + "\n", + "1. **Runtime > Change runtime type > T4 GPU** (any NVIDIA GPU works).\n", + "2. Optional: store a GAMS license as Colab secret `GAMS_LICENSE` (key icon in the left sidebar, paste the content of `gamslice.txt`, enable notebook access). Without it GAMS runs in demo mode and larger gamslib models fail on size limits.\n", + "3. Set the branch below and run all cells." + ] + }, + { + "cell_type": "code", + "metadata": {}, + "execution_count": null, + "outputs": [], + "source": [ + "BRANCH = \"claude/cuopt-wheels-pypi-j6l929\" # branch of GAMS-dev/cuoptlink-builder to build and test\n", + "CUDA = None # 12 or 13; None picks the newest one the GPU driver supports\n", + "MODELS = [] # gamslib models to test, empty list runs the full baseline\n", + "RESLIM = 120 # time limit per model in seconds" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "execution_count": null, + "outputs": [], + "source": [ + "import os, re, shutil, subprocess, sys\n", + "\n", + "smi = subprocess.run([\"nvidia-smi\"], capture_output=True, text=True)\n", + "if smi.returncode != 0:\n", + " raise SystemExit(\"No NVIDIA GPU found: select a GPU runtime (Runtime > Change runtime type)\")\n", + "print(smi.stdout)\n", + "driver_cuda = int(re.search(r\"CUDA Version:\\s*(\\d+)\", smi.stdout).group(1))\n", + "if CUDA is None:\n", + " CUDA = 13 if driver_cuda >= 13 else 12\n", + "if CUDA > driver_cuda:\n", + " raise SystemExit(f\"Driver supports CUDA {driver_cuda}, cannot run the CUDA {CUDA} build\")\n", + "print(f\"Testing the CUDA {CUDA} build\")" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "execution_count": null, + "outputs": [], + "source": [ + "WORK = \"/content/cuoptlink-builder\"\n", + "shutil.rmtree(WORK, ignore_errors=True)\n", + "subprocess.run([\"git\", \"clone\", \"-q\", \"--depth\", \"1\", \"-b\", BRANCH,\n", + " \"https://github.com/GAMS-dev/cuoptlink-builder\", WORK], check=True)\n", + "subprocess.run([sys.executable, \"-m\", \"pip\", \"install\", \"-q\", \"uv\", \"patchelf\", \"pyyaml\"], check=True)\n", + "print(subprocess.check_output([\"git\", \"-C\", WORK, \"log\", \"-1\", \"--format=%h %s\"], text=True))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Build like CI\n", + "\n", + "Runs the `run` steps of `.github/workflows/main-x86_64.yml` (venvs, GAMS download, compile, packaging) unchanged. `UV_PYTHON=3.13` makes the venvs match the `python3.13` paths the workflow uses. Takes a few minutes." + ] + }, + { + "cell_type": "code", + "metadata": {}, + "execution_count": null, + "outputs": [], + "source": [ + "import yaml\n", + "\n", + "wf = yaml.safe_load(open(f\"{WORK}/.github/workflows/main-x86_64.yml\"))\n", + "env = dict(os.environ, UV_PYTHON=\"3.13\")\n", + "for step in wf[\"jobs\"][\"build-link\"][\"steps\"]:\n", + " if \"run\" not in step or step.get(\"if\") or step[\"name\"].startswith(\"Install dependencies\"):\n", + " continue\n", + " print(\"===\", step[\"name\"], flush=True)\n", + " subprocess.run([\"bash\", \"-e\", \"-c\", step[\"run\"]], cwd=WORK, env=env, check=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install into the GAMS distribution" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "execution_count": null, + "outputs": [], + "source": [ + "GAMSDIST = f\"{WORK}/gamsdist\"\n", + "for src in (f\"{WORK}/release-cu{CUDA}\", f\"{WORK}/runtime-cu{CUDA}\"):\n", + " for name in os.listdir(src):\n", + " shutil.copy2(os.path.join(src, name), GAMSDIST)\n", + "shutil.copy2(f\"{GAMSDIST}/gamsconfig_cuopt.yaml\", f\"{GAMSDIST}/gamsconfig.yaml\")\n", + "\n", + "try:\n", + " from google.colab import userdata\n", + " lic = userdata.get(\"GAMS_LICENSE\")\n", + "except Exception:\n", + " lic = None\n", + "if lic:\n", + " with open(f\"{GAMSDIST}/gamslice.txt\", \"w\") as f:\n", + " f.write(lic.strip() + \"\\n\")\n", + " print(\"GAMS license installed\")\n", + "else:\n", + " print(\"No GAMS_LICENSE secret: GAMS runs in demo mode\")\n", + "os.environ[\"PATH\"] = GAMSDIST + os.pathsep + os.environ[\"PATH\"]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Smoke test: trnsport" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "execution_count": null, + "outputs": [], + "source": [ + "smoke = \"/content/smoke\"\n", + "shutil.rmtree(smoke, ignore_errors=True)\n", + "os.makedirs(smoke)\n", + "subprocess.run([f\"{GAMSDIST}/gamslib\", \"-q\", \"trnsport\"], cwd=smoke, check=True)\n", + "# GAMS ends normally even when the solver fails, so make a non-optimal solve abort the job\n", + "with open(f\"{smoke}/trnsport.gms\", \"a\") as f:\n", + " f.write(\"\\nabort$(transport.modelStat <> %modelStat.optimal%) 'cuOpt did not solve trnsport to optimality', transport.modelStat;\\n\")\n", + "r = subprocess.run([f\"{GAMSDIST}/gams\", \"trnsport\", \"lp=cuopt\", \"lo=3\"], cwd=smoke, capture_output=True, text=True)\n", + "print(r.stdout[-4000:])\n", + "if r.returncode != 0:\n", + " raise SystemExit(f\"trnsport failed with return code {r.returncode}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## gamslib regression test\n", + "\n", + "Solves the models in `tests/baseline.txt` with cuOpt and compares the objective with the CPLEX reference." + ] + }, + { + "cell_type": "code", + "metadata": {}, + "execution_count": null, + "outputs": [], + "source": [ + "r = subprocess.run([sys.executable, f\"{WORK}/tests/test-gamslib-cuopt.py\", \"-g\", GAMSDIST,\n", + " \"-r\", str(RESLIM), *MODELS], cwd=\"/content\")\n", + "print(\"PASSED\" if r.returncode == 0 else f\"FAILED (exit code {r.returncode})\")" + ] + } + ], + "metadata": { + "accelerator": "GPU", + "colab": { + "gpuType": "T4", + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + }, + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file From 25e038d1ed256a8f2bc3975bfae4a9936973b5bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Schnabel?= Date: Wed, 7 Oct 2026 07:38:53 +0200 Subject: [PATCH 4/4] tests: default Colab notebook branch to main --- tests/colab-gpu-test.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/colab-gpu-test.ipynb b/tests/colab-gpu-test.ipynb index 3954eb3..f3e87d5 100644 --- a/tests/colab-gpu-test.ipynb +++ b/tests/colab-gpu-test.ipynb @@ -19,7 +19,7 @@ "execution_count": null, "outputs": [], "source": [ - "BRANCH = \"claude/cuopt-wheels-pypi-j6l929\" # branch of GAMS-dev/cuoptlink-builder to build and test\n", + "BRANCH = \"main\" # branch of GAMS-dev/cuoptlink-builder to build and test\n", "CUDA = None # 12 or 13; None picks the newest one the GPU driver supports\n", "MODELS = [] # gamslib models to test, empty list runs the full baseline\n", "RESLIM = 120 # time limit per model in seconds"