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'
LINKER = 'linker'
@ -309,14 +309,14 @@ class CudaCompiler(Compiler):
raise ValueError("-Xcompiler flag merging failed, unknown argument form!")
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.
NVCC's "short" flags have broad similarities to the GCC standard, but have
gratuitous, irritating differences.
"""
xflags = []
flagit = iter(flags)
@ -371,7 +371,7 @@ class CudaCompiler(Compiler):
# 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).
if flag in self._FLAG_PASSTHRU_NOARGS:
if flag in cls._FLAG_PASSTHRU_NOARGS:
xflags.append(flag)
continue
@ -404,16 +404,16 @@ class CudaCompiler(Compiler):
else: # -Isomething
val = flag[2:]
flag = flag[:2] # -I
elif flag in self._FLAG_LONG2SHORT_WITHARGS or \
flag in self._FLAG_SHORT2LONG_WITHARGS:
elif flag in cls._FLAG_LONG2SHORT_WITHARGS or \
flag in cls._FLAG_SHORT2LONG_WITHARGS:
# This is either -o or a multi-letter flag, and it is receiving its
# value isolated.
try:
val = next(flagit) # -o something
except StopIteration:
pass
elif flag.split('=', 1)[0] in self._FLAG_LONG2SHORT_WITHARGS or \
flag.split('=', 1)[0] in self._FLAG_SHORT2LONG_WITHARGS:
elif flag.split('=', 1)[0] in cls._FLAG_LONG2SHORT_WITHARGS or \
flag.split('=', 1)[0] in cls._FLAG_SHORT2LONG_WITHARGS:
# This is either -o or a multi-letter flag, and it is receiving its
# value after an = sign.
flag, val = flag.split('=', 1) # -o=something
@ -442,14 +442,14 @@ class CudaCompiler(Compiler):
xflags.append('-prec-div=true')
xflags.append('-Xcompiler='+flag)
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.
continue
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.
flag = self._FLAG_LONG2SHORT_WITHARGS.get(flag, flag)
flag = cls._FLAG_LONG2SHORT_WITHARGS.get(flag, flag)
if flag in {'-include', '-isystem', '-I', '-L', '-l'}:
# 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
#in NVCC-speak, albeit unportable).
if len(flag) == 2:
xflags.append(flag+self._shield_nvcc_list_arg(val))
elif flag == '-isystem' and val in self.host_compiler.get_default_include_dirs():
xflags.append(flag+cls._shield_nvcc_list_arg(val))
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
# with -isystem that overlap with the host compiler's search path
pass
else:
xflags.append(flag)
xflags.append(self._shield_nvcc_list_arg(val))
xflags.append(cls._shield_nvcc_list_arg(val))
elif flag == '-O':
# Handle optimization levels GCC knows about that NVCC does not.
if val == 'fast':
@ -489,13 +489,16 @@ class CudaCompiler(Compiler):
xflags.append(flag)
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:
return False
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:
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]:
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,
suffix: str, soversion: str,
darwin_versions: T.Tuple[str, str]) -> T.List[str]:
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]:
return ['-c']
@ -729,20 +732,20 @@ class CudaCompiler(Compiler):
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]:
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:
return 'd'
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,
rpath_paths: T.Tuple[str, ...], build_rpath: str,
install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]:
(rpath_args, rpath_dirs_to_remove) = self.host_compiler.build_rpath_args(
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]:
return args
@ -767,7 +770,7 @@ class CudaCompiler(Compiler):
return []
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],
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)
if any(arg in {'/MDd', '/MD', '/MTd'} for arg in host_crt_compile_args):
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]:
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]:
return self._to_host_flags(super().get_dependency_compile_args(dep))
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]:
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)
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
popen_exceptions = {}
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)
cls = CudaCompiler
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())
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])}"')

Loading…
Cancel
Save