fix LDFLAGS for cuda

LDFLAGS may contain flags that nvcc is unable to handle and these flags
need to be processed before we pass them to nvcc
pull/13609/head
Zihua Wu 3 months ago committed by Eli Schwartz
parent cd0981bb3c
commit e940d58677
No known key found for this signature in database
GPG Key ID: CEB167EFB5722BD6
  1. 51
      mesonbuild/compilers/cuda.py
  2. 9
      mesonbuild/compilers/detect.py

@ -45,7 +45,7 @@ cuda_debug_args: T.Dict[bool, T.List[str]] = {
} }
class _Phase(enum.Enum): class Phase(enum.Enum):
COMPILER = 'compiler' COMPILER = 'compiler'
LINKER = 'linker' LINKER = 'linker'
@ -309,14 +309,14 @@ class CudaCompiler(Compiler):
raise ValueError("-Xcompiler flag merging failed, unknown argument form!") raise ValueError("-Xcompiler flag merging failed, unknown argument form!")
return xflags return xflags
def _to_host_flags(self, flags: T.List[str], phase: _Phase = _Phase.COMPILER) -> T.List[str]: @classmethod
def to_host_flags_base(cls, flags: T.List[str], phase: Phase = Phase.COMPILER, default_include_dirs: T.Optional[T.List[str]] = None) -> T.List[str]:
""" """
Translate generic "GCC-speak" plus particular "NVCC-speak" flags to NVCC flags. Translate generic "GCC-speak" plus particular "NVCC-speak" flags to NVCC flags.
NVCC's "short" flags have broad similarities to the GCC standard, but have NVCC's "short" flags have broad similarities to the GCC standard, but have
gratuitous, irritating differences. gratuitous, irritating differences.
""" """
xflags = [] xflags = []
flagit = iter(flags) flagit = iter(flags)
@ -371,7 +371,7 @@ class CudaCompiler(Compiler):
# an exception for -D (where this would be value-changing) and -U (because # an exception for -D (where this would be value-changing) and -U (because
# it isn't possible to define a macro with a comma in the name). # it isn't possible to define a macro with a comma in the name).
if flag in self._FLAG_PASSTHRU_NOARGS: if flag in cls._FLAG_PASSTHRU_NOARGS:
xflags.append(flag) xflags.append(flag)
continue continue
@ -404,16 +404,16 @@ class CudaCompiler(Compiler):
else: # -Isomething else: # -Isomething
val = flag[2:] val = flag[2:]
flag = flag[:2] # -I flag = flag[:2] # -I
elif flag in self._FLAG_LONG2SHORT_WITHARGS or \ elif flag in cls._FLAG_LONG2SHORT_WITHARGS or \
flag in self._FLAG_SHORT2LONG_WITHARGS: flag in cls._FLAG_SHORT2LONG_WITHARGS:
# This is either -o or a multi-letter flag, and it is receiving its # This is either -o or a multi-letter flag, and it is receiving its
# value isolated. # value isolated.
try: try:
val = next(flagit) # -o something val = next(flagit) # -o something
except StopIteration: except StopIteration:
pass pass
elif flag.split('=', 1)[0] in self._FLAG_LONG2SHORT_WITHARGS or \ elif flag.split('=', 1)[0] in cls._FLAG_LONG2SHORT_WITHARGS or \
flag.split('=', 1)[0] in self._FLAG_SHORT2LONG_WITHARGS: flag.split('=', 1)[0] in cls._FLAG_SHORT2LONG_WITHARGS:
# This is either -o or a multi-letter flag, and it is receiving its # This is either -o or a multi-letter flag, and it is receiving its
# value after an = sign. # value after an = sign.
flag, val = flag.split('=', 1) # -o=something flag, val = flag.split('=', 1) # -o=something
@ -442,14 +442,14 @@ class CudaCompiler(Compiler):
xflags.append('-prec-div=true') xflags.append('-prec-div=true')
xflags.append('-Xcompiler='+flag) xflags.append('-Xcompiler='+flag)
else: else:
xflags.append('-Xcompiler='+self._shield_nvcc_list_arg(flag)) xflags.append('-Xcompiler='+cls._shield_nvcc_list_arg(flag))
# The above should securely handle GCC's -Wl, -Wa, -Wp, arguments. # The above should securely handle GCC's -Wl, -Wa, -Wp, arguments.
continue continue
assert val is not None # Should only trip if there is a missing argument. assert val is not None # Should only trip if there is a missing argument.
# Take care of the various NVCC-supported flags that need special handling. # Take care of the various NVCC-supported flags that need special handling.
flag = self._FLAG_LONG2SHORT_WITHARGS.get(flag, flag) flag = cls._FLAG_LONG2SHORT_WITHARGS.get(flag, flag)
if flag in {'-include', '-isystem', '-I', '-L', '-l'}: if flag in {'-include', '-isystem', '-I', '-L', '-l'}:
# These flags are known to GCC, but list-valued in NVCC. They potentially # These flags are known to GCC, but list-valued in NVCC. They potentially
@ -461,14 +461,14 @@ class CudaCompiler(Compiler):
# -U with comma arguments is impossible in GCC-speak (and thus unambiguous # -U with comma arguments is impossible in GCC-speak (and thus unambiguous
#in NVCC-speak, albeit unportable). #in NVCC-speak, albeit unportable).
if len(flag) == 2: if len(flag) == 2:
xflags.append(flag+self._shield_nvcc_list_arg(val)) xflags.append(flag+cls._shield_nvcc_list_arg(val))
elif flag == '-isystem' and val in self.host_compiler.get_default_include_dirs(): elif flag == '-isystem' and default_include_dirs is not None and val in default_include_dirs:
# like GnuLikeCompiler, we have to filter out include directories specified # like GnuLikeCompiler, we have to filter out include directories specified
# with -isystem that overlap with the host compiler's search path # with -isystem that overlap with the host compiler's search path
pass pass
else: else:
xflags.append(flag) xflags.append(flag)
xflags.append(self._shield_nvcc_list_arg(val)) xflags.append(cls._shield_nvcc_list_arg(val))
elif flag == '-O': elif flag == '-O':
# Handle optimization levels GCC knows about that NVCC does not. # Handle optimization levels GCC knows about that NVCC does not.
if val == 'fast': if val == 'fast':
@ -489,13 +489,16 @@ class CudaCompiler(Compiler):
xflags.append(flag) xflags.append(flag)
xflags.append(val) xflags.append(val)
return self._merge_flags(xflags) return cls._merge_flags(xflags)
def _to_host_flags(self, flags: T.List[str], phase: Phase = Phase.COMPILER) -> T.List[str]:
return self.to_host_flags_base(flags, phase, self.host_compiler.get_default_include_dirs())
def needs_static_linker(self) -> bool: def needs_static_linker(self) -> bool:
return False return False
def thread_link_flags(self, environment: 'Environment') -> T.List[str]: def thread_link_flags(self, environment: 'Environment') -> T.List[str]:
return self._to_host_flags(self.host_compiler.thread_link_flags(environment), _Phase.LINKER) return self._to_host_flags(self.host_compiler.thread_link_flags(environment), Phase.LINKER)
def sanity_check(self, work_dir: str, env: 'Environment') -> None: def sanity_check(self, work_dir: str, env: 'Environment') -> None:
mlog.debug('Sanity testing ' + self.get_display_language() + ' compiler:', ' '.join(self.exelist)) mlog.debug('Sanity testing ' + self.get_display_language() + ' compiler:', ' '.join(self.exelist))
@ -684,13 +687,13 @@ class CudaCompiler(Compiler):
def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]: def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
args = self.get_ccbin_args(options) args = self.get_ccbin_args(options)
return args + self._to_host_flags(self.host_compiler.get_option_link_args(self._to_host_compiler_options(options)), _Phase.LINKER) return args + self._to_host_flags(self.host_compiler.get_option_link_args(self._to_host_compiler_options(options)), Phase.LINKER)
def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str, def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str,
suffix: str, soversion: str, suffix: str, soversion: str,
darwin_versions: T.Tuple[str, str]) -> T.List[str]: darwin_versions: T.Tuple[str, str]) -> T.List[str]:
return self._to_host_flags(self.host_compiler.get_soname_args( return self._to_host_flags(self.host_compiler.get_soname_args(
env, prefix, shlib_name, suffix, soversion, darwin_versions), _Phase.LINKER) env, prefix, shlib_name, suffix, soversion, darwin_versions), Phase.LINKER)
def get_compile_only_args(self) -> T.List[str]: def get_compile_only_args(self) -> T.List[str]:
return ['-c'] return ['-c']
@ -729,20 +732,20 @@ class CudaCompiler(Compiler):
return self._to_host_flags(self.host_compiler.get_compile_debugfile_args(rel_obj, pch)) return self._to_host_flags(self.host_compiler.get_compile_debugfile_args(rel_obj, pch))
def get_link_debugfile_args(self, targetfile: str) -> T.List[str]: def get_link_debugfile_args(self, targetfile: str) -> T.List[str]:
return self._to_host_flags(self.host_compiler.get_link_debugfile_args(targetfile), _Phase.LINKER) return self._to_host_flags(self.host_compiler.get_link_debugfile_args(targetfile), Phase.LINKER)
def get_depfile_suffix(self) -> str: def get_depfile_suffix(self) -> str:
return 'd' return 'd'
def get_optimization_link_args(self, optimization_level: str) -> T.List[str]: def get_optimization_link_args(self, optimization_level: str) -> T.List[str]:
return self._to_host_flags(self.host_compiler.get_optimization_link_args(optimization_level), _Phase.LINKER) return self._to_host_flags(self.host_compiler.get_optimization_link_args(optimization_level), Phase.LINKER)
def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str, def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
rpath_paths: T.Tuple[str, ...], build_rpath: str, rpath_paths: T.Tuple[str, ...], build_rpath: str,
install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]: install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]:
(rpath_args, rpath_dirs_to_remove) = self.host_compiler.build_rpath_args( (rpath_args, rpath_dirs_to_remove) = self.host_compiler.build_rpath_args(
env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath) env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath)
return (self._to_host_flags(rpath_args, _Phase.LINKER), rpath_dirs_to_remove) return (self._to_host_flags(rpath_args, Phase.LINKER), rpath_dirs_to_remove)
def linker_to_compiler_args(self, args: T.List[str]) -> T.List[str]: def linker_to_compiler_args(self, args: T.List[str]) -> T.List[str]:
return args return args
@ -767,7 +770,7 @@ class CudaCompiler(Compiler):
return [] return []
def get_std_exe_link_args(self) -> T.List[str]: def get_std_exe_link_args(self) -> T.List[str]:
return self._to_host_flags(self.host_compiler.get_std_exe_link_args(), _Phase.LINKER) return self._to_host_flags(self.host_compiler.get_std_exe_link_args(), Phase.LINKER)
def find_library(self, libname: str, env: 'Environment', extra_dirs: 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]]: libtype: LibType = LibType.PREFER_SHARED, lib_prefix_warning: bool = True) -> T.Optional[T.List[str]]:
@ -783,16 +786,16 @@ class CudaCompiler(Compiler):
host_crt_compile_args = self.host_compiler.get_crt_compile_args(crt_val, buildtype) host_crt_compile_args = self.host_compiler.get_crt_compile_args(crt_val, buildtype)
if any(arg in {'/MDd', '/MD', '/MTd'} for arg in host_crt_compile_args): if any(arg in {'/MDd', '/MD', '/MTd'} for arg in host_crt_compile_args):
host_link_arg_overrides += ['/NODEFAULTLIB:LIBCMT.lib'] host_link_arg_overrides += ['/NODEFAULTLIB:LIBCMT.lib']
return self._to_host_flags(host_link_arg_overrides + self.host_compiler.get_crt_link_args(crt_val, buildtype), _Phase.LINKER) return self._to_host_flags(host_link_arg_overrides + self.host_compiler.get_crt_link_args(crt_val, buildtype), Phase.LINKER)
def get_target_link_args(self, target: 'BuildTarget') -> T.List[str]: def get_target_link_args(self, target: 'BuildTarget') -> T.List[str]:
return self._to_host_flags(super().get_target_link_args(target), _Phase.LINKER) return self._to_host_flags(super().get_target_link_args(target), Phase.LINKER)
def get_dependency_compile_args(self, dep: 'Dependency') -> T.List[str]: def get_dependency_compile_args(self, dep: 'Dependency') -> T.List[str]:
return self._to_host_flags(super().get_dependency_compile_args(dep)) return self._to_host_flags(super().get_dependency_compile_args(dep))
def get_dependency_link_args(self, dep: 'Dependency') -> T.List[str]: def get_dependency_link_args(self, dep: 'Dependency') -> T.List[str]:
return self._to_host_flags(super().get_dependency_link_args(dep), _Phase.LINKER) return self._to_host_flags(super().get_dependency_link_args(dep), Phase.LINKER)
def get_ccbin_args(self, ccoptions: 'KeyedOptionDictType') -> T.List[str]: def get_ccbin_args(self, ccoptions: 'KeyedOptionDictType') -> T.List[str]:
key = self.form_compileropt_key('ccbindir') key = self.form_compileropt_key('ccbindir')

