From a01a803310036c09eb291298066e3b923ad5081d Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Thu, 2 Apr 2026 11:32:15 -0700 Subject: [PATCH 1/8] pathfinder: add cudla and nvcudla support Add pathfinder support for loading ``libcudla.so.1`` from the ``nvidia-cudla`` package and probing ``libnvcudla.so`` through the existing canary subprocess path. Use that probe in the cudla load test so hosts without the platform runtime are skipped, while real ``libcudla.so.1`` load failures still surface when ``libnvcudla.so`` is available. Made-with: Cursor --- .../pathfinder/_dynamic_libs/descriptor_catalog.py | 11 +++++++++++ .../_dynamic_libs/load_nvidia_dynamic_lib.py | 13 +++++++++++-- cuda_pathfinder/pyproject.toml | 1 + .../tests/test_load_nvidia_dynamic_lib.py | 11 +++++++++-- 4 files changed, 32 insertions(+), 4 deletions(-) diff --git a/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/descriptor_catalog.py b/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/descriptor_catalog.py index 83f78ef881..49b4b365df 100644 --- a/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/descriptor_catalog.py +++ b/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/descriptor_catalog.py @@ -324,6 +324,12 @@ class DescriptorSpec: site_packages_windows=("nvidia/cu13/bin", "nvidia/cu12/bin"), dependencies=("nvrtc",), ), + DescriptorSpec( + name="cudla", + packaged_with="other", + linux_sonames=("libcudla.so.1",), + site_packages_linux=("nvidia/cu13/lib",), + ), DescriptorSpec( name="cudss", packaged_with="other", @@ -386,6 +392,11 @@ class DescriptorSpec: linux_sonames=("libcuda.so.1",), windows_dlls=("nvcuda.dll",), ), + DescriptorSpec( + name="nvcudla", + packaged_with="driver", + linux_sonames=("libnvcudla.so",), + ), DescriptorSpec( name="nvml", packaged_with="driver", diff --git a/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_nvidia_dynamic_lib.py b/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_nvidia_dynamic_lib.py index f8df1f75e4..a7a8965d2e 100644 --- a/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_nvidia_dynamic_lib.py +++ b/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_nvidia_dynamic_lib.py @@ -99,14 +99,18 @@ def _raise_canary_probe_child_process_error( @functools.cache -def _resolve_system_loaded_abs_path_in_subprocess(libname: str) -> str | None: +def _resolve_system_loaded_abs_path_in_subprocess( + libname: str, + *, + timeout: float = _CANARY_PROBE_TIMEOUT_SECONDS, +) -> str | None: """Resolve a canary library's absolute path in a fresh Python subprocess.""" try: result = subprocess.run( # noqa: S603 - trusted argv: current interpreter + internal probe module build_dynamic_lib_subprocess_command(MODE_CANARY, libname), capture_output=True, text=True, - timeout=_CANARY_PROBE_TIMEOUT_SECONDS, + timeout=timeout, check=False, cwd=DYNAMIC_LIB_SUBPROCESS_CWD, ) @@ -127,6 +131,11 @@ def _resolve_system_loaded_abs_path_in_subprocess(libname: str) -> str | None: return None +def _loadable_via_canary_subprocess(libname: str, *, timeout: float = _CANARY_PROBE_TIMEOUT_SECONDS) -> bool: + """Return True if the canary subprocess can resolve ``libname`` via system search.""" + return _resolve_system_loaded_abs_path_in_subprocess(libname, timeout=timeout) is not None + + def _try_ctk_root_canary(ctx: SearchContext) -> str | None: """Try CTK-root canary fallback for descriptor-configured libraries.""" for canary_libname in ctx.desc.ctk_root_canary_anchor_libnames: diff --git a/cuda_pathfinder/pyproject.toml b/cuda_pathfinder/pyproject.toml index 2e08bdffae..5f86c0afb9 100644 --- a/cuda_pathfinder/pyproject.toml +++ b/cuda_pathfinder/pyproject.toml @@ -36,6 +36,7 @@ cu13 = [ "cuda-toolkit[cufile]==13.*; sys_platform != 'win32'", "cutensor-cu13", "nvidia-cublasmp-cu13; sys_platform != 'win32'", + "nvidia-cudla; platform_system == 'Linux' and platform_machine == 'aarch64'", "nvidia-cudss-cu13", "nvidia-cufftmp-cu13; sys_platform != 'win32'", "nvidia-cusolvermp-cu13; sys_platform != 'win32'", diff --git a/cuda_pathfinder/tests/test_load_nvidia_dynamic_lib.py b/cuda_pathfinder/tests/test_load_nvidia_dynamic_lib.py index 36487bd58e..514d1d1674 100644 --- a/cuda_pathfinder/tests/test_load_nvidia_dynamic_lib.py +++ b/cuda_pathfinder/tests/test_load_nvidia_dynamic_lib.py @@ -14,7 +14,10 @@ from cuda.pathfinder import DynamicLibNotAvailableError, DynamicLibUnknownError, load_nvidia_dynamic_lib from cuda.pathfinder._dynamic_libs import load_nvidia_dynamic_lib as load_nvidia_dynamic_lib_module from cuda.pathfinder._dynamic_libs import supported_nvidia_libs -from cuda.pathfinder._dynamic_libs.subprocess_protocol import STATUS_NOT_FOUND, parse_dynamic_lib_subprocess_payload +from cuda.pathfinder._dynamic_libs.subprocess_protocol import ( + STATUS_NOT_FOUND, + parse_dynamic_lib_subprocess_payload, +) from cuda.pathfinder._utils.platform_aware import IS_WINDOWS, quote_for_shell STRICTNESS = os.environ.get("CUDA_PATHFINDER_TEST_LOAD_NVIDIA_DYNAMIC_LIB_STRICTNESS", "see_what_works") @@ -95,7 +98,7 @@ def test_known_but_platform_unavailable_libname_raises_dynamic_lib_not_available def _is_expected_load_nvidia_dynamic_lib_failure(libname): - if libname == "nvpl_fftw" and platform.machine().lower() != "aarch64": + if libname in ("cudla", "nvcudla", "nvpl_fftw") and platform.machine().lower() != "aarch64": return True dist_name_pattern = IMPORTLIB_METADATA_DISTRIBUTIONS_NAMES.get(libname) if dist_name_pattern is not None: @@ -117,6 +120,10 @@ def raise_child_process_failed(): raise RuntimeError(build_child_process_failed_for_libname_message(libname, result)) if result.returncode != 0: + if libname == "cudla" and not load_nvidia_dynamic_lib_module._loadable_via_canary_subprocess( + "nvcudla", timeout=timeout + ): + pytest.skip("libnvcudla.so is not loadable via canary subprocess on this host.") raise_child_process_failed() assert not result.stderr payload = parse_dynamic_lib_subprocess_payload( From c80c137b720c9f68288903704f89e416735c0bdc Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Thu, 2 Apr 2026 15:01:07 -0700 Subject: [PATCH 2/8] pathfinder: gate cudla support by machine architecture Mark cudla and nvcudla as aarch64-only descriptors and derive the supported library tables from the current machine as well as the current OS. This keeps those libraries known to pathfinder while reporting them as unavailable on linux-64, and updates the descriptor-registry tests to match the new current-platform filtering model. Made-with: Cursor --- .../_dynamic_libs/descriptor_catalog.py | 9 +++ .../_dynamic_libs/load_nvidia_dynamic_lib.py | 9 ++- .../_dynamic_libs/supported_nvidia_libs.py | 68 ++++++++++++++----- .../cuda/pathfinder/_utils/platform_aware.py | 4 +- cuda_pathfinder/tests/test_lib_descriptor.py | 30 +++++--- 5 files changed, 93 insertions(+), 27 deletions(-) diff --git a/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/descriptor_catalog.py b/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/descriptor_catalog.py index 49b4b365df..4aa94b543a 100644 --- a/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/descriptor_catalog.py +++ b/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/descriptor_catalog.py @@ -8,6 +8,8 @@ from dataclasses import dataclass from typing import Literal +from cuda.pathfinder._utils.platform_aware import PLATFORM_MACHINE + PackagedWith = Literal["ctk", "other", "driver"] @@ -17,6 +19,7 @@ class DescriptorSpec: packaged_with: PackagedWith linux_sonames: tuple[str, ...] = () windows_dlls: tuple[str, ...] = () + platform_machines: tuple[str, ...] = () site_packages_linux: tuple[str, ...] = () site_packages_windows: tuple[str, ...] = () dependencies: tuple[str, ...] = () @@ -27,6 +30,10 @@ class DescriptorSpec: requires_rtld_deepbind: bool = False +def is_supported_on_current_machine(desc: DescriptorSpec) -> bool: + return not desc.platform_machines or PLATFORM_MACHINE in desc.platform_machines + + DESCRIPTOR_CATALOG: tuple[DescriptorSpec, ...] = ( # ----------------------------------------------------------------------- # CTK (CUDA Toolkit) libraries @@ -328,6 +335,7 @@ class DescriptorSpec: name="cudla", packaged_with="other", linux_sonames=("libcudla.so.1",), + platform_machines=("aarch64",), site_packages_linux=("nvidia/cu13/lib",), ), DescriptorSpec( @@ -396,6 +404,7 @@ class DescriptorSpec: name="nvcudla", packaged_with="driver", linux_sonames=("libnvcudla.so",), + platform_machines=("aarch64",), ), DescriptorSpec( name="nvml", diff --git a/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_nvidia_dynamic_lib.py b/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_nvidia_dynamic_lib.py index a7a8965d2e..4558572170 100644 --- a/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_nvidia_dynamic_lib.py +++ b/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_nvidia_dynamic_lib.py @@ -9,6 +9,7 @@ import sys from typing import TYPE_CHECKING +from cuda.pathfinder._dynamic_libs.descriptor_catalog import is_supported_on_current_machine from cuda.pathfinder._dynamic_libs.lib_descriptor import LIB_DESCRIPTORS from cuda.pathfinder._dynamic_libs.load_dl_common import ( DynamicLibNotAvailableError, @@ -43,7 +44,9 @@ # (CTK, third-party, driver). _ALL_KNOWN_LIBNAMES: frozenset[str] = frozenset(LIB_DESCRIPTORS) _ALL_SUPPORTED_LIBNAMES: frozenset[str] = frozenset( - name for name, desc in LIB_DESCRIPTORS.items() if (desc.windows_dlls if IS_WINDOWS else desc.linux_sonames) + name + for name, desc in LIB_DESCRIPTORS.items() + if is_supported_on_current_machine(desc) and (desc.windows_dlls if IS_WINDOWS else desc.linux_sonames) ) _PLATFORM_NAME = "Windows" if IS_WINDOWS else "Linux" _CANARY_PROBE_TIMEOUT_SECONDS = 10.0 @@ -51,7 +54,9 @@ # Driver libraries: shipped with the NVIDIA display driver, always on the # system linker path. These skip all CTK search steps (site-packages, # conda, CUDA_PATH, canary) and go straight to system search. -_DRIVER_ONLY_LIBNAMES = frozenset(name for name, desc in LIB_DESCRIPTORS.items() if desc.packaged_with == "driver") +_DRIVER_ONLY_LIBNAMES = frozenset( + name for name, desc in LIB_DESCRIPTORS.items() if desc.packaged_with == "driver" and name in _ALL_SUPPORTED_LIBNAMES +) def _load_driver_lib_no_cache(desc: LibDescriptor) -> LoadedDL: diff --git a/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/supported_nvidia_libs.py b/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/supported_nvidia_libs.py index db06411c6d..cb3302cfd8 100644 --- a/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/supported_nvidia_libs.py +++ b/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/supported_nvidia_libs.py @@ -10,7 +10,8 @@ from __future__ import annotations -from cuda.pathfinder._dynamic_libs.descriptor_catalog import DESCRIPTOR_CATALOG +from cuda.pathfinder._dynamic_libs.descriptor_catalog import DESCRIPTOR_CATALOG, is_supported_on_current_machine +from cuda.pathfinder._dynamic_libs.lib_descriptor import LibDescriptor from cuda.pathfinder._utils.platform_aware import IS_WINDOWS _CTK_DESCRIPTORS = tuple(desc for desc in DESCRIPTOR_CATALOG if desc.packaged_with == "ctk") @@ -18,12 +19,27 @@ _DRIVER_DESCRIPTORS = tuple(desc for desc in DESCRIPTOR_CATALOG if desc.packaged_with == "driver") _NON_CTK_DESCRIPTORS = _OTHER_DESCRIPTORS + _DRIVER_DESCRIPTORS -SUPPORTED_LIBNAMES_COMMON = tuple(desc.name for desc in _CTK_DESCRIPTORS if desc.linux_sonames and desc.windows_dlls) + +def _has_supported_linux_sonames(desc: LibDescriptor) -> bool: + return bool(desc.linux_sonames) and is_supported_on_current_machine(desc) + + +def _has_supported_windows_dlls(desc: LibDescriptor) -> bool: + return bool(desc.windows_dlls) and is_supported_on_current_machine(desc) + + +SUPPORTED_LIBNAMES_COMMON = tuple( + desc.name for desc in _CTK_DESCRIPTORS if _has_supported_linux_sonames(desc) and _has_supported_windows_dlls(desc) +) SUPPORTED_LIBNAMES_LINUX_ONLY = tuple( - desc.name for desc in _CTK_DESCRIPTORS if desc.linux_sonames and not desc.windows_dlls + desc.name + for desc in _CTK_DESCRIPTORS + if _has_supported_linux_sonames(desc) and not _has_supported_windows_dlls(desc) ) SUPPORTED_LIBNAMES_WINDOWS_ONLY = tuple( - desc.name for desc in _CTK_DESCRIPTORS if desc.windows_dlls and not desc.linux_sonames + desc.name + for desc in _CTK_DESCRIPTORS + if _has_supported_windows_dlls(desc) and not _has_supported_linux_sonames(desc) ) SUPPORTED_LIBNAMES_LINUX = SUPPORTED_LIBNAMES_COMMON + SUPPORTED_LIBNAMES_LINUX_ONLY @@ -34,37 +50,57 @@ DIRECT_DEPENDENCIES_CTK = {desc.name: desc.dependencies for desc in _CTK_DESCRIPTORS if desc.dependencies} DIRECT_DEPENDENCIES = {desc.name: desc.dependencies for desc in DESCRIPTOR_CATALOG if desc.dependencies} -SUPPORTED_LINUX_SONAMES_CTK = {desc.name: desc.linux_sonames for desc in _CTK_DESCRIPTORS if desc.linux_sonames} -SUPPORTED_LINUX_SONAMES_OTHER = {desc.name: desc.linux_sonames for desc in _OTHER_DESCRIPTORS if desc.linux_sonames} -SUPPORTED_LINUX_SONAMES_DRIVER = {desc.name: desc.linux_sonames for desc in _DRIVER_DESCRIPTORS if desc.linux_sonames} +SUPPORTED_LINUX_SONAMES_CTK = { + desc.name: desc.linux_sonames for desc in _CTK_DESCRIPTORS if _has_supported_linux_sonames(desc) +} +SUPPORTED_LINUX_SONAMES_OTHER = { + desc.name: desc.linux_sonames for desc in _OTHER_DESCRIPTORS if _has_supported_linux_sonames(desc) +} +SUPPORTED_LINUX_SONAMES_DRIVER = { + desc.name: desc.linux_sonames for desc in _DRIVER_DESCRIPTORS if _has_supported_linux_sonames(desc) +} SUPPORTED_LINUX_SONAMES = SUPPORTED_LINUX_SONAMES_CTK | SUPPORTED_LINUX_SONAMES_OTHER | SUPPORTED_LINUX_SONAMES_DRIVER -SUPPORTED_WINDOWS_DLLS_CTK = {desc.name: desc.windows_dlls for desc in _CTK_DESCRIPTORS if desc.windows_dlls} -SUPPORTED_WINDOWS_DLLS_OTHER = {desc.name: desc.windows_dlls for desc in _OTHER_DESCRIPTORS if desc.windows_dlls} -SUPPORTED_WINDOWS_DLLS_DRIVER = {desc.name: desc.windows_dlls for desc in _DRIVER_DESCRIPTORS if desc.windows_dlls} +SUPPORTED_WINDOWS_DLLS_CTK = { + desc.name: desc.windows_dlls for desc in _CTK_DESCRIPTORS if _has_supported_windows_dlls(desc) +} +SUPPORTED_WINDOWS_DLLS_OTHER = { + desc.name: desc.windows_dlls for desc in _OTHER_DESCRIPTORS if _has_supported_windows_dlls(desc) +} +SUPPORTED_WINDOWS_DLLS_DRIVER = { + desc.name: desc.windows_dlls for desc in _DRIVER_DESCRIPTORS if _has_supported_windows_dlls(desc) +} SUPPORTED_WINDOWS_DLLS = SUPPORTED_WINDOWS_DLLS_CTK | SUPPORTED_WINDOWS_DLLS_OTHER | SUPPORTED_WINDOWS_DLLS_DRIVER LIBNAMES_REQUIRING_OS_ADD_DLL_DIRECTORY = tuple( - desc.name for desc in DESCRIPTOR_CATALOG if desc.requires_add_dll_directory and desc.windows_dlls + desc.name for desc in DESCRIPTOR_CATALOG if desc.requires_add_dll_directory and _has_supported_windows_dlls(desc) ) LIBNAMES_REQUIRING_RTLD_DEEPBIND = tuple( - desc.name for desc in DESCRIPTOR_CATALOG if desc.requires_rtld_deepbind and desc.linux_sonames + desc.name for desc in DESCRIPTOR_CATALOG if desc.requires_rtld_deepbind and _has_supported_linux_sonames(desc) ) # Based on output of toolshed/make_site_packages_libdirs_linux.py SITE_PACKAGES_LIBDIRS_LINUX_CTK = { - desc.name: desc.site_packages_linux for desc in _CTK_DESCRIPTORS if desc.site_packages_linux + desc.name: desc.site_packages_linux + for desc in _CTK_DESCRIPTORS + if desc.site_packages_linux and _has_supported_linux_sonames(desc) } SITE_PACKAGES_LIBDIRS_LINUX_OTHER = { - desc.name: desc.site_packages_linux for desc in _NON_CTK_DESCRIPTORS if desc.site_packages_linux + desc.name: desc.site_packages_linux + for desc in _NON_CTK_DESCRIPTORS + if desc.site_packages_linux and _has_supported_linux_sonames(desc) } SITE_PACKAGES_LIBDIRS_LINUX = SITE_PACKAGES_LIBDIRS_LINUX_CTK | SITE_PACKAGES_LIBDIRS_LINUX_OTHER SITE_PACKAGES_LIBDIRS_WINDOWS_CTK = { - desc.name: desc.site_packages_windows for desc in _CTK_DESCRIPTORS if desc.site_packages_windows + desc.name: desc.site_packages_windows + for desc in _CTK_DESCRIPTORS + if desc.site_packages_windows and _has_supported_windows_dlls(desc) } SITE_PACKAGES_LIBDIRS_WINDOWS_OTHER = { - desc.name: desc.site_packages_windows for desc in _NON_CTK_DESCRIPTORS if desc.site_packages_windows + desc.name: desc.site_packages_windows + for desc in _NON_CTK_DESCRIPTORS + if desc.site_packages_windows and _has_supported_windows_dlls(desc) } SITE_PACKAGES_LIBDIRS_WINDOWS = SITE_PACKAGES_LIBDIRS_WINDOWS_CTK | SITE_PACKAGES_LIBDIRS_WINDOWS_OTHER diff --git a/cuda_pathfinder/cuda/pathfinder/_utils/platform_aware.py b/cuda_pathfinder/cuda/pathfinder/_utils/platform_aware.py index 72ecbc5359..4247da3851 100644 --- a/cuda_pathfinder/cuda/pathfinder/_utils/platform_aware.py +++ b/cuda_pathfinder/cuda/pathfinder/_utils/platform_aware.py @@ -1,9 +1,11 @@ -# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +import platform import sys IS_WINDOWS = sys.platform == "win32" +PLATFORM_MACHINE = platform.machine().lower() def quote_for_shell(s: str) -> str: diff --git a/cuda_pathfinder/tests/test_lib_descriptor.py b/cuda_pathfinder/tests/test_lib_descriptor.py index cda96131e1..17c8b304b6 100644 --- a/cuda_pathfinder/tests/test_lib_descriptor.py +++ b/cuda_pathfinder/tests/test_lib_descriptor.py @@ -2,10 +2,11 @@ # SPDX-License-Identifier: Apache-2.0 """Tests verifying that the LibDescriptor registry faithfully represents -the existing data tables in supported_nvidia_libs.py.""" +the current-platform data tables in supported_nvidia_libs.py.""" import pytest +from cuda.pathfinder._dynamic_libs.descriptor_catalog import is_supported_on_current_machine from cuda.pathfinder._dynamic_libs.lib_descriptor import LIB_DESCRIPTORS from cuda.pathfinder._dynamic_libs.supported_nvidia_libs import ( DIRECT_DEPENDENCIES, @@ -33,7 +34,8 @@ def test_registry_covers_all_windows_dlls(): def test_registry_has_no_extra_entries(): expected = set(SUPPORTED_LINUX_SONAMES) | set(SUPPORTED_WINDOWS_DLLS) - assert set(LIB_DESCRIPTORS) == expected + extra = set(LIB_DESCRIPTORS) - expected + assert all(not is_supported_on_current_machine(LIB_DESCRIPTORS[name]) for name in extra) # --------------------------------------------------------------------------- @@ -43,22 +45,30 @@ def test_registry_has_no_extra_entries(): @pytest.mark.parametrize("name", sorted(LIB_DESCRIPTORS)) def test_linux_sonames_match(name): - assert LIB_DESCRIPTORS[name].linux_sonames == SUPPORTED_LINUX_SONAMES.get(name, ()) + desc = LIB_DESCRIPTORS[name] + expected = desc.linux_sonames if is_supported_on_current_machine(desc) else () + assert expected == SUPPORTED_LINUX_SONAMES.get(name, ()) @pytest.mark.parametrize("name", sorted(LIB_DESCRIPTORS)) def test_windows_dlls_match(name): - assert LIB_DESCRIPTORS[name].windows_dlls == SUPPORTED_WINDOWS_DLLS.get(name, ()) + desc = LIB_DESCRIPTORS[name] + expected = desc.windows_dlls if is_supported_on_current_machine(desc) else () + assert expected == SUPPORTED_WINDOWS_DLLS.get(name, ()) @pytest.mark.parametrize("name", sorted(LIB_DESCRIPTORS)) def test_site_packages_linux_match(name): - assert LIB_DESCRIPTORS[name].site_packages_linux == SITE_PACKAGES_LIBDIRS_LINUX.get(name, ()) + desc = LIB_DESCRIPTORS[name] + expected = desc.site_packages_linux if is_supported_on_current_machine(desc) else () + assert expected == SITE_PACKAGES_LIBDIRS_LINUX.get(name, ()) @pytest.mark.parametrize("name", sorted(LIB_DESCRIPTORS)) def test_site_packages_windows_match(name): - assert LIB_DESCRIPTORS[name].site_packages_windows == SITE_PACKAGES_LIBDIRS_WINDOWS.get(name, ()) + desc = LIB_DESCRIPTORS[name] + expected = desc.site_packages_windows if is_supported_on_current_machine(desc) else () + assert expected == SITE_PACKAGES_LIBDIRS_WINDOWS.get(name, ()) @pytest.mark.parametrize("name", sorted(LIB_DESCRIPTORS)) @@ -68,12 +78,16 @@ def test_dependencies_match(name): @pytest.mark.parametrize("name", sorted(LIB_DESCRIPTORS)) def test_requires_add_dll_directory_match(name): - assert LIB_DESCRIPTORS[name].requires_add_dll_directory == (name in LIBNAMES_REQUIRING_OS_ADD_DLL_DIRECTORY) + desc = LIB_DESCRIPTORS[name] + expected = desc.requires_add_dll_directory if is_supported_on_current_machine(desc) else False + assert expected == (name in LIBNAMES_REQUIRING_OS_ADD_DLL_DIRECTORY) @pytest.mark.parametrize("name", sorted(LIB_DESCRIPTORS)) def test_requires_rtld_deepbind_match(name): - assert LIB_DESCRIPTORS[name].requires_rtld_deepbind == (name in LIBNAMES_REQUIRING_RTLD_DEEPBIND) + desc = LIB_DESCRIPTORS[name] + expected = desc.requires_rtld_deepbind if is_supported_on_current_machine(desc) else False + assert expected == (name in LIBNAMES_REQUIRING_RTLD_DEEPBIND) # --------------------------------------------------------------------------- From 42bebe32678e5ee0de34624275deacda4b191072 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Fri, 3 Apr 2026 14:34:52 -0700 Subject: [PATCH 3/8] pathfinder: skip nvcudla tests when runtime is absent Skip the cudla and nvcudla load tests on aarch64 hosts when the nvcudla canary probe cannot resolve libnvcudla.so. This keeps non-Tegra linux-aarch64 systems from failing strict test runs while still exercising the real success path on Tegra platforms where the platform runtime is installed. Made-with: Cursor --- cuda_pathfinder/tests/test_driver_lib_loading.py | 12 +++++++++++- .../tests/test_load_nvidia_dynamic_lib.py | 11 ++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/cuda_pathfinder/tests/test_driver_lib_loading.py b/cuda_pathfinder/tests/test_driver_lib_loading.py index bfc8e87f49..19ba794dd1 100644 --- a/cuda_pathfinder/tests/test_driver_lib_loading.py +++ b/cuda_pathfinder/tests/test_driver_lib_loading.py @@ -16,6 +16,7 @@ run_load_nvidia_dynamic_lib_in_subprocess, ) +from cuda.pathfinder._dynamic_libs import load_nvidia_dynamic_lib as load_nvidia_dynamic_lib_module from cuda.pathfinder._dynamic_libs.lib_descriptor import LIB_DESCRIPTORS from cuda.pathfinder._dynamic_libs.load_dl_common import DynamicLibNotFoundError, LoadedDL from cuda.pathfinder._dynamic_libs.load_nvidia_dynamic_lib import ( @@ -24,7 +25,7 @@ _load_lib_no_cache, ) from cuda.pathfinder._dynamic_libs.subprocess_protocol import STATUS_NOT_FOUND, parse_dynamic_lib_subprocess_payload -from cuda.pathfinder._utils.platform_aware import IS_WINDOWS, quote_for_shell +from cuda.pathfinder._utils.platform_aware import IS_WINDOWS, PLATFORM_MACHINE, quote_for_shell STRICTNESS = os.environ.get("CUDA_PATHFINDER_TEST_LOAD_NVIDIA_DYNAMIC_LIB_STRICTNESS", "see_what_works") assert STRICTNESS in ("see_what_works", "all_must_work") @@ -40,6 +41,14 @@ def _make_loaded_dl(path, found_via): return LoadedDL(path, False, 0xDEAD, found_via) +def _skip_if_missing_nvcudla_runtime(libname: str, *, timeout: float) -> None: + if libname != "nvcudla" or PLATFORM_MACHINE != "aarch64": + return + if load_nvidia_dynamic_lib_module._loadable_via_canary_subprocess("nvcudla", timeout=timeout): + return + pytest.skip("libnvcudla.so is not loadable via canary subprocess on this host.") + + # --------------------------------------------------------------------------- # _load_driver_lib_no_cache # --------------------------------------------------------------------------- @@ -147,6 +156,7 @@ def raise_child_process_failed(): error_label="Load subprocess child process", ) if payload.status == STATUS_NOT_FOUND: + _skip_if_missing_nvcudla_runtime(libname, timeout=timeout) if STRICTNESS == "all_must_work": raise_child_process_failed() info_summary_append(f"Not found: {libname=!r}") diff --git a/cuda_pathfinder/tests/test_load_nvidia_dynamic_lib.py b/cuda_pathfinder/tests/test_load_nvidia_dynamic_lib.py index 514d1d1674..a6fd595767 100644 --- a/cuda_pathfinder/tests/test_load_nvidia_dynamic_lib.py +++ b/cuda_pathfinder/tests/test_load_nvidia_dynamic_lib.py @@ -18,7 +18,7 @@ STATUS_NOT_FOUND, parse_dynamic_lib_subprocess_payload, ) -from cuda.pathfinder._utils.platform_aware import IS_WINDOWS, quote_for_shell +from cuda.pathfinder._utils.platform_aware import IS_WINDOWS, PLATFORM_MACHINE, quote_for_shell STRICTNESS = os.environ.get("CUDA_PATHFINDER_TEST_LOAD_NVIDIA_DYNAMIC_LIB_STRICTNESS", "see_what_works") assert STRICTNESS in ("see_what_works", "all_must_work") @@ -106,6 +106,14 @@ def _is_expected_load_nvidia_dynamic_lib_failure(libname): return False +def _skip_if_missing_nvcudla_runtime(libname: str, *, timeout: float) -> None: + if libname != "nvcudla" or PLATFORM_MACHINE != "aarch64": + return + if load_nvidia_dynamic_lib_module._loadable_via_canary_subprocess("nvcudla", timeout=timeout): + return + pytest.skip("libnvcudla.so is not loadable via canary subprocess on this host.") + + @pytest.mark.parametrize( "libname", supported_nvidia_libs.SUPPORTED_WINDOWS_DLLS if IS_WINDOWS else supported_nvidia_libs.SUPPORTED_LINUX_SONAMES, @@ -132,6 +140,7 @@ def raise_child_process_failed(): error_label="Load subprocess child process", ) if payload.status == STATUS_NOT_FOUND: + _skip_if_missing_nvcudla_runtime(libname, timeout=timeout) if STRICTNESS == "all_must_work" and not _is_expected_load_nvidia_dynamic_lib_failure(libname): raise_child_process_failed() info_summary_append(f"Not found: {libname=!r}") From 7c043023fbb9982ca0c4badaa2a9ab987888a706 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Fri, 3 Apr 2026 14:50:28 -0700 Subject: [PATCH 4/8] pathfinder: rely on nvcudla runtime probe in tests Remove the machine-architecture gating for cudla and nvcudla so they remain part of the normal Linux descriptor tables. Let the nvcudla canary probe decide whether cudla and nvcudla tests should run, which keeps strict test runs green on hosts without the platform runtime while still exercising real load behavior where libnvcudla.so is available. Made-with: Cursor --- .../_dynamic_libs/descriptor_catalog.py | 9 --- .../_dynamic_libs/load_nvidia_dynamic_lib.py | 9 +-- .../_dynamic_libs/supported_nvidia_libs.py | 68 +++++-------------- .../cuda/pathfinder/_utils/platform_aware.py | 2 - .../tests/test_driver_lib_loading.py | 4 +- cuda_pathfinder/tests/test_lib_descriptor.py | 30 +++----- .../tests/test_load_nvidia_dynamic_lib.py | 11 ++- 7 files changed, 32 insertions(+), 101 deletions(-) diff --git a/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/descriptor_catalog.py b/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/descriptor_catalog.py index 4aa94b543a..49b4b365df 100644 --- a/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/descriptor_catalog.py +++ b/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/descriptor_catalog.py @@ -8,8 +8,6 @@ from dataclasses import dataclass from typing import Literal -from cuda.pathfinder._utils.platform_aware import PLATFORM_MACHINE - PackagedWith = Literal["ctk", "other", "driver"] @@ -19,7 +17,6 @@ class DescriptorSpec: packaged_with: PackagedWith linux_sonames: tuple[str, ...] = () windows_dlls: tuple[str, ...] = () - platform_machines: tuple[str, ...] = () site_packages_linux: tuple[str, ...] = () site_packages_windows: tuple[str, ...] = () dependencies: tuple[str, ...] = () @@ -30,10 +27,6 @@ class DescriptorSpec: requires_rtld_deepbind: bool = False -def is_supported_on_current_machine(desc: DescriptorSpec) -> bool: - return not desc.platform_machines or PLATFORM_MACHINE in desc.platform_machines - - DESCRIPTOR_CATALOG: tuple[DescriptorSpec, ...] = ( # ----------------------------------------------------------------------- # CTK (CUDA Toolkit) libraries @@ -335,7 +328,6 @@ def is_supported_on_current_machine(desc: DescriptorSpec) -> bool: name="cudla", packaged_with="other", linux_sonames=("libcudla.so.1",), - platform_machines=("aarch64",), site_packages_linux=("nvidia/cu13/lib",), ), DescriptorSpec( @@ -404,7 +396,6 @@ def is_supported_on_current_machine(desc: DescriptorSpec) -> bool: name="nvcudla", packaged_with="driver", linux_sonames=("libnvcudla.so",), - platform_machines=("aarch64",), ), DescriptorSpec( name="nvml", diff --git a/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_nvidia_dynamic_lib.py b/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_nvidia_dynamic_lib.py index 4558572170..a7a8965d2e 100644 --- a/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_nvidia_dynamic_lib.py +++ b/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/load_nvidia_dynamic_lib.py @@ -9,7 +9,6 @@ import sys from typing import TYPE_CHECKING -from cuda.pathfinder._dynamic_libs.descriptor_catalog import is_supported_on_current_machine from cuda.pathfinder._dynamic_libs.lib_descriptor import LIB_DESCRIPTORS from cuda.pathfinder._dynamic_libs.load_dl_common import ( DynamicLibNotAvailableError, @@ -44,9 +43,7 @@ # (CTK, third-party, driver). _ALL_KNOWN_LIBNAMES: frozenset[str] = frozenset(LIB_DESCRIPTORS) _ALL_SUPPORTED_LIBNAMES: frozenset[str] = frozenset( - name - for name, desc in LIB_DESCRIPTORS.items() - if is_supported_on_current_machine(desc) and (desc.windows_dlls if IS_WINDOWS else desc.linux_sonames) + name for name, desc in LIB_DESCRIPTORS.items() if (desc.windows_dlls if IS_WINDOWS else desc.linux_sonames) ) _PLATFORM_NAME = "Windows" if IS_WINDOWS else "Linux" _CANARY_PROBE_TIMEOUT_SECONDS = 10.0 @@ -54,9 +51,7 @@ # Driver libraries: shipped with the NVIDIA display driver, always on the # system linker path. These skip all CTK search steps (site-packages, # conda, CUDA_PATH, canary) and go straight to system search. -_DRIVER_ONLY_LIBNAMES = frozenset( - name for name, desc in LIB_DESCRIPTORS.items() if desc.packaged_with == "driver" and name in _ALL_SUPPORTED_LIBNAMES -) +_DRIVER_ONLY_LIBNAMES = frozenset(name for name, desc in LIB_DESCRIPTORS.items() if desc.packaged_with == "driver") def _load_driver_lib_no_cache(desc: LibDescriptor) -> LoadedDL: diff --git a/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/supported_nvidia_libs.py b/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/supported_nvidia_libs.py index cb3302cfd8..db06411c6d 100644 --- a/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/supported_nvidia_libs.py +++ b/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/supported_nvidia_libs.py @@ -10,8 +10,7 @@ from __future__ import annotations -from cuda.pathfinder._dynamic_libs.descriptor_catalog import DESCRIPTOR_CATALOG, is_supported_on_current_machine -from cuda.pathfinder._dynamic_libs.lib_descriptor import LibDescriptor +from cuda.pathfinder._dynamic_libs.descriptor_catalog import DESCRIPTOR_CATALOG from cuda.pathfinder._utils.platform_aware import IS_WINDOWS _CTK_DESCRIPTORS = tuple(desc for desc in DESCRIPTOR_CATALOG if desc.packaged_with == "ctk") @@ -19,27 +18,12 @@ _DRIVER_DESCRIPTORS = tuple(desc for desc in DESCRIPTOR_CATALOG if desc.packaged_with == "driver") _NON_CTK_DESCRIPTORS = _OTHER_DESCRIPTORS + _DRIVER_DESCRIPTORS - -def _has_supported_linux_sonames(desc: LibDescriptor) -> bool: - return bool(desc.linux_sonames) and is_supported_on_current_machine(desc) - - -def _has_supported_windows_dlls(desc: LibDescriptor) -> bool: - return bool(desc.windows_dlls) and is_supported_on_current_machine(desc) - - -SUPPORTED_LIBNAMES_COMMON = tuple( - desc.name for desc in _CTK_DESCRIPTORS if _has_supported_linux_sonames(desc) and _has_supported_windows_dlls(desc) -) +SUPPORTED_LIBNAMES_COMMON = tuple(desc.name for desc in _CTK_DESCRIPTORS if desc.linux_sonames and desc.windows_dlls) SUPPORTED_LIBNAMES_LINUX_ONLY = tuple( - desc.name - for desc in _CTK_DESCRIPTORS - if _has_supported_linux_sonames(desc) and not _has_supported_windows_dlls(desc) + desc.name for desc in _CTK_DESCRIPTORS if desc.linux_sonames and not desc.windows_dlls ) SUPPORTED_LIBNAMES_WINDOWS_ONLY = tuple( - desc.name - for desc in _CTK_DESCRIPTORS - if _has_supported_windows_dlls(desc) and not _has_supported_linux_sonames(desc) + desc.name for desc in _CTK_DESCRIPTORS if desc.windows_dlls and not desc.linux_sonames ) SUPPORTED_LIBNAMES_LINUX = SUPPORTED_LIBNAMES_COMMON + SUPPORTED_LIBNAMES_LINUX_ONLY @@ -50,57 +34,37 @@ def _has_supported_windows_dlls(desc: LibDescriptor) -> bool: DIRECT_DEPENDENCIES_CTK = {desc.name: desc.dependencies for desc in _CTK_DESCRIPTORS if desc.dependencies} DIRECT_DEPENDENCIES = {desc.name: desc.dependencies for desc in DESCRIPTOR_CATALOG if desc.dependencies} -SUPPORTED_LINUX_SONAMES_CTK = { - desc.name: desc.linux_sonames for desc in _CTK_DESCRIPTORS if _has_supported_linux_sonames(desc) -} -SUPPORTED_LINUX_SONAMES_OTHER = { - desc.name: desc.linux_sonames for desc in _OTHER_DESCRIPTORS if _has_supported_linux_sonames(desc) -} -SUPPORTED_LINUX_SONAMES_DRIVER = { - desc.name: desc.linux_sonames for desc in _DRIVER_DESCRIPTORS if _has_supported_linux_sonames(desc) -} +SUPPORTED_LINUX_SONAMES_CTK = {desc.name: desc.linux_sonames for desc in _CTK_DESCRIPTORS if desc.linux_sonames} +SUPPORTED_LINUX_SONAMES_OTHER = {desc.name: desc.linux_sonames for desc in _OTHER_DESCRIPTORS if desc.linux_sonames} +SUPPORTED_LINUX_SONAMES_DRIVER = {desc.name: desc.linux_sonames for desc in _DRIVER_DESCRIPTORS if desc.linux_sonames} SUPPORTED_LINUX_SONAMES = SUPPORTED_LINUX_SONAMES_CTK | SUPPORTED_LINUX_SONAMES_OTHER | SUPPORTED_LINUX_SONAMES_DRIVER -SUPPORTED_WINDOWS_DLLS_CTK = { - desc.name: desc.windows_dlls for desc in _CTK_DESCRIPTORS if _has_supported_windows_dlls(desc) -} -SUPPORTED_WINDOWS_DLLS_OTHER = { - desc.name: desc.windows_dlls for desc in _OTHER_DESCRIPTORS if _has_supported_windows_dlls(desc) -} -SUPPORTED_WINDOWS_DLLS_DRIVER = { - desc.name: desc.windows_dlls for desc in _DRIVER_DESCRIPTORS if _has_supported_windows_dlls(desc) -} +SUPPORTED_WINDOWS_DLLS_CTK = {desc.name: desc.windows_dlls for desc in _CTK_DESCRIPTORS if desc.windows_dlls} +SUPPORTED_WINDOWS_DLLS_OTHER = {desc.name: desc.windows_dlls for desc in _OTHER_DESCRIPTORS if desc.windows_dlls} +SUPPORTED_WINDOWS_DLLS_DRIVER = {desc.name: desc.windows_dlls for desc in _DRIVER_DESCRIPTORS if desc.windows_dlls} SUPPORTED_WINDOWS_DLLS = SUPPORTED_WINDOWS_DLLS_CTK | SUPPORTED_WINDOWS_DLLS_OTHER | SUPPORTED_WINDOWS_DLLS_DRIVER LIBNAMES_REQUIRING_OS_ADD_DLL_DIRECTORY = tuple( - desc.name for desc in DESCRIPTOR_CATALOG if desc.requires_add_dll_directory and _has_supported_windows_dlls(desc) + desc.name for desc in DESCRIPTOR_CATALOG if desc.requires_add_dll_directory and desc.windows_dlls ) LIBNAMES_REQUIRING_RTLD_DEEPBIND = tuple( - desc.name for desc in DESCRIPTOR_CATALOG if desc.requires_rtld_deepbind and _has_supported_linux_sonames(desc) + desc.name for desc in DESCRIPTOR_CATALOG if desc.requires_rtld_deepbind and desc.linux_sonames ) # Based on output of toolshed/make_site_packages_libdirs_linux.py SITE_PACKAGES_LIBDIRS_LINUX_CTK = { - desc.name: desc.site_packages_linux - for desc in _CTK_DESCRIPTORS - if desc.site_packages_linux and _has_supported_linux_sonames(desc) + desc.name: desc.site_packages_linux for desc in _CTK_DESCRIPTORS if desc.site_packages_linux } SITE_PACKAGES_LIBDIRS_LINUX_OTHER = { - desc.name: desc.site_packages_linux - for desc in _NON_CTK_DESCRIPTORS - if desc.site_packages_linux and _has_supported_linux_sonames(desc) + desc.name: desc.site_packages_linux for desc in _NON_CTK_DESCRIPTORS if desc.site_packages_linux } SITE_PACKAGES_LIBDIRS_LINUX = SITE_PACKAGES_LIBDIRS_LINUX_CTK | SITE_PACKAGES_LIBDIRS_LINUX_OTHER SITE_PACKAGES_LIBDIRS_WINDOWS_CTK = { - desc.name: desc.site_packages_windows - for desc in _CTK_DESCRIPTORS - if desc.site_packages_windows and _has_supported_windows_dlls(desc) + desc.name: desc.site_packages_windows for desc in _CTK_DESCRIPTORS if desc.site_packages_windows } SITE_PACKAGES_LIBDIRS_WINDOWS_OTHER = { - desc.name: desc.site_packages_windows - for desc in _NON_CTK_DESCRIPTORS - if desc.site_packages_windows and _has_supported_windows_dlls(desc) + desc.name: desc.site_packages_windows for desc in _NON_CTK_DESCRIPTORS if desc.site_packages_windows } SITE_PACKAGES_LIBDIRS_WINDOWS = SITE_PACKAGES_LIBDIRS_WINDOWS_CTK | SITE_PACKAGES_LIBDIRS_WINDOWS_OTHER diff --git a/cuda_pathfinder/cuda/pathfinder/_utils/platform_aware.py b/cuda_pathfinder/cuda/pathfinder/_utils/platform_aware.py index 4247da3851..4aa0056816 100644 --- a/cuda_pathfinder/cuda/pathfinder/_utils/platform_aware.py +++ b/cuda_pathfinder/cuda/pathfinder/_utils/platform_aware.py @@ -1,11 +1,9 @@ # SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -import platform import sys IS_WINDOWS = sys.platform == "win32" -PLATFORM_MACHINE = platform.machine().lower() def quote_for_shell(s: str) -> str: diff --git a/cuda_pathfinder/tests/test_driver_lib_loading.py b/cuda_pathfinder/tests/test_driver_lib_loading.py index 19ba794dd1..d47d831d8a 100644 --- a/cuda_pathfinder/tests/test_driver_lib_loading.py +++ b/cuda_pathfinder/tests/test_driver_lib_loading.py @@ -25,7 +25,7 @@ _load_lib_no_cache, ) from cuda.pathfinder._dynamic_libs.subprocess_protocol import STATUS_NOT_FOUND, parse_dynamic_lib_subprocess_payload -from cuda.pathfinder._utils.platform_aware import IS_WINDOWS, PLATFORM_MACHINE, quote_for_shell +from cuda.pathfinder._utils.platform_aware import IS_WINDOWS, quote_for_shell STRICTNESS = os.environ.get("CUDA_PATHFINDER_TEST_LOAD_NVIDIA_DYNAMIC_LIB_STRICTNESS", "see_what_works") assert STRICTNESS in ("see_what_works", "all_must_work") @@ -42,7 +42,7 @@ def _make_loaded_dl(path, found_via): def _skip_if_missing_nvcudla_runtime(libname: str, *, timeout: float) -> None: - if libname != "nvcudla" or PLATFORM_MACHINE != "aarch64": + if libname != "nvcudla": return if load_nvidia_dynamic_lib_module._loadable_via_canary_subprocess("nvcudla", timeout=timeout): return diff --git a/cuda_pathfinder/tests/test_lib_descriptor.py b/cuda_pathfinder/tests/test_lib_descriptor.py index 17c8b304b6..cda96131e1 100644 --- a/cuda_pathfinder/tests/test_lib_descriptor.py +++ b/cuda_pathfinder/tests/test_lib_descriptor.py @@ -2,11 +2,10 @@ # SPDX-License-Identifier: Apache-2.0 """Tests verifying that the LibDescriptor registry faithfully represents -the current-platform data tables in supported_nvidia_libs.py.""" +the existing data tables in supported_nvidia_libs.py.""" import pytest -from cuda.pathfinder._dynamic_libs.descriptor_catalog import is_supported_on_current_machine from cuda.pathfinder._dynamic_libs.lib_descriptor import LIB_DESCRIPTORS from cuda.pathfinder._dynamic_libs.supported_nvidia_libs import ( DIRECT_DEPENDENCIES, @@ -34,8 +33,7 @@ def test_registry_covers_all_windows_dlls(): def test_registry_has_no_extra_entries(): expected = set(SUPPORTED_LINUX_SONAMES) | set(SUPPORTED_WINDOWS_DLLS) - extra = set(LIB_DESCRIPTORS) - expected - assert all(not is_supported_on_current_machine(LIB_DESCRIPTORS[name]) for name in extra) + assert set(LIB_DESCRIPTORS) == expected # --------------------------------------------------------------------------- @@ -45,30 +43,22 @@ def test_registry_has_no_extra_entries(): @pytest.mark.parametrize("name", sorted(LIB_DESCRIPTORS)) def test_linux_sonames_match(name): - desc = LIB_DESCRIPTORS[name] - expected = desc.linux_sonames if is_supported_on_current_machine(desc) else () - assert expected == SUPPORTED_LINUX_SONAMES.get(name, ()) + assert LIB_DESCRIPTORS[name].linux_sonames == SUPPORTED_LINUX_SONAMES.get(name, ()) @pytest.mark.parametrize("name", sorted(LIB_DESCRIPTORS)) def test_windows_dlls_match(name): - desc = LIB_DESCRIPTORS[name] - expected = desc.windows_dlls if is_supported_on_current_machine(desc) else () - assert expected == SUPPORTED_WINDOWS_DLLS.get(name, ()) + assert LIB_DESCRIPTORS[name].windows_dlls == SUPPORTED_WINDOWS_DLLS.get(name, ()) @pytest.mark.parametrize("name", sorted(LIB_DESCRIPTORS)) def test_site_packages_linux_match(name): - desc = LIB_DESCRIPTORS[name] - expected = desc.site_packages_linux if is_supported_on_current_machine(desc) else () - assert expected == SITE_PACKAGES_LIBDIRS_LINUX.get(name, ()) + assert LIB_DESCRIPTORS[name].site_packages_linux == SITE_PACKAGES_LIBDIRS_LINUX.get(name, ()) @pytest.mark.parametrize("name", sorted(LIB_DESCRIPTORS)) def test_site_packages_windows_match(name): - desc = LIB_DESCRIPTORS[name] - expected = desc.site_packages_windows if is_supported_on_current_machine(desc) else () - assert expected == SITE_PACKAGES_LIBDIRS_WINDOWS.get(name, ()) + assert LIB_DESCRIPTORS[name].site_packages_windows == SITE_PACKAGES_LIBDIRS_WINDOWS.get(name, ()) @pytest.mark.parametrize("name", sorted(LIB_DESCRIPTORS)) @@ -78,16 +68,12 @@ def test_dependencies_match(name): @pytest.mark.parametrize("name", sorted(LIB_DESCRIPTORS)) def test_requires_add_dll_directory_match(name): - desc = LIB_DESCRIPTORS[name] - expected = desc.requires_add_dll_directory if is_supported_on_current_machine(desc) else False - assert expected == (name in LIBNAMES_REQUIRING_OS_ADD_DLL_DIRECTORY) + assert LIB_DESCRIPTORS[name].requires_add_dll_directory == (name in LIBNAMES_REQUIRING_OS_ADD_DLL_DIRECTORY) @pytest.mark.parametrize("name", sorted(LIB_DESCRIPTORS)) def test_requires_rtld_deepbind_match(name): - desc = LIB_DESCRIPTORS[name] - expected = desc.requires_rtld_deepbind if is_supported_on_current_machine(desc) else False - assert expected == (name in LIBNAMES_REQUIRING_RTLD_DEEPBIND) + assert LIB_DESCRIPTORS[name].requires_rtld_deepbind == (name in LIBNAMES_REQUIRING_RTLD_DEEPBIND) # --------------------------------------------------------------------------- diff --git a/cuda_pathfinder/tests/test_load_nvidia_dynamic_lib.py b/cuda_pathfinder/tests/test_load_nvidia_dynamic_lib.py index a6fd595767..d46db9ef11 100644 --- a/cuda_pathfinder/tests/test_load_nvidia_dynamic_lib.py +++ b/cuda_pathfinder/tests/test_load_nvidia_dynamic_lib.py @@ -18,7 +18,7 @@ STATUS_NOT_FOUND, parse_dynamic_lib_subprocess_payload, ) -from cuda.pathfinder._utils.platform_aware import IS_WINDOWS, PLATFORM_MACHINE, quote_for_shell +from cuda.pathfinder._utils.platform_aware import IS_WINDOWS, quote_for_shell STRICTNESS = os.environ.get("CUDA_PATHFINDER_TEST_LOAD_NVIDIA_DYNAMIC_LIB_STRICTNESS", "see_what_works") assert STRICTNESS in ("see_what_works", "all_must_work") @@ -98,7 +98,7 @@ def test_known_but_platform_unavailable_libname_raises_dynamic_lib_not_available def _is_expected_load_nvidia_dynamic_lib_failure(libname): - if libname in ("cudla", "nvcudla", "nvpl_fftw") and platform.machine().lower() != "aarch64": + if libname == "nvpl_fftw" and platform.machine().lower() != "aarch64": return True dist_name_pattern = IMPORTLIB_METADATA_DISTRIBUTIONS_NAMES.get(libname) if dist_name_pattern is not None: @@ -107,7 +107,7 @@ def _is_expected_load_nvidia_dynamic_lib_failure(libname): def _skip_if_missing_nvcudla_runtime(libname: str, *, timeout: float) -> None: - if libname != "nvcudla" or PLATFORM_MACHINE != "aarch64": + if libname not in ("cudla", "nvcudla"): return if load_nvidia_dynamic_lib_module._loadable_via_canary_subprocess("nvcudla", timeout=timeout): return @@ -128,10 +128,7 @@ def raise_child_process_failed(): raise RuntimeError(build_child_process_failed_for_libname_message(libname, result)) if result.returncode != 0: - if libname == "cudla" and not load_nvidia_dynamic_lib_module._loadable_via_canary_subprocess( - "nvcudla", timeout=timeout - ): - pytest.skip("libnvcudla.so is not loadable via canary subprocess on this host.") + _skip_if_missing_nvcudla_runtime(libname, timeout=timeout) raise_child_process_failed() assert not result.stderr payload = parse_dynamic_lib_subprocess_payload( From 1a46a7943d58b06032ac02850d3ce4eb7d935324 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Fri, 3 Apr 2026 15:07:13 -0700 Subject: [PATCH 5/8] pathfinder: share libnvcudla test skip helper Move the libnvcudla.so skip logic into conftest so cudla and nvcudla tests use one shared rule. Keeping the helper in the pytest support layer avoids duplicate test code while still deferring the pathfinder import until the helper runs. Made-with: Cursor --- cuda_pathfinder/tests/conftest.py | 12 ++++++++++++ cuda_pathfinder/tests/test_driver_lib_loading.py | 12 ++---------- .../tests/test_load_nvidia_dynamic_lib.py | 13 +++---------- 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/cuda_pathfinder/tests/conftest.py b/cuda_pathfinder/tests/conftest.py index 47f8ff1612..e8a5e11b39 100644 --- a/cuda_pathfinder/tests/conftest.py +++ b/cuda_pathfinder/tests/conftest.py @@ -29,3 +29,15 @@ def _append(message): request.config.custom_info.append(f"{request.node.name}: {message}") return _append + + +def skip_if_missing_libnvcudla_so(libname: str, *, timeout: float) -> None: + if libname not in ("cudla", "nvcudla"): + return + # Keep the import inside the helper so unrelated import issues do not fail + # pytest collection for the whole test suite. + from cuda.pathfinder._dynamic_libs import load_nvidia_dynamic_lib as load_nvidia_dynamic_lib_module + + if load_nvidia_dynamic_lib_module._loadable_via_canary_subprocess("nvcudla", timeout=timeout): + return + pytest.skip("libnvcudla.so is not loadable via canary subprocess on this host.") diff --git a/cuda_pathfinder/tests/test_driver_lib_loading.py b/cuda_pathfinder/tests/test_driver_lib_loading.py index d47d831d8a..bf62a17d70 100644 --- a/cuda_pathfinder/tests/test_driver_lib_loading.py +++ b/cuda_pathfinder/tests/test_driver_lib_loading.py @@ -16,7 +16,7 @@ run_load_nvidia_dynamic_lib_in_subprocess, ) -from cuda.pathfinder._dynamic_libs import load_nvidia_dynamic_lib as load_nvidia_dynamic_lib_module +from conftest import skip_if_missing_libnvcudla_so from cuda.pathfinder._dynamic_libs.lib_descriptor import LIB_DESCRIPTORS from cuda.pathfinder._dynamic_libs.load_dl_common import DynamicLibNotFoundError, LoadedDL from cuda.pathfinder._dynamic_libs.load_nvidia_dynamic_lib import ( @@ -41,14 +41,6 @@ def _make_loaded_dl(path, found_via): return LoadedDL(path, False, 0xDEAD, found_via) -def _skip_if_missing_nvcudla_runtime(libname: str, *, timeout: float) -> None: - if libname != "nvcudla": - return - if load_nvidia_dynamic_lib_module._loadable_via_canary_subprocess("nvcudla", timeout=timeout): - return - pytest.skip("libnvcudla.so is not loadable via canary subprocess on this host.") - - # --------------------------------------------------------------------------- # _load_driver_lib_no_cache # --------------------------------------------------------------------------- @@ -156,7 +148,7 @@ def raise_child_process_failed(): error_label="Load subprocess child process", ) if payload.status == STATUS_NOT_FOUND: - _skip_if_missing_nvcudla_runtime(libname, timeout=timeout) + skip_if_missing_libnvcudla_so(libname, timeout=timeout) if STRICTNESS == "all_must_work": raise_child_process_failed() info_summary_append(f"Not found: {libname=!r}") diff --git a/cuda_pathfinder/tests/test_load_nvidia_dynamic_lib.py b/cuda_pathfinder/tests/test_load_nvidia_dynamic_lib.py index d46db9ef11..401e7dc13f 100644 --- a/cuda_pathfinder/tests/test_load_nvidia_dynamic_lib.py +++ b/cuda_pathfinder/tests/test_load_nvidia_dynamic_lib.py @@ -11,6 +11,7 @@ ) from local_helpers import have_distribution +from conftest import skip_if_missing_libnvcudla_so from cuda.pathfinder import DynamicLibNotAvailableError, DynamicLibUnknownError, load_nvidia_dynamic_lib from cuda.pathfinder._dynamic_libs import load_nvidia_dynamic_lib as load_nvidia_dynamic_lib_module from cuda.pathfinder._dynamic_libs import supported_nvidia_libs @@ -106,14 +107,6 @@ def _is_expected_load_nvidia_dynamic_lib_failure(libname): return False -def _skip_if_missing_nvcudla_runtime(libname: str, *, timeout: float) -> None: - if libname not in ("cudla", "nvcudla"): - return - if load_nvidia_dynamic_lib_module._loadable_via_canary_subprocess("nvcudla", timeout=timeout): - return - pytest.skip("libnvcudla.so is not loadable via canary subprocess on this host.") - - @pytest.mark.parametrize( "libname", supported_nvidia_libs.SUPPORTED_WINDOWS_DLLS if IS_WINDOWS else supported_nvidia_libs.SUPPORTED_LINUX_SONAMES, @@ -128,7 +121,7 @@ def raise_child_process_failed(): raise RuntimeError(build_child_process_failed_for_libname_message(libname, result)) if result.returncode != 0: - _skip_if_missing_nvcudla_runtime(libname, timeout=timeout) + skip_if_missing_libnvcudla_so(libname, timeout=timeout) raise_child_process_failed() assert not result.stderr payload = parse_dynamic_lib_subprocess_payload( @@ -137,7 +130,7 @@ def raise_child_process_failed(): error_label="Load subprocess child process", ) if payload.status == STATUS_NOT_FOUND: - _skip_if_missing_nvcudla_runtime(libname, timeout=timeout) + skip_if_missing_libnvcudla_so(libname, timeout=timeout) if STRICTNESS == "all_must_work" and not _is_expected_load_nvidia_dynamic_lib_failure(libname): raise_child_process_failed() info_summary_append(f"Not found: {libname=!r}") From 8b88040d813cf6595513f2f6562b09c80df457d6 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Fri, 3 Apr 2026 15:50:07 -0700 Subject: [PATCH 6/8] pathfinder: add cudla header lookup support Register cudla as a CTK header so locate_nvidia_header_directory() can find cudla.h in the standard cu13 wheel include directory. In strict header tests, skip cudla on hosts where libnvcudla.so is not available so Tegra setups still exercise the real path without making unsupported hosts fail. Made-with: Cursor --- .../cuda/pathfinder/_headers/header_descriptor_catalog.py | 7 +++++++ cuda_pathfinder/tests/test_find_nvidia_headers.py | 3 +++ 2 files changed, 10 insertions(+) diff --git a/cuda_pathfinder/cuda/pathfinder/_headers/header_descriptor_catalog.py b/cuda_pathfinder/cuda/pathfinder/_headers/header_descriptor_catalog.py index 81f93638c5..493445c8ad 100644 --- a/cuda_pathfinder/cuda/pathfinder/_headers/header_descriptor_catalog.py +++ b/cuda_pathfinder/cuda/pathfinder/_headers/header_descriptor_catalog.py @@ -134,6 +134,13 @@ class HeaderDescriptorSpec: site_packages_dirs=("nvidia/cu13/include", "nvidia/cuda_nvcc/nvvm/include"), anchor_include_rel_dirs=("nvvm/include",), ), + HeaderDescriptorSpec( + name="cudla", + packaged_with="ctk", + header_basename="cudla.h", + site_packages_dirs=("nvidia/cu13/include",), + available_on_windows=False, + ), # ----------------------------------------------------------------------- # Third-party / separately packaged headers # ----------------------------------------------------------------------- diff --git a/cuda_pathfinder/tests/test_find_nvidia_headers.py b/cuda_pathfinder/tests/test_find_nvidia_headers.py index a4ca8df602..e28f64d352 100644 --- a/cuda_pathfinder/tests/test_find_nvidia_headers.py +++ b/cuda_pathfinder/tests/test_find_nvidia_headers.py @@ -21,6 +21,7 @@ import pytest import cuda.pathfinder._headers.find_nvidia_headers as find_nvidia_headers_module +from conftest import skip_if_missing_libnvcudla_so from cuda.pathfinder import LocatedHeaderDir, find_nvidia_header_directory, locate_nvidia_header_directory from cuda.pathfinder._dynamic_libs.load_nvidia_dynamic_lib import ( _resolve_system_loaded_abs_path_in_subprocess, @@ -158,6 +159,8 @@ def test_locate_ctk_headers(info_summary_append, libname): h_filename = SUPPORTED_HEADERS_CTK[libname] assert os.path.isfile(os.path.join(hdr_dir, h_filename)) if STRICTNESS == "all_must_work": + if libname == "cudla": + skip_if_missing_libnvcudla_so(libname, timeout=30) assert hdr_dir is not None From 9327aea28b3e1ec09f848c6ac263d1d9a68e6d65 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Fri, 3 Apr 2026 16:00:33 -0700 Subject: [PATCH 7/8] pathfinder: classify cudla as a CTK library Move cudla into the CTK descriptor block so its packaging classification matches how it is shipped in toolkit installs and the optional nvidia-cudla wheel. This keeps the catalog organization consistent with the current understanding of cudla as a CUDA Toolkit component rather than a third-party add-on. Made-with: Cursor --- .../pathfinder/_dynamic_libs/descriptor_catalog.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/descriptor_catalog.py b/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/descriptor_catalog.py index 49b4b365df..f30afe5667 100644 --- a/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/descriptor_catalog.py +++ b/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/descriptor_catalog.py @@ -290,6 +290,12 @@ class DescriptorSpec: anchor_rel_dirs_windows=("extras/CUPTI/lib64", "bin"), ctk_root_canary_anchor_libnames=("cudart",), ), + DescriptorSpec( + name="cudla", + packaged_with="ctk", + linux_sonames=("libcudla.so.1",), + site_packages_linux=("nvidia/cu13/lib",), + ), # ----------------------------------------------------------------------- # Third-party / separately packaged libraries # ----------------------------------------------------------------------- @@ -324,12 +330,6 @@ class DescriptorSpec: site_packages_windows=("nvidia/cu13/bin", "nvidia/cu12/bin"), dependencies=("nvrtc",), ), - DescriptorSpec( - name="cudla", - packaged_with="other", - linux_sonames=("libcudla.so.1",), - site_packages_linux=("nvidia/cu13/lib",), - ), DescriptorSpec( name="cudss", packaged_with="other", From 5898b7adde831bf3d67e3a77291cb461866e6744 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Sat, 4 Apr 2026 10:48:24 -0700 Subject: [PATCH 8/8] Undo Copyright date change left over after undoing all other intermediate changes. --- cuda_pathfinder/cuda/pathfinder/_utils/platform_aware.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cuda_pathfinder/cuda/pathfinder/_utils/platform_aware.py b/cuda_pathfinder/cuda/pathfinder/_utils/platform_aware.py index 4aa0056816..72ecbc5359 100644 --- a/cuda_pathfinder/cuda/pathfinder/_utils/platform_aware.py +++ b/cuda_pathfinder/cuda/pathfinder/_utils/platform_aware.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 import sys