Skip to content

cuda.bindings: support multiple CTK release lines on main - #2737

Draft
rwgk wants to merge 28 commits into
NVIDIA:mainfrom
rwgk:agent/cuda-bindings-12-on-main
Draft

cuda.bindings: support multiple CTK release lines on main#2737
rwgk wants to merge 28 commits into
NVIDIA:mainfrom
rwgk:agent/cuda-bindings-12-on-main

Conversation

@rwgk

@rwgk rwgk commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

REMINDER

Before merging, remove the temporary .lycheeignore before triggering final CI. It excludes only three canonical main/cuda_bindings_12 URLs that cannot resolve until this PR is merged. The authored-source lychee hook is skipped by CI, so removing the file will not prevent final CI from passing.

After merging, run pre-commit run lychee --all-files on fresh main to validate those links.

Summary

Closes #1199.

This PR continues and supersedes Keith Kraus's original PR #2675, cuda.bindings: build 12.9 and 13.x selectively from main. The bulk of the implementation and commit history originated there. PR #2675 was automatically closed only because its temporary pull-request/2467 base was deleted after #2467 merged. Its head branch is not maintainer-writable, so this replacement preserves that history on a writable fork, targets current main, and completes the redesign requested in the first review of this PR.

The result is one active development branch for multiple CUDA bindings release lines:

  • CUDA 12.9 and CUDA 13.3 bindings are built, tested, documented, and released from main.
  • CI and release orchestration obtain release-line details from one validated registry rather than treating 12, 13, current, and backport as interchangeable concepts.
  • The historical 12.9.x branch becomes a read-only release record; it is no longer an active backport or artifact-source branch.

This builds on the dependency-aware selective CI merged in #2467.

Release-line registry

ci/versions.yml is the authoritative mapping used by public CI and release tooling:

Line ID Role CTK target Source root Release-tag family
released-12 maintenance 12.9 cuda_bindings_12/ v12.9.*
released-13 current 13.3 cuda_bindings/ v13.3.*

Each line record also contains its exact toolkit pin and channel and its prerelease-tag policy. ci/tools/bindings_config.py validates the registry and emits normalized records for downstream consumers. Workflow logic selects records by stable line ID or by the current, maintenance, and unreleased roles; it does not infer a role from a directory name or CUDA major.

A release line and a CUDA ABI major are deliberately separate dimensions. For example, future 13.4 and 13.5 lines could retain distinct source roots, artifacts, and tests while both derive the cu13 ABI variant. The registry, selective-change planner, sdist jobs, release routing, and test-matrix validation are list-based and preserve that line identity. CUDA Core work is aggregated by ABI major only where that is valid.

The public monolithic wheel builder retains one explicit transitional boundary: it currently requires exactly one current line and one maintenance line with different CUDA ABI majors. Unsupported registry shapes fail closed. Generalizing that job for multiple maintenance lines or multiple same-major lines is a separate, reviewer-visible change rather than implicit behavior in this PR.

The unreleased role is empty in the public repository. A future ctk-next overlay may populate it, but overlay merging and promotion are intentionally outside this PR.

Source layout and maintenance model

The filesystem names describe their contents; the registry describes their role at a particular time:

  • cuda_bindings/ contains the released CUDA 13 line.
  • cuda_bindings_12/ contains the released CUDA 12.9 line.
  • current and maintenance remain indirections in ci/versions.yml, not aliases embedded in the directory names.

This keeps a directory from silently changing meaning across a major-version transition. Advancing the release lines is an explicit registry and source-tree change, while consumers continue selecting roles through the registry.

The two complete package roots are an intentional transitional design. Most of cuda_bindings_12/ is imported from NVIDIA/cuda-python@238955935bd903ac72817c0dfdfe4f6a54ee6bb1:cuda_bindings. cuda_bindings_12/MAINTENANCE.md records its ownership and generation provenance, including the portion reproduced by cybind commit 95d8bb525de46a9ff7ae40d759a98cbe50cf8391.

ci/cuda-bindings-shared-files.json lists the small handwritten subset that must remain byte-identical across public roots, and a pre-commit/CI checker enforces it. Generated files are guarded by their content seals and generation provenance instead of being incorrectly required to match across CTK targets. For every later bindings fix, contributors must update every applicable root or document concretely why a line is unaffected.

Build, test, and release behavior

Change or event Result
Source change under one registered bindings root Build and test that bindings line and its matching cuda-python package; exercise the relevant CUDA Core ABI as needed
Shared bindings consumer or CI/release infrastructure change Exercise all public release lines affected by the shared change
v12.9.* release tag Select the registered CUDA 12.9 bindings/metapackage pair
v13.3.* release tag Select the registered CUDA 13.3 bindings/metapackage pair

Release selection is based on the registry stored in the tagged source tree. A compatibility path supports older tags created before schema 2, when their source tree still used the generic cuda_bindings/ directory.

