From 588643f6a8abbd10a0c704b4d60f26db7d28d898 Mon Sep 17 00:00:00 2001 From: David Seifert Date: Wed, 22 May 2024 15:55:55 +0200 Subject: [PATCH] cuda: fix `cuda.find_library()` hardcoded to yield true * Previously, cuda would just plainly prepend `-l` to the libname. * By relying on the host compiler to find libraries, we now get more subtle failures, such as CUDA modules not being found anymore. * We need to simplify these CUDA modules when nvcc is used for linking, since this may have side-effects from the cuda toolchain. Closes: #13240 --- mesonbuild/compilers/compilers.py | 2 +- mesonbuild/compilers/cuda.py | 2 +- mesonbuild/dependencies/cuda.py | 43 ++++++++++++++++++++----------- 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 44b998a67cda..673b63f9d581 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -1046,7 +1046,7 @@ def get_dependency_compile_args(self, dep: 'Dependency') -> T.List[str]: return dep.get_compile_args() def get_dependency_link_args(self, dep: 'Dependency') -> T.List[str]: - return dep.get_link_args() + return dep.get_link_args(self.get_language()) @classmethod def use_linker_args(cls, linker: str, version: str) -> T.List[str]: diff --git a/mesonbuild/compilers/cuda.py b/mesonbuild/compilers/cuda.py index 3761019b9945..7231a267c02b 100644 --- a/mesonbuild/compilers/cuda.py +++ b/mesonbuild/compilers/cuda.py @@ -768,7 +768,7 @@ def get_std_exe_link_args(self) -> T.List[str]: def find_library(self, libname: str, env: 'Environment', extra_dirs: T.List[str], libtype: LibType = LibType.PREFER_SHARED, lib_prefix_warning: bool = True) -> T.Optional[T.List[str]]: - return ['-l' + libname] # FIXME + return self.host_compiler.find_library(libname, env, extra_dirs, libtype, lib_prefix_warning) def get_crt_compile_args(self, crt_val: str, buildtype: str) -> T.List[str]: return self._to_host_flags(self.host_compiler.get_crt_compile_args(crt_val, buildtype)) diff --git a/mesonbuild/dependencies/cuda.py b/mesonbuild/dependencies/cuda.py index a38e325b8741..82bf5ad82b94 100644 --- a/mesonbuild/dependencies/cuda.py +++ b/mesonbuild/dependencies/cuda.py @@ -41,11 +41,6 @@ def __init__(self, environment: 'Environment', kwargs: T.Dict[str, T.Any]) -> No req_modules = ['cudart'] if kwargs.get('static', True): req_modules = ['cudart_static'] - machine = self.env.machines[self.for_machine] - if machine.is_linux(): - # extracted by running - # nvcc -v foo.o - req_modules += ['rt', 'pthread', 'dl'] self.requested_modules = req_modules + self.requested_modules (self.cuda_path, self.version, self.is_found) = self._detect_cuda_path_and_version() @@ -61,12 +56,9 @@ def __init__(self, environment: 'Environment', kwargs: T.Dict[str, T.Any]) -> No self.incdir = os.path.join(self.cuda_path, 'include') self.compile_args += [f'-I{self.incdir}'] - if self.language != 'cuda': - arch_libdir = self._detect_arch_libdir() - self.libdir = os.path.join(self.cuda_path, arch_libdir) - mlog.debug('CUDA library directory is', mlog.bold(self.libdir)) - else: - self.libdir = None + arch_libdir = self._detect_arch_libdir() + self.libdir = os.path.join(self.cuda_path, arch_libdir) + mlog.debug('CUDA library directory is', mlog.bold(self.libdir)) self.is_found = self._find_requested_libraries() @@ -244,7 +236,14 @@ def _find_requested_libraries(self) -> bool: all_found = True for module in self.requested_modules: - args = self.clib_compiler.find_library(module, self.env, [self.libdir] if self.libdir else []) + args = self.clib_compiler.find_library(module, self.env, [self.libdir]) + if module == 'cudart_static' and self.language != 'cuda': + machine = self.env.machines[self.for_machine] + if machine.is_linux(): + # extracted by running + # nvcc -v foo.o + args += ['-lrt', '-lpthread', '-ldl'] + if args is None: self._report_dependency_error(f'Couldn\'t find requested CUDA module \'{module}\'') all_found = False @@ -286,10 +285,24 @@ def get_requested(self, kwargs: T.Dict[str, T.Any]) -> T.List[str]: def get_link_args(self, language: T.Optional[str] = None, raw: bool = False) -> T.List[str]: args: T.List[str] = [] - if self.libdir: - args += self.clib_compiler.get_linker_search_args(self.libdir) for lib in self.requested_modules: - args += self.lib_modules[lib] + link_args = self.lib_modules[lib] + # Turn canonical arguments like + # /opt/cuda/lib64/libcublas.so + # back into + # -lcublas + # since this is how CUDA modules were passed to nvcc since time immemorial + if language == 'cuda': + if lib in frozenset(['cudart', 'cudart_static']): + # nvcc always links these unconditionally + mlog.debug(f'Not adding \'{lib}\' to dependency, since nvcc will link it implicitly') + link_args = [] + elif link_args and link_args[0].startswith(self.libdir): + # module included with CUDA, nvcc knows how to find these itself + mlog.debug(f'CUDA module \'{lib}\' found in CUDA libdir') + link_args = ['-l' + lib] + args += link_args + return args packages['cuda'] = CudaDependency