diff --git a/.github/ISSUE_TEMPLATE/release_checklist.yml b/.github/ISSUE_TEMPLATE/release_checklist.yml index f7307fbe92a..1edc0e9e12b 100644 --- a/.github/ISSUE_TEMPLATE/release_checklist.yml +++ b/.github/ISSUE_TEMPLATE/release_checklist.yml @@ -20,6 +20,7 @@ body: - label: File an internal nvbug to communicate test plan & release schedule with QA - label: Ensure all pending PRs are reviewed, tested, and merged - label: Check (or update if needed) the dependency requirements + - label: Sweep deprecations whose stated removal version has arrived (`grep -rn 'deprecated::' cuda_core/cuda`) and remove any that are due - label: "Finalize the doc update, including release notes (\"Note: Touching docstrings/type annotations in code is OK during code freeze, apply your best judgement!\")" - label: Update the docs for the new version - label: Create a public release tag diff --git a/.github/RELEASE-core.md b/.github/RELEASE-core.md index 01e182c76ef..72472a42fdc 100644 --- a/.github/RELEASE-core.md +++ b/.github/RELEASE-core.md @@ -66,6 +66,27 @@ requirements are current. --- +## Sweep deprecations whose removal version has arrived + +Deprecated APIs are marked in the source with a Sphinx `deprecated` +directive naming the version that introduced the deprecation, and their +docstrings state the version in which they will be removed. Find them all +with: + +```console +$ grep -rn 'deprecated::' cuda_core/cuda +``` + +For each hit, check the stated removal version against the version being +released. If the release has reached or passed it, remove the API, its +runtime `DeprecationWarning`, and any tests asserting that warning. + +This must happen *before* the release tag is cut. Removals are breaking +changes, so they are only permitted at a major-version boundary per the +[support policy](https://nvidia.github.io/cuda-python/cuda-core/latest/support.html). + +--- + ## Finalize the doc update, including release notes Review every PR included in the release. For each one, check whether new diff --git a/cuda_core/cuda/core/_linker.pyi b/cuda_core/cuda/core/_linker.pyi index 42b08313f78..e2eaef90556 100644 --- a/cuda_core/cuda/core/_linker.pyi +++ b/cuda_core/cuda/core/_linker.pyi @@ -177,6 +177,18 @@ class LinkerOptions: no_cache : bool, optional Do not cache the intermediate steps of nvJitLink. Default: False. + numba_debug : bool, optional + Non-functional. ``numba_debug`` is an NVVM/NVRTC *compiler* option; + neither nvJitLink nor the driver's cuLink API recognizes it, so no + linking backend can honor it and the value is ignored. + Default: None. + + .. deprecated:: 1.2.0 + Setting this option emits a :class:`DeprecationWarning`. It has never + had an effect on any linking backend and will be removed in + ``cuda.core`` 2.0.0. Use + :attr:`ProgramOptions.numba_debug` on an NVVM or NVRTC compilation + path instead. """ name: str | None = '' arch: str | None = None diff --git a/cuda_core/cuda/core/_linker.pyx b/cuda_core/cuda/core/_linker.pyx index 0687632c3bb..9e14a789f95 100644 --- a/cuda_core/cuda/core/_linker.pyx +++ b/cuda_core/cuda/core/_linker.pyx @@ -283,6 +283,18 @@ class LinkerOptions: no_cache : bool, optional Do not cache the intermediate steps of nvJitLink. Default: False. + numba_debug : bool, optional + Non-functional. ``numba_debug`` is an NVVM/NVRTC *compiler* option; + neither nvJitLink nor the driver's cuLink API recognizes it, so no + linking backend can honor it and the value is ignored. + Default: None. + + .. deprecated:: 1.2.0 + Setting this option emits a :class:`DeprecationWarning`. It has never + had an effect on any linking backend and will be removed in + ``cuda.core`` 2.0.0. Use + :attr:`ProgramOptions.numba_debug` on an NVVM or NVRTC compilation + path instead. """ name: str | None = "" @@ -311,6 +323,21 @@ class LinkerOptions: def __post_init__(self) -> None: _lazy_init() self._name = self.name.encode() + # No linking backend reads ``numba_debug``, so warn where the value is + # supplied rather than in the option builders -- the user learns once, + # at the call site that set it, instead of once per link. The gate is + # ``is not None`` (unlike the ignore-warning on the PTX compile path): + # it is the *field* that is going away, so any explicit value earns the + # notice, including ``False``. + if self.numba_debug is not None: + warn( + "numba_debug is not supported by any linking backend and is ignored. " + "LinkerOptions.numba_debug is deprecated and will be removed in " + "cuda.core 2.0.0; use ProgramOptions.numba_debug on an NVVM or NVRTC " + "compilation path instead.", + DeprecationWarning, + stacklevel=3, + ) def _prepare_nvjitlink_options(self, as_bytes: bool = False) -> list[bytes] | list[str]: options = [] diff --git a/cuda_core/cuda/core/_program.pyi b/cuda_core/cuda/core/_program.pyi index fd40aae069f..8a2aff48752 100644 --- a/cuda_core/cuda/core/_program.pyi +++ b/cuda_core/cuda/core/_program.pyi @@ -316,8 +316,11 @@ class ProgramOptions: numba_debug : bool, optional Emit the debug information layout expected by Numba. Recognized only by newer toolkits; compilers that do not support it reject the option with - an error. - Default: False + an error. Applies only to the NVVM and NVRTC compilation backends -- + ``code_type="ptx"`` is processed by the linker, which cannot honor it, + so enabling this option there emits a :class:`UserWarning` and the + option is ignored. + Default: None """ name: str | None = 'default_program' arch: str | None = None diff --git a/cuda_core/cuda/core/_program.pyx b/cuda_core/cuda/core/_program.pyx index 16094fa0c14..1d07b88bbf4 100644 --- a/cuda_core/cuda/core/_program.pyx +++ b/cuda_core/cuda/core/_program.pyx @@ -469,8 +469,11 @@ class ProgramOptions: numba_debug : bool, optional Emit the debug information layout expected by Numba. Recognized only by newer toolkits; compilers that do not support it reject the option with - an error. - Default: False + an error. Applies only to the NVVM and NVRTC compilation backends -- + ``code_type="ptx"`` is processed by the linker, which cannot honor it, + so enabling this option there emits a :class:`UserWarning` and the + option is ignored. + Default: None """ name: str | None = "default_program" @@ -732,6 +735,21 @@ cpdef bint _can_load_generated_ptx() except? -1: cdef inline object _translate_program_options(object options): """Translate ProgramOptions to LinkerOptions for PTX compilation.""" + # ``numba_debug`` is an NVVM/NVRTC compiler option that no linking backend can + # honor. It used to be forwarded into ``LinkerOptions`` and dropped without a + # word; warn instead, and do not forward -- forwarding would only trigger the + # deprecation warning on a field the user never touched. ``UserWarning``, not + # ``DeprecationWarning``: ``ProgramOptions.numba_debug`` is not deprecated, it + # is fully supported on NVVM and NVRTC and merely inapplicable here. The gate + # is truthiness, matching ``_prepare_nvvm_options_impl``: only an enabled + # ``numba_debug`` asks for something this path cannot deliver. + if options.numba_debug: + warn( + "numba_debug is ignored for code_type='ptx', which is processed by the linker; " + "it applies only to the NVVM and NVRTC compilation backends.", + UserWarning, + stacklevel=4, + ) return LinkerOptions( name=options.name, arch=options.arch, @@ -747,7 +765,6 @@ cdef inline object _translate_program_options(object options): split_compile=options.split_compile, ptxas_options=options.ptxas_options, no_cache=options.no_cache, - numba_debug = options.numba_debug ) diff --git a/cuda_core/cuda/core/utils/_program_cache/_keys.py b/cuda_core/cuda/core/utils/_program_cache/_keys.py index e170bc18131..2df2d893835 100644 --- a/cuda_core/cuda/core/utils/_program_cache/_keys.py +++ b/cuda_core/cuda/core/utils/_program_cache/_keys.py @@ -499,6 +499,11 @@ def validate(self, options: ProgramOptions, target_type: str, extra_digest: byte raise ValueError( "extra_sources is only valid for code_type='nvvm'; Program() rejects it for code_type='ptx'." ) + # ``numba_debug`` is deliberately not rejected here and is absent from + # ``_LINKER_FIELD_GATES``: for PTX inputs the linker ignores it (with a + # warning from ``_translate_program_options``), so it cannot change the + # generated code and must not perturb the key. Two PTX compiles that + # differ only in ``numba_debug`` are the same compile. # PTX compiles go through the Linker. When the driver (cuLink) # backend is selected (nvJitLink unavailable), ``Program.compile`` # rejects a subset of options that nvJitLink would accept; reject diff --git a/cuda_core/docs/source/release/1.2.0-notes.rst b/cuda_core/docs/source/release/1.2.0-notes.rst index aee86d938f2..b2c26e2d401 100644 --- a/cuda_core/docs/source/release/1.2.0-notes.rst +++ b/cuda_core/docs/source/release/1.2.0-notes.rst @@ -130,9 +130,34 @@ Fixes and enhancements still reports ``NVVM_ERROR_INVALID_OPTION``. (closes `#2570 `__) +- ``Program(ptx, "ptx", ProgramOptions(numba_debug=True))`` now warns that the + option is ignored instead of discarding it silently. ``numba_debug`` is an + NVVM/NVRTC *compiler* option: nvJitLink rejects it with + ``ERROR_UNRECOGNIZED_OPTION`` under every spelling, and the driver's + ``cuLink`` API has no corresponding ``CUjit_option``, so no linking backend + can honor it. PTX inputs are handed to the linker, and the option used to be + forwarded into ``LinkerOptions`` and then dropped without a diagnostic. The + warning is a :class:`UserWarning`, not a :class:`DeprecationWarning` -- + ``ProgramOptions.numba_debug`` is not deprecated and remains fully supported + on the NVVM and NVRTC compilation paths, where it takes effect; it is simply + inapplicable to a linking backend. The gate is truthiness, matching how the + NVVM path gates emission, so ``numba_debug=False`` asks for nothing and is + not worth a warning. + (closes `#2640 `__) + Deprecation Notices ------------------- +- ``LinkerOptions.numba_debug`` is deprecated and will be removed in + ``cuda.core`` 2.0.0. It was exposed in ``cuda-core`` 1.1.0 but no linking + backend ever read it, so setting it has never had any effect; + ``numba_debug`` is an NVVM/NVRTC compiler option with no linker equivalent. + Setting it now emits a :class:`DeprecationWarning` and the value continues + to be ignored. Removal waits for the next major version because the + :doc:`support policy <../support>` confines breaking API changes to + major-version boundaries. Use :attr:`ProgramOptions.numba_debug` on an NVVM + or NVRTC compilation path instead. + - Support for using ``cuda-core`` with Python 3.10 is deprecated and will be removed in a future version. Python 3.10 reaches end of life in October 2026 per the `CPython support cycle `_. diff --git a/cuda_core/tests/test_linker.py b/cuda_core/tests/test_linker.py index 4f4433a1a1a..c875cfc0318 100644 --- a/cuda_core/tests/test_linker.py +++ b/cuda_core/tests/test_linker.py @@ -3,6 +3,7 @@ # SPDX-License-Identifier: Apache-2.0 import inspect +import warnings import pytest @@ -436,6 +437,41 @@ def test_prepare_driver_options_unsupported_raises(driver_binding, kwargs, match opts._prepare_driver_options() +@pytest.mark.agent_authored(model="claude-opus-5") +@pytest.mark.parametrize("value", [True, False]) +def test_numba_debug_warns_and_is_ignored(value): + """No linking backend reads ``numba_debug``, so it is ignored -- but not + silently, which was the bug in #2640. + + The gate is ``is not None``, not truthiness: it is the field itself that is + deprecated, so ``numba_debug=False`` earns the notice too even though it + asks for nothing. + """ + with pytest.warns(DeprecationWarning, match="numba_debug is not supported by any linking backend"): + opts = LinkerOptions(arch="sm_80", debug=True, numba_debug=value) + # Warned, not rejected, and the rest of the option set is untouched. + assert opts._prepare_nvjitlink_options(as_bytes=True) == [b"-arch=sm_80", b"-g"] + + +@pytest.mark.agent_authored(model="claude-opus-5") +def test_numba_debug_unset_does_not_warn(): + """The deprecation notice fires only when the field is explicitly set.""" + with warnings.catch_warnings(): + warnings.simplefilter("error", DeprecationWarning) + options = LinkerOptions(arch="sm_80", debug=True)._prepare_nvjitlink_options(as_bytes=True) + assert options == [b"-arch=sm_80", b"-g"] + + +@pytest.mark.agent_authored(model="claude-opus-5") +def test_numba_debug_ignored_by_driver_backend_too(driver_binding): + """The cuLink driver API has no CUjit_option for numba_debug either, so it + is ignored there as well rather than reaching the driver.""" + with pytest.warns(DeprecationWarning, match="numba_debug"): + opts = LinkerOptions(arch="sm_80", numba_debug=True) + formatted_options, option_keys = opts._prepare_driver_options() + assert not any("NUMBA" in str(key) for key in option_keys) + + def test_linker_empty_object_codes_raises(): """Linker with no ObjectCode raises ValueError.""" with pytest.raises(ValueError, match="At least one ObjectCode object must be provided"): diff --git a/cuda_core/tests/test_program.py b/cuda_core/tests/test_program.py index c4e2e0c6428..72f8b8f5942 100644 --- a/cuda_core/tests/test_program.py +++ b/cuda_core/tests/test_program.py @@ -316,8 +316,10 @@ def test_cpp_program_pch_status_none_without_pch(init_cuda): ProgramOptions(prec_div=True), ProgramOptions(prec_sqrt=True), ProgramOptions(fma=True), - # Plumb-through; no-op at link time. See #1287. - ProgramOptions(debug=True, numba_debug=True), + # ``numba_debug`` is deliberately absent: it was listed here as a link-time + # no-op (#1287), but no linker backend accepts it, so it was dropped + # silently (#2640). The PTX path now warns; see + # test_ptx_program_numba_debug_warns_and_is_ignored. ] if not is_culink_backend: options += [ @@ -870,6 +872,34 @@ def test_ptx_program_extra_sources_unsupported(ptx_code_object): Program(ptx_code_object.code.decode(), "ptx", options) +@pytest.mark.agent_authored(model="claude-opus-5") +def test_ptx_program_numba_debug_warns_and_is_ignored(init_cuda, ptx_code_object): + """PTX inputs go to the linker, which cannot honor numba_debug (#2640). + + It used to be forwarded into ``LinkerOptions`` and dropped without a word, + so the compile appeared to succeed with the option applied. It is still + ignored -- no linker can do anything with it -- but no longer silently. + + ``UserWarning``, not ``DeprecationWarning``: ``ProgramOptions.numba_debug`` + is not deprecated, it is supported on NVVM/NVRTC and merely inapplicable to + this backend. + """ + with pytest.warns(UserWarning, match="numba_debug is ignored for code_type='ptx'"): + program = Program(ptx_code_object.code.decode(), "ptx", ProgramOptions(numba_debug=True)) + assert program.compile("cubin") is not None + + +@pytest.mark.agent_authored(model="claude-opus-5") +@pytest.mark.parametrize("value", [None, False]) +def test_ptx_program_numba_debug_unset_or_false_does_not_warn(init_cuda, ptx_code_object, value): + """The gate is truthiness: only an enabled ``numba_debug`` asks for + something the PTX path cannot deliver, so ``False`` is not worth a warning.""" + with warnings.catch_warnings(): + warnings.simplefilter("error", UserWarning) + program = Program(ptx_code_object.code.decode(), "ptx", ProgramOptions(numba_debug=value)) + assert program.compile("cubin") is not None + + def test_ptx_program_handle_is_linker_handle(init_cuda, ptx_code_object): """Program.handle for the PTX backend delegates to the linker handle.""" program = Program(ptx_code_object.code.decode(), "ptx") diff --git a/cuda_core/tests/test_program_cache.py b/cuda_core/tests/test_program_cache.py index a8d3fc85f7e..2b5402374a6 100644 --- a/cuda_core/tests/test_program_cache.py +++ b/cuda_core/tests/test_program_cache.py @@ -319,6 +319,20 @@ def test_make_program_cache_key_rejects_extra_sources_outside_nvvm(code_type, co ) +@pytest.mark.agent_authored(model="claude-opus-5") +@pytest.mark.parametrize("value", [True, False]) +def test_make_program_cache_key_ignores_numba_debug_for_ptx(value): + """``numba_debug`` cannot change PTX-path output -- no linker backend reads + it -- so it must not perturb the cache key (#2640). + + If it did, two compiles producing byte-identical cubins would miss each + other in the cache. + """ + baseline = _make_key(code=".version 7.0", code_type="ptx", target_type="cubin", options=_opts()) + with_flag = _make_key(code=".version 7.0", code_type="ptx", target_type="cubin", options=_opts(numba_debug=value)) + assert with_flag == baseline + + @pytest.mark.parametrize( "kwargs, exc_type, match", [