A single commit may carry one CUDA 12.9 release tag and one CUDA 13.3 release tag. Each tag independently selects the matching line, package root, metadata, and artifacts. The current implementation still uses one tag-triggered release run per line; releasing both lines in one run is not required by this PR. As usual, two different releases from the same tag family should not be placed on one commit.

CUDA 12 development versions advance normally after the stable v12.9.8 tag becomes reachable instead of remaining forced to 12.9.8.dev0 indefinitely.

Decisions requested from reviewers

Please explicitly accept or reject these policies:

  1. main is the sole active source of truth. The historical 12.9.x branch receives no further routine or emergency backports. Applicable CUDA 12 fixes are made in cuda_bindings_12/ on main alongside any corresponding current-line change.
  2. Released bindings use explicit, versioned source roots. Role indirection belongs in ci/versions.yml; directory names state which generation they contain. The present full-root duplication is transitional and is not precedent for automatically adding every future same-major CTK minor to the public repository.
  3. Extensibility is represented honestly. The registry and planners model ordered lists of release lines, including same-major lines, while the wheel builder explicitly rejects shapes it cannot yet execute. Support for private unreleased overlays and a generalized multi-line wheel build remain future work.

The later generated NVML memoryview fix discussed in the first review is not part of this PR; it should be handled independently if a CUDA 12 backport is needed.

Review map

The high-value review surface is outside the imported CUDA 12 tree:

  • Registry and semantics: ci/versions.yml, ci/tools/bindings_config.py, and their tests.
  • Selective planning: ci/tools/compute_ci_plan.py, matrix validation, and their tests.
  • Build and test routing: GitHub workflows plus the artifact, environment, and wheel helpers under ci/tools/.
  • Release routing and versioning: release workflows, tag resolution, release-note validation, and maintenance-line SCM handling.
  • Cross-root safety: ci/cuda-bindings-shared-files.json, its checker, and cuda_bindings_12/MAINTENANCE.md.

Most files under cuda_bindings_12/ are the direct CUDA 12.9 import from Keith's PR #2675. Differences from cuda_bindings/ are generally target- or generation-specific and intentional; the maintenance document and later focused commits identify the reviewable post-import adjustments.

Validation

  • pre-commit run --all-files, including registry validation, shared-file checks, generated-file seals, Ruff, actionlint, YAML/TOML/RST checks, and lychee with the temporary three-URL exception described in the REMINDER
  • CUDA 13.3 Linux QA source build, including editable installs and Cython test-extension builds for cuda.bindings and cuda.core
  • 159 CI-tool unit tests covering registry validation, role and line selection, same-major line identity, selective build/test planning, tag matching, tagged-tree and legacy release resolution, SCM behavior, artifact lookup/downloads, matrix validation, and release-wheel validation
  • archive/version smoke tests with real v12.9.7, v13.3.1, and v13.4.0b1 tags, including independent release-family selection when different tag families point to the same commit
  • CUDA 12 source-build/import, Cython-extension, dependency-metadata, and environment-routing smoke validation inherited from Keith's PR cuda.bindings: build 12.9 and 13.x selectively from main #2675 and repeated for this replacement
  • Full gated GitHub Actions matrix on review head f4ddc4e: run 33456145474 passed; one self-hosted runner disconnect was rerun successfully

Out of scope

  • Refactoring generated target-specific content into overlays or otherwise eliminating the two complete released package roots
  • Adding public 13.4/13.5 source roots or implementing the private ctk-next overlay/promotion mechanism
  • Generalizing the monolithic wheel builder to multiple maintenance lines or multiple lines sharing one CUDA ABI major
  • Combining multiple release tags into a single release workflow run

Checklist

  • New or existing tests cover these changes.
  • Documentation is updated for the new maintenance and release-line model.

@rwgk rwgk added this to the cuda.bindings 13.5.0 & 12.9.10 milestone Aug 31, 2026
@rwgk rwgk added enhancement Any code-related improvements CI/CD CI/CD infrastructure cuda.bindings Everything related to the cuda.bindings module labels Aug 31, 2026
@rwgk rwgk self-assigned this Aug 31, 2026
@copy-pr-bot

copy-pr-bot Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

rwgk commented Aug 31, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test b87d0a1

@github-actions

Copy link
Copy Markdown

