From 432771c690b5064cd834ddfb99b13edb282bf32d Mon Sep 17 00:00:00 2001 From: Phillip Cloud <417981+cpcloud@users.noreply.github.com> Date: Tue, 21 Apr 2026 11:14:56 -0400 Subject: [PATCH 1/3] feat(core): convert Linker.backend from property to classmethod MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allows querying the linking backend without constructing a Linker instance — useful for dispatching on input format (PTX vs. LTOIR) before linking. Updates existing call sites (Program init, test_linker) to use the new invocation form Linker.backend(). --- cuda_core/cuda/core/_linker.pyx | 20 ++++++++++++++++---- cuda_core/cuda/core/_program.pyx | 2 +- cuda_core/tests/test_linker.py | 2 +- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/cuda_core/cuda/core/_linker.pyx b/cuda_core/cuda/core/_linker.pyx index 09aa9863cd7..2a4bda413c2 100644 --- a/cuda_core/cuda/core/_linker.pyx +++ b/cuda_core/cuda/core/_linker.pyx @@ -167,10 +167,22 @@ cdef class Linker: else: return as_py(self._culink_handle) - @property - def backend(self) -> str: - """Return this Linker instance's underlying backend.""" - return "nvJitLink" if self._use_nvjitlink else "driver" + @classmethod + def backend(cls) -> str: + """Return which linking backend will be used. + + Returns ``"nvJitLink"`` when the nvJitLink library is available + and meets the minimum version requirement, otherwise ``"driver"``. + + .. note:: + + Prefer letting :class:`Linker` decide. Query ``backend()`` + only when you need to dispatch based on input format (for + example: choose PTX vs. LTOIR before constructing a + ``Linker``). The returned string names an implementation + detail whose support matrix may shift across CTK releases. + """ + return "driver" if _decide_nvjitlink_or_driver() else "nvJitLink" # ============================================================================= diff --git a/cuda_core/cuda/core/_program.pyx b/cuda_core/cuda/core/_program.pyx index 194ef6da53f..bcbd8ca3758 100644 --- a/cuda_core/cuda/core/_program.pyx +++ b/cuda_core/cuda/core/_program.pyx @@ -649,7 +649,7 @@ cdef inline int Program_init(Program self, object code, str code_type, object op self._linker = Linker( ObjectCode._init(code.encode(), code_type), options=_translate_program_options(options) ) - self._backend = self._linker.backend + self._backend = self._linker.backend() elif code_type == "nvvm": _get_nvvm_module() # Validate NVVM availability diff --git a/cuda_core/tests/test_linker.py b/cuda_core/tests/test_linker.py index 0d4ff91dcd9..863a55af713 100644 --- a/cuda_core/tests/test_linker.py +++ b/cuda_core/tests/test_linker.py @@ -92,7 +92,7 @@ def test_linker_init(compile_ptx_functions, options): linker = Linker(*compile_ptx_functions, options=options) object_code = linker.link("cubin") assert isinstance(object_code, ObjectCode) - assert linker.backend == ("driver" if is_culink_backend else "nvJitLink") + assert linker.backend() == ("driver" if is_culink_backend else "nvJitLink") def test_linker_init_invalid_arch(compile_ptx_functions): From 6327b220dad9a1aa97b272ae2566df70c6692ef0 Mon Sep 17 00:00:00 2001 From: Phillip Cloud <417981+cpcloud@users.noreply.github.com> Date: Tue, 21 Apr 2026 11:15:22 -0400 Subject: [PATCH 2/3] test(core): add tests for Linker.backend classmethod Covers classmethod invocation (Linker.backend() without an instance), memoisation flag handling, probe-on-first-use, and non-property attribute semantics. --- cuda_core/tests/test_linker.py | 39 ++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/cuda_core/tests/test_linker.py b/cuda_core/tests/test_linker.py index 863a55af713..9b3d33e891f 100644 --- a/cuda_core/tests/test_linker.py +++ b/cuda_core/tests/test_linker.py @@ -2,6 +2,8 @@ # # SPDX-License-Identifier: Apache-2.0 +import inspect + import pytest from cuda.core import Device, Linker, LinkerOptions, Program, ProgramOptions, _linker @@ -242,3 +244,40 @@ def test_linker_options_nvjitlink_options_as_str(): assert f"-arch={ARCH}" in options assert "-g" in options assert "-lineinfo" in options + + +class TestBackendClassmethod: + def test_backend_returns_nvjitlink(self, monkeypatch): + monkeypatch.setattr(_linker, "_use_nvjitlink_backend", True) + assert Linker.backend() == "nvJitLink" + + def test_backend_returns_driver(self, monkeypatch): + monkeypatch.setattr(_linker, "_use_nvjitlink_backend", False) + assert Linker.backend() == "driver" + + def test_backend_invokes_probe_when_not_memoised(self, monkeypatch): + monkeypatch.setattr(_linker, "_use_nvjitlink_backend", None) + called = [] + + def fake_decide(): + called.append(True) + return False # False = not falling back to driver = nvJitLink + + monkeypatch.setattr(_linker, "_decide_nvjitlink_or_driver", fake_decide) + result = Linker.backend() + assert result == "nvJitLink" + assert called, "_decide_nvjitlink_or_driver was not called" + + def test_backend_is_classmethod(self): + attr = inspect.getattr_static(Linker, "backend") + assert isinstance(attr, classmethod) + + def test_backend_is_not_property(self): + """backend is a classmethod, not a property. + + This is an intentional breaking change from the prior property API. + Attribute-style access (``linker.backend``) now returns a bound method, + not a string. All call sites must use parens: ``Linker.backend()``. + """ + attr = inspect.getattr_static(Linker, "backend") + assert not isinstance(attr, property) From 12d291b1693a3db25bb6662f60c628364b3ca8e9 Mon Sep 17 00:00:00 2001 From: Phillip Cloud <417981+cpcloud@users.noreply.github.com> Date: Tue, 21 Apr 2026 11:15:23 -0400 Subject: [PATCH 3/3] docs(core): add 1.0.0 release notes for Linker.backend change Breaking change: Linker.backend is now a classmethod, so call sites must use parens: Linker.backend(). --- cuda_core/docs/source/release/1.0.0-notes.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 cuda_core/docs/source/release/1.0.0-notes.rst diff --git a/cuda_core/docs/source/release/1.0.0-notes.rst b/cuda_core/docs/source/release/1.0.0-notes.rst new file mode 100644 index 00000000000..d289500deff --- /dev/null +++ b/cuda_core/docs/source/release/1.0.0-notes.rst @@ -0,0 +1,17 @@ +.. SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +.. SPDX-License-Identifier: Apache-2.0 + +.. currentmodule:: cuda.core + +``cuda.core`` 1.0.0 Release Notes +================================= + + +Breaking Changes +---------------- + +- :meth:`Linker.backend` is now a classmethod instead of an instance property. + Call sites must use ``Linker.backend()`` (with parentheses) instead of + ``linker.backend``. This allows querying the linking backend without + constructing a ``Linker`` instance — for example, to choose between PTX and + LTOIR input before linking.