@ -616,7 +616,8 @@ def detect_cpp_compiler(env: 'Environment', for_machine: MachineChoice) -> Compi
return _detect_c_or_cpp_compiler(env, 'cpp', for_machine) return _detect_c_or_cpp_compiler(env, 'cpp', for_machine)
def detect_cuda_compiler(env: 'Environment', for_machine: MachineChoice) -> Compiler: def detect_cuda_compiler(env: 'Environment', for_machine: MachineChoice) -> Compiler:
from .cuda import CudaCompiler from .cuda import CudaCompiler, Phase
from ..options import OptionKey
from ..linkers.linkers import CudaLinker from ..linkers.linkers import CudaLinker
popen_exceptions = {} popen_exceptions = {}
is_cross = env.is_cross_build(for_machine) is_cross = env.is_cross_build(for_machine)
@ -648,6 +649,12 @@ def detect_cuda_compiler(env: 'Environment', for_machine: MachineChoice) -> Comp
cpp_compiler = detect_cpp_compiler(env, for_machine) cpp_compiler = detect_cpp_compiler(env, for_machine)
cls = CudaCompiler cls = CudaCompiler
env.coredata.add_lang_args(cls.language, cls, for_machine, env) env.coredata.add_lang_args(cls.language, cls, for_machine, env)
key = OptionKey('cuda_link_args', machine=for_machine)
if key in env.options:
# To fix LDFLAGS issue
val = env.options[key]
assert isinstance(val, list)
env.coredata.set_options({key: cls.to_host_flags_base(val, Phase.LINKER)})
linker = CudaLinker(compiler, for_machine, CudaCompiler.LINKER_PREFIX, [], version=CudaLinker.parse_version()) linker = CudaLinker(compiler, for_machine, CudaCompiler.LINKER_PREFIX, [], version=CudaLinker.parse_version())
return cls(ccache, compiler, version, for_machine, is_cross, host_compiler=cpp_compiler, info=info, linker=linker) return cls(ccache, compiler, version, for_machine, is_cross, host_compiler=cpp_compiler, info=info, linker=linker)
raise EnvironmentException(f'Could not find suitable CUDA compiler: "{"; ".join([" ".join(c) for c in compilers])}"') raise EnvironmentException(f'Could not find suitable CUDA compiler: "{"; ".join([" ".join(c) for c in compilers])}"')

Loading…
Cancel
Save