@mdboom mdboom left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I started to comment on some individual things, but then decided to stop because I think there is a more fundamental change that needs to be made across this whole PR (and then I'm happy to come back and review further).

/Today/ the "current" version is 13, and the backport version is 12. But at some point in the future that will switch to 14 and 13. This pervasively hardcodes those version numbers all over this codebase, especially in CI, but in a bunch of the release scripts as well, and even the cuda_bindings_12 directory name as indicators of current vs. backport.

Instead, we should use the config we already have in versions.yml and use that to drive the numbers everywhere. That way when it's time to move on, all that should be required is updating versions.yml, and copying/overwriting the existing cuda_bindings to cuda_bindings_backport (or whatever we want to call it), and move on. I'm sure there are many details I'm missing, but that should be the goal and design -- it would be preferable to reduce it to as close to that as possible. The problem with this as-is is that there are hundreds of context-sensitive places that would need to be updated to do that update -- we are creating a massive pile of technical debt to pay later. I'm sure an agent might get that X% correct, but I always think it's better to engineer for flexibility, especially for something we know will happen. If versions.yml (which requires using yq to parse etc.) makes this too difficult, we could explore a simple VARIABLE=value format which would parse as both bash variables and Python variables and probably be more convenient to use from the many places it is needed. There are really only two actual values in versions.yml today, so that should be fine.

I'm also a little concerned (without any testing-based evidence) that this will break when we tag the same commit with v13.x.y and v12.x.y, which will be the common case, in fact, IMHO, one of the real benefits of moving to this approach. We should get an agent to do a thorough investigation of that use case and make sure it is covered. Ideally, it would be nice for a single release run to do both releases simultaneously but it's not a deal breaker if it still requires kicking off two runs.

Also what is this (from the agent's PR description):

The later NVML memoryview fix is reproduced byte-for-byte from cybind commit
6def52ca508c9e14ef67f4ce26a0c677f3fbad72 with Doxygen 1.17.0:

If there is something like this that wasn't backported, let's deal with that separately so it's not an unrelated tag-along to this PR.

Also a note for future agent reviewers of this PR: The interesting part of this PR is the part outside of the cuda_bindings_backport or cuda_bindings_12 directory. Those are just direct copies from the 12.9.x branch, and any differences between that and the cuda_bindings directory are likely intentional. When reviewing, focus on the scaffolding / CI / overall structure.

Comment thread .github/workflows/backport.yml Outdated
Comment thread .github/workflows/build-wheel.yml Outdated
Comment thread ci/cuda-bindings-shared-files.json Outdated
Comment thread ci/cuda-bindings-shared-files.json Outdated
Comment thread ci/ci-pipeline.svg
Comment thread cuda_python/docs/environment-docs.yml
Comment thread ci/tools/check_cuda_bindings_shared_files.py
@rwgk rwgk changed the title cuda.bindings: build 12.9 and 13.x selectively from main cuda.bindings: support multiple CTK release lines on main Aug 31, 2026
@rwgk

rwgk commented Aug 31, 2026

Copy link
Copy Markdown
Contributor Author

Archiving options related to a lychee chicken-and-egg issue. I'll go with Option 1 below. This comment is to explain why.


codex:

We have three sensible options. For PR 2737, I recommend keeping the canonical links unchanged and treating these as documented pre-merge exceptions.

  1. One-off exact exclusions — recommended

Run lychee once with only these three URLs excluded, record that every other link passes, and rerun without exclusions after merge.

This is reasonable because authored-source lychee is explicitly skipped by the GitHub CI job at .github/workflows/ci.yml, so these are not merge-gating failures. It avoids landing temporary configuration or compromising the final URLs.

  1. Temporary .lycheeignore

Add three exact anchored patterns so pre-commit run --all-files is completely green, then remove them immediately after merging. Lychee officially supports checked-in, commented exclusions via .lycheeignore. Lychee exclusion documentation

This is practical, but creates a mandatory cleanup PR and briefly leaves three blind spots on main.

  1. Permanent local remapping

Teach the hook to map:

https://github.com/NVIDIA/cuda-python/{tree,blob}/main/<path>
→ file://<current-worktree>/<path>

Then links to newly introduced files are validated against the checkout before they exist online. This is exactly the future-URL use case for lychee’s remapping feature. Lychee remapping documentation

It is the principled reusable solution, but needs a portable wrapper to calculate the absolute worktree path. I would pursue it separately only if this problem starts recurring.

I would avoid:

  • Accepting all 404 responses; lychee’s setting is global.
  • Excluding the entire cuda_bindings_12 subtree or source files.
  • Replacing the links with fork, PR, SHA, or repository-root URLs; those are inferior permanent package metadata.
  • Splitting out a bootstrap PR solely to make the paths exist.

So my recommendation is option 1: preserve the three correct final URLs, validate everything else with exact one-off exclusions, and rerun lychee from fresh main after merging.

@github-actions github-actions Bot added cuda.core Everything related to the cuda.core module cuda.pathfinder Everything related to the cuda.pathfinder module labels Sep 1, 2026
@rwgk

rwgk commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test f4ddc4e

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CI/CD CI/CD infrastructure cuda.bindings Everything related to the cuda.bindings module cuda.core Everything related to the cuda.core module cuda.pathfinder Everything related to the cuda.pathfinder module enhancement Any code-related improvements

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Revisit cuda-bindings branching strategy

3 participants