Skip to content

Commit 6134171

Browse files
rparolinclaude
andauthored
fix(cuda.core): warn instead of silently dropping numba_debug on link paths (#2658)
`LinkerOptions` carries a public `numba_debug` field that no linking backend reads. nvJitLink rejects the option under every spelling and the driver's cuLink API has no corresponding `CUjit_option`, so setting it does nothing and reports nothing. It is not merely dead: `_translate_program_options` forwarded `numba_debug` from `ProgramOptions` into `LinkerOptions` on the `code_type="ptx"` path, so `Program(ptx, "ptx", ProgramOptions(numba_debug=True))` silently discarded an option the user explicitly set. Make the drop audible without breaking any caller: - `LinkerOptions.numba_debug` is deprecated. Setting it emits a `DeprecationWarning` from `__post_init__` and the value is still ignored. The field stays, so no constructor signature changes. - `_translate_program_options` no longer forwards it and emits a `UserWarning` saying it is ignored for `code_type="ptx"`. `UserWarning` rather than `DeprecationWarning` because `ProgramOptions.numba_debug` is not deprecated -- it is fully supported on NVVM and NVRTC and merely inapplicable to a linking backend. - The option builders are untouched; the linker needs no knowledge of `numba_debug` to ignore it. - `_LinkerBackend.validate` rejects nothing, and `numba_debug` stays out of `_LINKER_FIELD_GATES`: it cannot change PTX-path output, so it must not perturb the program-cache key. The warning gates differ on purpose. The linker field uses `is not None` -- the field itself is going away, so any explicit value earns the notice, including `False`. The PTX path uses truthiness, matching `_prepare_nvvm_options_impl`, because `False` asks for nothing. Removal of `LinkerOptions.numba_debug` is deferred to 2.0.0: the support policy confines breaking API changes to major-version boundaries and requires a deprecation notice at least one minor release ahead. Nothing in the repo tracks a scheduled removal -- the existing precedent (`Device.max_links`) only says "a future release" -- so a version-gated test fails the build once the version crosses 2.0. The NVVM and NVRTC paths are unchanged and still emit the option. Closes #2640 Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 1766775 commit 6134171

11 files changed

Lines changed: 198 additions & 7 deletions

File tree

‎.github/ISSUE_TEMPLATE/release_checklist.yml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ body:
2020
- label: File an internal nvbug to communicate test plan & release schedule with QA
2121
- label: Ensure all pending PRs are reviewed, tested, and merged
2222
- label: Check (or update if needed) the dependency requirements
23+
- label: Sweep deprecations whose stated removal version has arrived (`grep -rn 'deprecated::' cuda_core/cuda`) and remove any that are due
2324
- label: "Finalize the doc update, including release notes (\"Note: Touching docstrings/type annotations in code is OK during code freeze, apply your best judgement!\")"
2425
- label: Update the docs for the new version
2526
- label: Create a public release tag

‎.github/RELEASE-core.md‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,27 @@ requirements are current.
6666

6767
---
6868

69+
## Sweep deprecations whose removal version has arrived
70+
71+
Deprecated APIs are marked in the source with a Sphinx `deprecated`
72+
directive naming the version that introduced the deprecation, and their
73+
docstrings state the version in which they will be removed. Find them all
74+
with:
75+
76+
```console
77+
$ grep -rn 'deprecated::' cuda_core/cuda
78+
```
79+
80+
For each hit, check the stated removal version against the version being
81+
released. If the release has reached or passed it, remove the API, its
82+
runtime `DeprecationWarning`, and any tests asserting that warning.
83+
84+
This must happen *before* the release tag is cut. Removals are breaking
85+
changes, so they are only permitted at a major-version boundary per the
86+
[support policy](https://nvidia.github.io/cuda-python/cuda-core/latest/support.html).
87+
88+
---
89+
6990
## Finalize the doc update, including release notes
7091

7192
Review every PR included in the release. For each one, check whether new

‎cuda_core/cuda/core/_linker.pyi‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,18 @@ class LinkerOptions:
177177
no_cache : bool, optional
178178
Do not cache the intermediate steps of nvJitLink.
179179
Default: False.
180+
numba_debug : bool, optional
181+
Non-functional. ``numba_debug`` is an NVVM/NVRTC *compiler* option;
182+
neither nvJitLink nor the driver's cuLink API recognizes it, so no
183+
linking backend can honor it and the value is ignored.
184+
Default: None.
185+
186+
.. deprecated:: 1.2.0
187+
Setting this option emits a :class:`DeprecationWarning`. It has never
188+
had an effect on any linking backend and will be removed in
189+
``cuda.core`` 2.0.0. Use
190+
:attr:`ProgramOptions.numba_debug` on an NVVM or NVRTC compilation
191+
path instead.
180192
"""
181193
name: str | None = '<default linker>'
182194
arch: str | None = None

‎cuda_core/cuda/core/_linker.pyx‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,18 @@ class LinkerOptions:
283283
no_cache : bool, optional
284284
Do not cache the intermediate steps of nvJitLink.
285285
Default: False.
286+
numba_debug : bool, optional
287+
Non-functional. ``numba_debug`` is an NVVM/NVRTC *compiler* option;
288+
neither nvJitLink nor the driver's cuLink API recognizes it, so no
289+
linking backend can honor it and the value is ignored.
290+
Default: None.
291+
292+
.. deprecated:: 1.2.0
293+
Setting this option emits a :class:`DeprecationWarning`. It has never
294+
had an effect on any linking backend and will be removed in
295+
``cuda.core`` 2.0.0. Use
296+
:attr:`ProgramOptions.numba_debug` on an NVVM or NVRTC compilation
297+
path instead.
286298
"""
287299

288300
name: str | None = "<default linker>"
@@ -311,6 +323,21 @@ class LinkerOptions:
311323
def __post_init__(self) -> None:
312324
_lazy_init()
313325
self._name = self.name.encode()
326+
# No linking backend reads ``numba_debug``, so warn where the value is
327+
# supplied rather than in the option builders -- the user learns once,
328+
# at the call site that set it, instead of once per link. The gate is
329+
# ``is not None`` (unlike the ignore-warning on the PTX compile path):
330+
# it is the *field* that is going away, so any explicit value earns the
331+
# notice, including ``False``.
332+
if self.numba_debug is not None:
333+
warn(
334+
"numba_debug is not supported by any linking backend and is ignored. "
335+
"LinkerOptions.numba_debug is deprecated and will be removed in "
336+
"cuda.core 2.0.0; use ProgramOptions.numba_debug on an NVVM or NVRTC "
337+
"compilation path instead.",
338+
DeprecationWarning,
339+
stacklevel=3,
340+
)
314341

315342
def _prepare_nvjitlink_options(self, as_bytes: bool = False) -> list[bytes] | list[str]:
316343
options = []

‎cuda_core/cuda/core/_program.pyi‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -316,8 +316,11 @@ class ProgramOptions:
316316
numba_debug : bool, optional
317317
Emit the debug information layout expected by Numba. Recognized only by
318318
newer toolkits; compilers that do not support it reject the option with
319-
an error.
320-
Default: False
319+
an error. Applies only to the NVVM and NVRTC compilation backends --
320+
``code_type="ptx"`` is processed by the linker, which cannot honor it,
321+
so enabling this option there emits a :class:`UserWarning` and the
322+
option is ignored.
323+
Default: None
321324
"""
322325
name: str | None = 'default_program'
323326
arch: str | None = None

‎cuda_core/cuda/core/_program.pyx‎

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -469,8 +469,11 @@ class ProgramOptions:
469469
numba_debug : bool, optional
470470
Emit the debug information layout expected by Numba. Recognized only by
471471
newer toolkits; compilers that do not support it reject the option with
472-
an error.
473-
Default: False
472+
an error. Applies only to the NVVM and NVRTC compilation backends --
473+
``code_type="ptx"`` is processed by the linker, which cannot honor it,
474+
so enabling this option there emits a :class:`UserWarning` and the
475+
option is ignored.
476+
Default: None
474477
"""
475478

476479
name: str | None = "default_program"
@@ -732,6 +735,21 @@ cpdef bint _can_load_generated_ptx() except? -1:
732735

733736
cdef inline object _translate_program_options(object options):
734737
"""Translate ProgramOptions to LinkerOptions for PTX compilation."""
738+
# ``numba_debug`` is an NVVM/NVRTC compiler option that no linking backend can
739+
# honor. It used to be forwarded into ``LinkerOptions`` and dropped without a
740+
# word; warn instead, and do not forward -- forwarding would only trigger the
741+
# deprecation warning on a field the user never touched. ``UserWarning``, not
742+
# ``DeprecationWarning``: ``ProgramOptions.numba_debug`` is not deprecated, it
743+
# is fully supported on NVVM and NVRTC and merely inapplicable here. The gate
744+
# is truthiness, matching ``_prepare_nvvm_options_impl``: only an enabled
745+
# ``numba_debug`` asks for something this path cannot deliver.
746+
if options.numba_debug:
747+
warn(
748+
"numba_debug is ignored for code_type='ptx', which is processed by the linker; "
749+
"it applies only to the NVVM and NVRTC compilation backends.",
750+
UserWarning,
751+
stacklevel=4,
752+
)
735753
return LinkerOptions(
736754
name=options.name,
737755
arch=options.arch,
@@ -747,7 +765,6 @@ cdef inline object _translate_program_options(object options):
747765
split_compile=options.split_compile,
748766
ptxas_options=options.ptxas_options,
749767
no_cache=options.no_cache,
750-
numba_debug = options.numba_debug
751768
)
752769

753770

‎cuda_core/cuda/core/utils/_program_cache/_keys.py‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,11 @@ def validate(self, options: ProgramOptions, target_type: str, extra_digest: byte
499499
raise ValueError(
500500
"extra_sources is only valid for code_type='nvvm'; Program() rejects it for code_type='ptx'."
501501
)
502+
# ``numba_debug`` is deliberately not rejected here and is absent from
503+
# ``_LINKER_FIELD_GATES``: for PTX inputs the linker ignores it (with a
504+
# warning from ``_translate_program_options``), so it cannot change the
505+
# generated code and must not perturb the key. Two PTX compiles that
506+
# differ only in ``numba_debug`` are the same compile.
502507
# PTX compiles go through the Linker. When the driver (cuLink)
503508
# backend is selected (nvJitLink unavailable), ``Program.compile``
504509
# rejects a subset of options that nvJitLink would accept; reject

‎cuda_core/docs/source/release/1.2.0-notes.rst‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,9 +157,34 @@ Fixes and enhancements
157157
still reports ``NVVM_ERROR_INVALID_OPTION``.
158158
(closes `#2570 <https://github.com/NVIDIA/cuda-python/issues/2570>`__)
159159

160+
- ``Program(ptx, "ptx", ProgramOptions(numba_debug=True))`` now warns that the
161+
option is ignored instead of discarding it silently. ``numba_debug`` is an
162+
NVVM/NVRTC *compiler* option: nvJitLink rejects it with
163+
``ERROR_UNRECOGNIZED_OPTION`` under every spelling, and the driver's
164+
``cuLink`` API has no corresponding ``CUjit_option``, so no linking backend
165+
can honor it. PTX inputs are handed to the linker, and the option used to be
166+
forwarded into ``LinkerOptions`` and then dropped without a diagnostic. The
167+
warning is a :class:`UserWarning`, not a :class:`DeprecationWarning` --
168+
``ProgramOptions.numba_debug`` is not deprecated and remains fully supported
169+
on the NVVM and NVRTC compilation paths, where it takes effect; it is simply
170+
inapplicable to a linking backend. The gate is truthiness, matching how the
171+
NVVM path gates emission, so ``numba_debug=False`` asks for nothing and is
172+
not worth a warning.
173+
(closes `#2640 <https://github.com/NVIDIA/cuda-python/issues/2640>`__)
174+
160175
Deprecation Notices
161176
-------------------
162177

178+
- ``LinkerOptions.numba_debug`` is deprecated and will be removed in
179+
``cuda.core`` 2.0.0. It was exposed in ``cuda-core`` 1.1.0 but no linking
180+
backend ever read it, so setting it has never had any effect;
181+
``numba_debug`` is an NVVM/NVRTC compiler option with no linker equivalent.
182+
Setting it now emits a :class:`DeprecationWarning` and the value continues
183+
to be ignored. Removal waits for the next major version because the
184+
:doc:`support policy <../support>` confines breaking API changes to
185+
major-version boundaries. Use :attr:`ProgramOptions.numba_debug` on an NVVM
186+
or NVRTC compilation path instead.
187+
163188
- Support for using ``cuda-core`` with Python 3.10 is deprecated and will be
164189
removed in a future version. Python 3.10 reaches end of life in October 2026
165190
per the `CPython support cycle <https://devguide.python.org/versions/>`_.

‎cuda_core/tests/test_linker.py‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# SPDX-License-Identifier: Apache-2.0
44

55
import inspect
6+
import warnings
67

78
import pytest
89

@@ -436,6 +437,41 @@ def test_prepare_driver_options_unsupported_raises(driver_binding, kwargs, match
436437
opts._prepare_driver_options()
437438

438439

440+
@pytest.mark.agent_authored(model="claude-opus-5")
441+
@pytest.mark.parametrize("value", [True, False])
442+
def test_numba_debug_warns_and_is_ignored(value):
443+
"""No linking backend reads ``numba_debug``, so it is ignored -- but not
444+
silently, which was the bug in #2640.
445+
446+
The gate is ``is not None``, not truthiness: it is the field itself that is
447+
deprecated, so ``numba_debug=False`` earns the notice too even though it
448+
asks for nothing.
449+
"""
450+
with pytest.warns(DeprecationWarning, match="numba_debug is not supported by any linking backend"):
451+
opts = LinkerOptions(arch="sm_80", debug=True, numba_debug=value)
452+
# Warned, not rejected, and the rest of the option set is untouched.
453+
assert opts._prepare_nvjitlink_options(as_bytes=True) == [b"-arch=sm_80", b"-g"]
454+
455+
456+
@pytest.mark.agent_authored(model="claude-opus-5")
457+
def test_numba_debug_unset_does_not_warn():
458+
"""The deprecation notice fires only when the field is explicitly set."""
459+
with warnings.catch_warnings():
460+
warnings.simplefilter("error", DeprecationWarning)
461+
options = LinkerOptions(arch="sm_80", debug=True)._prepare_nvjitlink_options(as_bytes=True)
462+
assert options == [b"-arch=sm_80", b"-g"]
463+
464+
465+
@pytest.mark.agent_authored(model="claude-opus-5")
466+
def test_numba_debug_ignored_by_driver_backend_too(driver_binding):
467+
"""The cuLink driver API has no CUjit_option for numba_debug either, so it
468+
is ignored there as well rather than reaching the driver."""
469+
with pytest.warns(DeprecationWarning, match="numba_debug"):
470+
opts = LinkerOptions(arch="sm_80", numba_debug=True)
471+
formatted_options, option_keys = opts._prepare_driver_options()
472+
assert not any("NUMBA" in str(key) for key in option_keys)
473+
474+
439475
def test_linker_empty_object_codes_raises():
440476
"""Linker with no ObjectCode raises ValueError."""
441477
with pytest.raises(ValueError, match="At least one ObjectCode object must be provided"):

‎cuda_core/tests/test_program.py‎

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -316,8 +316,10 @@ def test_cpp_program_pch_status_none_without_pch(init_cuda):
316316
ProgramOptions(prec_div=True),
317317
ProgramOptions(prec_sqrt=True),
318318
ProgramOptions(fma=True),
319-
# Plumb-through; no-op at link time. See #1287.
320-
ProgramOptions(debug=True, numba_debug=True),
319+
# ``numba_debug`` is deliberately absent: it was listed here as a link-time
320+
# no-op (#1287), but no linker backend accepts it, so it was dropped
321+
# silently (#2640). The PTX path now warns; see
322+
# test_ptx_program_numba_debug_warns_and_is_ignored.
321323
]
322324
if not is_culink_backend:
323325
options += [
@@ -870,6 +872,34 @@ def test_ptx_program_extra_sources_unsupported(ptx_code_object):
870872
Program(ptx_code_object.code.decode(), "ptx", options)
871873

872874

875+
@pytest.mark.agent_authored(model="claude-opus-5")
876+
def test_ptx_program_numba_debug_warns_and_is_ignored(init_cuda, ptx_code_object):
877+
"""PTX inputs go to the linker, which cannot honor numba_debug (#2640).
878+
879+
It used to be forwarded into ``LinkerOptions`` and dropped without a word,
880+
so the compile appeared to succeed with the option applied. It is still
881+
ignored -- no linker can do anything with it -- but no longer silently.
882+
883+
``UserWarning``, not ``DeprecationWarning``: ``ProgramOptions.numba_debug``
884+
is not deprecated, it is supported on NVVM/NVRTC and merely inapplicable to
885+
this backend.
886+
"""
887+
with pytest.warns(UserWarning, match="numba_debug is ignored for code_type='ptx'"):
888+
program = Program(ptx_code_object.code.decode(), "ptx", ProgramOptions(numba_debug=True))
889+
assert program.compile("cubin") is not None
890+
891+
892+
@pytest.mark.agent_authored(model="claude-opus-5")
893+
@pytest.mark.parametrize("value", [None, False])
894+
def test_ptx_program_numba_debug_unset_or_false_does_not_warn(init_cuda, ptx_code_object, value):
895+
"""The gate is truthiness: only an enabled ``numba_debug`` asks for
896+
something the PTX path cannot deliver, so ``False`` is not worth a warning."""
897+
with warnings.catch_warnings():
898+
warnings.simplefilter("error", UserWarning)
899+
program = Program(ptx_code_object.code.decode(), "ptx", ProgramOptions(numba_debug=value))
900+
assert program.compile("cubin") is not None
901+
902+
873903
def test_ptx_program_handle_is_linker_handle(init_cuda, ptx_code_object):
874904
"""Program.handle for the PTX backend delegates to the linker handle."""
875905
program = Program(ptx_code_object.code.decode(), "ptx")

0 commit comments

Comments
 (0)