Skip to content

Commit 5bd23ec

Browse files
committed
Add find_nvidia_dynamic_library() and use from nvjitlink_linux.pyx, nvvm_linux.pyx
1 parent e82c878 commit 5bd23ec

6 files changed

Lines changed: 122 additions & 55 deletions

File tree

cuda_bindings/cuda/bindings/_internal/nvjitlink_linux.pyx

Lines changed: 6 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ import os
88

99
from libc.stdint cimport intptr_t
1010

11-
from .utils cimport get_nvjitlink_dso_version_suffix
12-
1311
from .utils import FunctionNotFoundError, NotSupportedError
1412

1513
from cuda.bindings import path_finder
@@ -57,49 +55,12 @@ cdef void* __nvJitLinkVersion = NULL
5755

5856

5957
cdef void* load_library(const int driver_ver) except* with gil:
60-
# TODO(rwgk): Move the version check here.
61-
# Intentionally ignoring returned value:
62-
get_nvjitlink_dso_version_suffix(driver_ver)
63-
64-
so_basename = "libnvJitLink.so"
65-
cdef void* handle = NULL;
66-
paths = path_finder.get_cuda_paths()
67-
paths_cudalib_dir = paths["cudalib_dir"]
68-
if not paths_cudalib_dir:
69-
raise RuntimeError("Failure obtaining paths_cudalib_dir")
70-
if not paths_cudalib_dir.info:
71-
raise RuntimeError("Failure obtaining paths_cudalib_dir.info")
72-
primary_so_dir = paths_cudalib_dir.info + "/"
73-
candidate_so_dirs = [primary_so_dir]
74-
libs = ["/lib/", "/lib64/"]
75-
for _ in range(2):
76-
alt_dir = libs[0].join(primary_so_dir.rsplit(libs[1], 1))
77-
if alt_dir not in candidate_so_dirs:
78-
candidate_so_dirs.append(alt_dir)
79-
libs.reverse()
80-
candidate_so_names = [
81-
so_dirname + so_basename
82-
for so_dirname in candidate_so_dirs]
83-
error_messages = []
84-
for so_name in candidate_so_names:
85-
if not os.path.exists(so_name):
86-
error_messages.append(f"No such file: {so_name}")
87-
else:
88-
handle = dlopen(so_name.encode(), RTLD_NOW | RTLD_GLOBAL)
89-
if handle != NULL:
90-
return handle
91-
err_msg = dlerror().decode(errors="backslashreplace")
92-
error_messages.append(f"Failed to dlopen {so_name}: {err_msg}")
93-
attachment = []
94-
for so_dirname in candidate_so_dirs:
95-
attachment.append(f" listdir({repr(so_dirname)}):")
96-
if not os.path.isdir(so_dirname):
97-
attachment.append(" DIRECTORY DOES NOT EXIST")
98-
else:
99-
for node in sorted(os.listdir(so_dirname)):
100-
attachment.append(f" {node}")
101-
attachment = "\n".join(attachment)
102-
raise RuntimeError(f"Unable to load {so_basename} from: {', '.join(error_messages)}\n{attachment}")
58+
so_name = path_finder.find_nvidia_dynamic_library("nvJitLink")
59+
cdef void* handle = dlopen(so_name.encode(), RTLD_NOW | RTLD_GLOBAL)
60+
if handle != NULL:
61+
return handle
62+
err_msg = dlerror().decode(errors="backslashreplace")
63+
raise RuntimeError(f"Failed to dlopen {so_name}: {err_msg}")
10364

10465

10566
cdef int _check_or_init_nvjitlink() except -1 nogil:

cuda_bindings/cuda/bindings/_internal/nvvm_linux.pyx

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,17 +51,12 @@ cdef void* __nvvmGetProgramLog = NULL
5151

5252

5353
cdef void* load_library(const int driver_ver) except* with gil:
54-
cdef void* handle = NULL;
55-
paths = path_finder.get_cuda_paths()
56-
paths_nvvm = paths["nvvm"]
57-
if paths_nvvm:
58-
so_name = paths_nvvm.info
59-
handle = dlopen(so_name.encode(), RTLD_NOW | RTLD_GLOBAL)
60-
if handle == NULL:
61-
err_msg = dlerror()
62-
raise RuntimeError(f'Failed to dlopen {so_name} ({err_msg.decode()})')
54+
so_name = path_finder.find_nvidia_dynamic_library("nvvm")
55+
cdef void* handle = dlopen(so_name.encode(), RTLD_NOW | RTLD_GLOBAL)
56+
if handle != NULL:
6357
return handle
64-
raise RuntimeError('Unable to locate libnvvm.so')
58+
err_msg = dlerror().decode(errors="backslashreplace")
59+
raise RuntimeError(f"Failed to dlopen {so_name}: {err_msg}")
6560

6661

