Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions cuda_pathfinder/cuda/pathfinder/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

from cuda.pathfinder._version import __version__ # noqa: F401

from cuda.pathfinder._binaries.find_nvidia_binaries import find_nvidia_binary as find_nvidia_binary
from cuda.pathfinder._binaries.supported_nvidia_binaries import SUPPORTED_BINARIES as SUPPORTED_NVIDIA_BINARIES
from cuda.pathfinder._dynamic_libs.load_dl_common import DynamicLibNotFoundError as DynamicLibNotFoundError
from cuda.pathfinder._dynamic_libs.load_dl_common import LoadedDL as LoadedDL
from cuda.pathfinder._dynamic_libs.load_nvidia_dynamic_lib import load_nvidia_dynamic_lib as load_nvidia_dynamic_lib
Expand All @@ -13,6 +15,15 @@
)
from cuda.pathfinder._headers.find_nvidia_headers import find_nvidia_header_directory as find_nvidia_header_directory
from cuda.pathfinder._headers.supported_nvidia_headers import SUPPORTED_HEADERS_CTK as _SUPPORTED_HEADERS_CTK
from cuda.pathfinder._static_libs.find_nvidia_static_libs import find_nvidia_static_lib as find_nvidia_static_lib
from cuda.pathfinder._static_libs.supported_nvidia_static_libs import (
SUPPORTED_STATIC_LIBS as SUPPORTED_NVIDIA_STATIC_LIBS,
)
from cuda.pathfinder._utils.toolchain_tracker import (
SearchContext as SearchContext,
ToolchainMismatchError as ToolchainMismatchError,
reset_default_context as reset_default_context,
)

# Indirections to help Sphinx find the docstrings.
#: Mapping from short CUDA Toolkit (CTK) library names to their canonical
Expand Down
110 changes: 110 additions & 0 deletions cuda_pathfinder/cuda/pathfinder/_binaries/find_nvidia_binaries.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

import functools
import os
from typing import Sequence

from cuda.pathfinder._binaries.supported_nvidia_binaries import SITE_PACKAGES_BINDIRS, SUPPORTED_BINARIES
from cuda.pathfinder._utils.env_vars import get_cuda_home_or_path
from cuda.pathfinder._utils.find_sub_dirs import find_sub_dirs_all_sitepackages
from cuda.pathfinder._utils.path_utils import _abs_norm
from cuda.pathfinder._utils.toolchain_tracker import (
SearchContext,
SearchLocation,
ToolchainSource,
get_default_context,
)


def _binary_filename_variants(name: str) -> Sequence[str]:
"""Generate filename variants for a binary (cross-platform).

Args:
name: Base binary name.

Returns:
Tuple of possible filenames (e.g., "nvcc", "nvcc.exe").
"""
return (name, f"{name}.exe")


def _get_site_packages_subdirs(binary_name: str) -> Sequence[str]:
"""Get site-packages sub-directories for a binary.

Args:
binary_name: Name of the binary.

Returns:
List of sub-directories to search, or empty list if binary not in site-packages.
"""
relative_directories = SITE_PACKAGES_BINDIRS.get(binary_name)
if not relative_directories:
return []

# Expand site-packages paths
sub_directories = []
for relative_directory in relative_directories:
for found_dir in find_sub_dirs_all_sitepackages(tuple(relative_directory.split("/"))):
sub_directories.append(found_dir)
return sub_directories


# Define search locations for binaries
def _create_search_locations(binary_name: str) -> list[SearchLocation]:
"""Create search location configurations for a specific binary.

Args:
binary_name: Name of the binary to search for.

Returns:
List of SearchLocation objects to try.
"""
return [
SearchLocation(
source=ToolchainSource.SITE_PACKAGES,
base_dir_func=lambda: None, # Use subdirs for full paths
subdirs=_get_site_packages_subdirs(binary_name),
filename_variants=_binary_filename_variants,
),
SearchLocation(
source=ToolchainSource.CONDA,
base_dir_func=lambda: os.environ.get("CONDA_PREFIX"),
subdirs=["Library/bin", "bin"], # Windows and Unix layouts
filename_variants=_binary_filename_variants,
),
SearchLocation(
source=ToolchainSource.CUDA_HOME,
base_dir_func=get_cuda_home_or_path,
subdirs=["bin"],
filename_variants=_binary_filename_variants,
),
]


@functools.cache
def find_nvidia_binary(binary_name: str, *, context: SearchContext | None = None) -> str | None:
"""Locate a CUDA binary executable.

Args:
binary_name: Name of the binary (e.g., "nvdisasm", "cuobjdump").
context: Optional SearchContext for toolchain consistency tracking.
If None, uses the default module-level context.

Returns:
Absolute path to the binary, or None if not found.

Raises:
RuntimeError: If binary_name is not supported.
ToolchainMismatchError: If binary found in different source than
the context's preferred source.
"""
if binary_name not in SUPPORTED_BINARIES:
raise RuntimeError(f"UNKNOWN {binary_name=}")

