server / source /cuda /pathfinder /_dynamic_libs /find_nvidia_dynamic_lib.py
Harmony18090's picture
Add source batch 2/11
76f9669 verified
raw
history blame
7.63 kB
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
import glob
import os
from collections.abc import Sequence
from cuda.pathfinder._dynamic_libs.load_dl_common import DynamicLibNotFoundError
from cuda.pathfinder._dynamic_libs.supported_nvidia_libs import (
SITE_PACKAGES_LIBDIRS_LINUX,
SITE_PACKAGES_LIBDIRS_WINDOWS,
is_suppressed_dll_file,
)
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.platform_aware import IS_WINDOWS
def _no_such_file_in_sub_dirs(
sub_dirs: Sequence[str], file_wild: str, error_messages: list[str], attachments: list[str]
) -> None:
error_messages.append(f"No such file: {file_wild}")
for sub_dir in find_sub_dirs_all_sitepackages(sub_dirs):
attachments.append(f' listdir("{sub_dir}"):')
for node in sorted(os.listdir(sub_dir)):
attachments.append(f" {node}")
def _find_so_using_nvidia_lib_dirs(
libname: str, so_basename: str, error_messages: list[str], attachments: list[str]
) -> str | None:
rel_dirs = SITE_PACKAGES_LIBDIRS_LINUX.get(libname)
if rel_dirs is not None:
sub_dirs_searched = []
file_wild = so_basename + "*"
for rel_dir in rel_dirs:
sub_dir = tuple(rel_dir.split(os.path.sep))
for abs_dir in find_sub_dirs_all_sitepackages(sub_dir):
# First look for an exact match
so_name = os.path.join(abs_dir, so_basename)
if os.path.isfile(so_name):
return so_name
# Look for a versioned library
# Using sort here mainly to make the result deterministic.
for so_name in sorted(glob.glob(os.path.join(abs_dir, file_wild))):
if os.path.isfile(so_name):
return so_name
sub_dirs_searched.append(sub_dir)
for sub_dir in sub_dirs_searched:
_no_such_file_in_sub_dirs(sub_dir, file_wild, error_messages, attachments)
return None
def _find_dll_under_dir(dirpath: str, file_wild: str) -> str | None:
for path in sorted(glob.glob(os.path.join(dirpath, file_wild))):
if not os.path.isfile(path):
continue
if not is_suppressed_dll_file(os.path.basename(path)):
return path
return None
def _find_dll_using_nvidia_bin_dirs(
libname: str, lib_searched_for: str, error_messages: list[str], attachments: list[str]
) -> str | None:
rel_dirs = SITE_PACKAGES_LIBDIRS_WINDOWS.get(libname)
if rel_dirs is not None:
sub_dirs_searched = []
for rel_dir in rel_dirs:
sub_dir = tuple(rel_dir.split(os.path.sep))
for abs_dir in find_sub_dirs_all_sitepackages(sub_dir):
dll_name = _find_dll_under_dir(abs_dir, lib_searched_for)
if dll_name is not None:
return dll_name
sub_dirs_searched.append(sub_dir)
for sub_dir in sub_dirs_searched:
_no_such_file_in_sub_dirs(sub_dir, lib_searched_for, error_messages, attachments)
return None
def _find_lib_dir_using_anchor_point(libname: str, anchor_point: str, linux_lib_dir: str) -> str | None:
# Resolve paths for the four cases:
# Windows/Linux x nvvm yes/no
if IS_WINDOWS:
if libname == "nvvm": # noqa: SIM108
rel_paths = [
"nvvm/bin/*", # CTK 13
"nvvm/bin", # CTK 12
]
else:
rel_paths = [
"bin/x64", # CTK 13
"bin", # CTK 12
]
else:
if libname == "nvvm": # noqa: SIM108
rel_paths = ["nvvm/lib64"]
else:
rel_paths = [linux_lib_dir]
for rel_path in rel_paths:
for dirname in sorted(glob.glob(os.path.join(anchor_point, rel_path))):
if os.path.isdir(dirname):
return dirname
return None
def _find_lib_dir_using_cuda_home(libname: str) -> str | None:
cuda_home = get_cuda_home_or_path()
if cuda_home is None:
return None
return _find_lib_dir_using_anchor_point(libname, anchor_point=cuda_home, linux_lib_dir="lib64")
def _find_lib_dir_using_conda_prefix(libname: str) -> str | None:
conda_prefix = os.environ.get("CONDA_PREFIX")
if not conda_prefix:
return None
return _find_lib_dir_using_anchor_point(
libname, anchor_point=os.path.join(conda_prefix, "Library") if IS_WINDOWS else conda_prefix, linux_lib_dir="lib"
)
def _find_so_using_lib_dir(
lib_dir: str, so_basename: str, error_messages: list[str], attachments: list[str]
) -> str | None:
so_name = os.path.join(lib_dir, so_basename)
if os.path.isfile(so_name):
return so_name
error_messages.append(f"No such file: {so_name}")
attachments.append(f' listdir("{lib_dir}"):')
if not os.path.isdir(lib_dir):
attachments.append(" DIRECTORY DOES NOT EXIST")
else:
for node in sorted(os.listdir(lib_dir)):
attachments.append(f" {node}")
return None
def _find_dll_using_lib_dir(
lib_dir: str, libname: str, error_messages: list[str], attachments: list[str]
) -> str | None:
file_wild = libname + "*.dll"
dll_name = _find_dll_under_dir(lib_dir, file_wild)
if dll_name is not None:
return dll_name
error_messages.append(f"No such file: {file_wild}")
attachments.append(f' listdir("{lib_dir}"):')
for node in sorted(os.listdir(lib_dir)):
attachments.append(f" {node}")
return None
class _FindNvidiaDynamicLib:
def __init__(self, libname: str):
self.libname = libname
if IS_WINDOWS:
self.lib_searched_for = f"{libname}*.dll"
else:
self.lib_searched_for = f"lib{libname}.so"
self.error_messages: list[str] = []
self.attachments: list[str] = []
self.abs_path: str | None = None
def try_site_packages(self) -> str | None:
if IS_WINDOWS:
return _find_dll_using_nvidia_bin_dirs(
self.libname,
self.lib_searched_for,
self.error_messages,
self.attachments,
)
else:
return _find_so_using_nvidia_lib_dirs(
self.libname,
self.lib_searched_for,
self.error_messages,
self.attachments,
)
def try_with_conda_prefix(self) -> str | None:
return self._find_using_lib_dir(_find_lib_dir_using_conda_prefix(self.libname))
def try_with_cuda_home(self) -> str | None:
return self._find_using_lib_dir(_find_lib_dir_using_cuda_home(self.libname))
def _find_using_lib_dir(self, lib_dir: str | None) -> str | None:
if lib_dir is None:
return None
if IS_WINDOWS:
return _find_dll_using_lib_dir(
lib_dir,
self.libname,
self.error_messages,
self.attachments,
)
else:
return _find_so_using_lib_dir(
lib_dir,
self.lib_searched_for,
self.error_messages,
self.attachments,
)
def raise_not_found_error(self) -> None:
err = ", ".join(self.error_messages)
att = "\n".join(self.attachments)
raise DynamicLibNotFoundError(f'Failure finding "{self.lib_searched_for}": {err}\n{att}')