6762
cdef int _check_or_init_nvvm() except -1 nogil:
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# Copyright 2024-2025 NVIDIA Corporation. All rights reserved.
2+
#
3+
# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE
4+
5+
import functools
6+
import os
7+
8+
from .cuda_paths import get_cuda_paths
9+
from .find_nvidia_lib_dirs import find_nvidia_lib_dirs
10+
11+
12+
def _find_using_nvidia_lib_dirs(so_basename, error_messages, attachments):
13+
for lib_dir in find_nvidia_lib_dirs():
14+
so_name = os.path.join(lib_dir, so_basename)
15+
if os.path.isfile(so_name):
16+
return so_name
17+
error_messages.append(f"No such file: {so_name}")
18+
for lib_dir in find_nvidia_lib_dirs():
19+
attachments.append(f" listdir({repr(lib_dir)}):")
20+
for node in sorted(os.listdir(lib_dir)):
21+
attachments.append(f" {node}")
22+
return None
23+
24+
25+
def _get_cuda_paths_info(key, error_messages):
26+
env_path_tuple = get_cuda_paths()[key]
27+
if not env_path_tuple:
28+
error_messages.append(f'Failure obtaining get_cuda_paths()["{key}"]')
29+
return None
30+
if not env_path_tuple.info:
31+
error_messages.append(f'Failure obtaining get_cuda_paths()["{key}"].info')
32+
return None
33+
return env_path_tuple.info
34+
35+
36+
def _find_using_lib_dir(so_basename, error_messages, attachments):
37+
lib_dir = _get_cuda_paths_info("cudalib_dir", error_messages)
38+
primary_so_dir = lib_dir + "/"
39+
candidate_so_dirs = [primary_so_dir]
40+
libs = ["/lib/", "/lib64/"]
41+
for _ in range(2):
42+
alt_dir = libs[0].join(primary_so_dir.rsplit(libs[1], 1))
43+
if alt_dir not in candidate_so_dirs:
44+
candidate_so_dirs.append(alt_dir)
45+
libs.reverse()
46+
candidate_so_names = [so_dirname + so_basename for so_dirname in candidate_so_dirs]
47+
error_messages = []
48+
for so_name in candidate_so_names:
49+
if os.path.isfile(so_name):
50+
return so_name
51+
error_messages.append(f"No such file: {so_name}")
52+
for so_dirname in candidate_so_dirs:
53+
attachments.append(f" listdir({repr(so_dirname)}):")
54+
if not os.path.isdir(so_dirname):
55+
attachments.append(" DIRECTORY DOES NOT EXIST")
56+
else:
57+
for node in sorted(os.listdir(so_dirname)):
58+
attachments.append(f" {node}")
59+
return None
60+
61+
62+
@functools.cache
63+
def find_nvidia_dynamic_library(libbasename):
64+
so_basename = f"lib{libbasename}.so"
65+
error_messages = []
66+
attachments = []
67+
so_name = _find_using_nvidia_lib_dirs(so_basename, error_messages, attachments)
68+
if so_name is None:
69+
if libbasename == "nvvm":
70+
so_name = _get_cuda_paths_info("nvvm", error_messages)
71+
else:
72+
so_name = _find_using_lib_dir(so_basename, error_messages, attachments)
73+
if so_name is None:
74+
attachments = "\n".join(attachments)
75+
raise RuntimeError(f"Unable to load {so_basename} from: {', '.join(error_messages)}\n{attachments}")
76+
return so_name
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Copyright 2024-2025 NVIDIA Corporation. All rights reserved.
2+
#
3+
# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE
4+
5+
import functools
6+
import os
7+
import sys
8+
9+
10+
@functools.cache
11+
def _find_nvidia_lib_dirs(sys_path):
12+
results = []
13+
for base in sys_path:
14+
nvidia_base = os.path.join(base, "nvidia")
15+
if not os.path.isdir(nvidia_base):
16+
continue
17+
try:
18+
subdirs = os.listdir(nvidia_base)
19+
except OSError:
20+
continue
21+
for sub in subdirs:
22+
sub_path = os.path.join(nvidia_base, sub)
23+
lib_path = os.path.join(sub_path, "lib")
24+
if os.path.isdir(lib_path):
25+
results.append(lib_path)
26+
return results
27+
28+
29+
def find_nvidia_lib_dirs():
30+
return _find_nvidia_lib_dirs(tuple(sys.path))

cuda_bindings/cuda/bindings/path_finder.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@
1616
get_nvidia_static_cudalib_ctk,
1717
get_system_ctk,
1818
)
19+
from cuda.bindings._path_finder_utils.find_nvidia_dynamic_library import find_nvidia_dynamic_library
1920

2021
__all__ = [
22+
"find_nvidia_dynamic_library",
2123
"get_conda_ctk",
2224
"get_conda_include_dir",
2325
"get_cuda_home",

cuda_bindings/tests/path_finder.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@
44

55
for k, v in paths.items():
66
print(f"{k}: {v}", flush=True)
7+
8+
print(path_finder.find_nvidia_dynamic_library("nvvm"))
9+
print(path_finder.find_nvidia_dynamic_library("nvJitLink"))

0 commit comments

Comments
 (0)