if context is None:
context = get_default_context()

locations = _create_search_locations(binary_name)
path = context.find(binary_name, locations)
return _abs_norm(path) if path else None
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

# THIS FILE NEEDS TO BE REVIEWED/UPDATED FOR EACH CTK RELEASE
# Likely candidates for updates are:
# SUPPORTED_BINARIES
# SITE_PACKAGES_BINDIRS

from cuda.pathfinder._utils.platform_aware import IS_WINDOWS

# Supported CUDA binaries that can be found
SUPPORTED_BINARIES_COMMON = (
"nvdisasm",
"cuobjdump",
)

SUPPORTED_BINARIES = SUPPORTED_BINARIES_COMMON

# Map from binary name to relative paths under site-packages
# These are typically from cuda-toolkit[nvcc] wheels
SITE_PACKAGES_BINDIRS = {
"nvdisasm": ["nvidia/cuda_nvcc/bin"],
"cuobjdump": ["nvidia/cuda_nvcc/bin"],
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,10 @@
from cuda.pathfinder._headers import supported_nvidia_headers
from cuda.pathfinder._utils.env_vars import get_cuda_home_or_path
from cuda.pathfinder._utils.find_sub_dirs import find_sub_dirs_all_sitepackages
from cuda.pathfinder._utils.path_utils import _abs_norm
from cuda.pathfinder._utils.platform_aware import IS_WINDOWS


def _abs_norm(path: str | None) -> str | None:
if path:
return os.path.normpath(os.path.abspath(path))
return None


def _joined_isfile(dirpath: str, basename: str) -> bool:
return os.path.isfile(os.path.join(dirpath, basename))

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

"""Configuration for artifact search patterns across platforms and environments."""

from dataclasses import dataclass

from cuda.pathfinder._utils.platform_aware import IS_WINDOWS


@dataclass(frozen=True)
class ArtifactSearchConfig:
"""Configuration for searching a specific artifact (platform-resolved at init).

Attributes:
canonical_name: Platform-agnostic identifier for the artifact.
filenames: Filenames to search for on the current platform.
conda_dirs: Directory paths relative to CONDA_PREFIX.
cuda_home_dirs: Directory paths relative to CUDA_HOME.
search_targets_subdirs: Whether to search targets/*/{lib,lib64} subdirs
for cross-compilation setups (Linux only).
"""

canonical_name: str
filenames: tuple[str, ...]
conda_dirs: tuple[str, ...]
cuda_home_dirs: tuple[str, ...]
search_targets_subdirs: bool = False


def _create_config(
canonical_name: str,
linux_filenames: tuple[str, ...],
windows_filenames: tuple[str, ...],
conda_linux_dirs: tuple[str, ...],
conda_windows_dirs: tuple[str, ...],
cuda_home_linux_dirs: tuple[str, ...],
cuda_home_windows_dirs: tuple[str, ...],
search_targets_subdirs: bool = False,
) -> ArtifactSearchConfig:
"""Create a platform-specific config by selecting appropriate values at init time."""
return ArtifactSearchConfig(
canonical_name=canonical_name,
filenames=windows_filenames if IS_WINDOWS else linux_filenames,
conda_dirs=conda_windows_dirs if IS_WINDOWS else conda_linux_dirs,
cuda_home_dirs=cuda_home_windows_dirs if IS_WINDOWS else cuda_home_linux_dirs,
search_targets_subdirs=search_targets_subdirs,
)


# Registry of all supported artifacts with their search configurations
# Platform selection happens once at module import time via _create_config
ARTIFACT_CONFIGS = {
"libcudadevrt.a": _create_config(
canonical_name="cudadevrt",
linux_filenames=("libcudadevrt.a",),
windows_filenames=("cudadevrt.lib",),
conda_linux_dirs=("lib",),
conda_windows_dirs=("Library/lib", "Library/lib/x64"),
cuda_home_linux_dirs=("lib64", "lib"),
cuda_home_windows_dirs=("lib/x64", "lib"),
search_targets_subdirs=True,
),
"libdevice.10.bc": _create_config(
canonical_name="libdevice",
linux_filenames=("libdevice.10.bc",),
windows_filenames=("libdevice.10.bc",),
conda_linux_dirs=("nvvm/libdevice",),
conda_windows_dirs=("Library/nvvm/libdevice",),
cuda_home_linux_dirs=("nvvm/libdevice",),
cuda_home_windows_dirs=("nvvm/libdevice",),
search_targets_subdirs=False,
),
}
Loading