rust: Always link dll and exe with the correct vscrt

This fixes missing flags in the link_whole case and link failure for
static libraries.
pull/12400/head
Xavier Claessens 1 year ago committed by Xavier Claessens
parent 361f7484d2
commit e2a87afa52
  1. 50
      mesonbuild/backend/ninjabackend.py
  2. 16
      mesonbuild/compilers/rust.py

@ -1951,40 +1951,16 @@ class NinjaBackend(backends.Backend):
linkdirs = mesonlib.OrderedSet()
external_deps = target.external_deps.copy()
# Have we already injected msvc-crt args?
#
# If we don't have A C, C++, or Fortran compiler that is
# VisualStudioLike treat this as if we've already injected them
#
# We handle this here rather than in the rust compiler because in
# general we don't want to link rust targets to a non-default crt.
# However, because of the way that MSCRTs work you can only link to one
# per target, so if A links to the debug one, and B links to the normal
# one you can't link A and B. Rust is hardcoded to the default one,
# so if we compile C/C++ code and link against a non-default MSCRT then
# linking will fail. We can work around this by injecting MSCRT link
# arguments early in the rustc command line
# Rustc always use non-debug Windows runtime. Inject the one selected
# by Meson options instead.
# https://github.com/rust-lang/rust/issues/39016
crt_args_injected = not any(x is not None and x.get_argument_syntax() == 'msvc' for x in
(self.environment.coredata.compilers[target.for_machine].get(l)
for l in ['c', 'cpp', 'fortran']))
crt_link_args: T.List[str] = []
try:
buildtype = target.get_option(OptionKey('buildtype'))
crt = target.get_option(OptionKey('b_vscrt'))
crt = rustc.get_crt_val(crt, buildtype)
if crt == 'mdd':
crt_link_args = ['-l', 'static=msvcrtd']
elif crt == 'md':
# this is the default, no need to inject anything
crt_args_injected = True
elif crt == 'mtd':
crt_link_args = ['-l', 'static=libcmtd']
elif crt == 'mt':
crt_link_args = ['-l', 'static=libcmt']
except KeyError:
crt_args_injected = True
if not isinstance(target, build.StaticLibrary):
try:
buildtype = target.get_option(OptionKey('buildtype'))
crt = target.get_option(OptionKey('b_vscrt'))
args += rustc.get_crt_link_args(crt, buildtype)
except KeyError:
pass
# TODO: we likely need to use verbatim to handle name_prefix and name_suffix
for d in target.link_targets:
@ -2001,10 +1977,6 @@ class NinjaBackend(backends.Backend):
project_deps.append(RustDep(d_name, self.rust_crates[d.name].order))
continue
if not crt_args_injected and not {'c', 'cpp', 'fortran'}.isdisjoint(d.compilers):
args += crt_link_args
crt_args_injected = True
if isinstance(d, build.StaticLibrary):
# Rustc doesn't follow Meson's convention that static libraries
# are called .a, and import libraries are .lib, so we have to
@ -2045,10 +2017,6 @@ class NinjaBackend(backends.Backend):
args += ['--extern', '{}={}'.format(d_name, os.path.join(d.subdir, d.filename))]
project_deps.append(RustDep(d_name, self.rust_crates[d.name].order))
else:
if not crt_args_injected and not {'c', 'cpp', 'fortran'}.isdisjoint(d.compilers):
crt_args_injected = True
crt_args_injected = True
if rustc.linker.id in {'link', 'lld-link'}:
if verbatim:
# If we can use the verbatim modifier, then everything is great

@ -55,6 +55,17 @@ class RustCompiler(Compiler):
'3': ['-W', 'warnings'],
}
# Those are static libraries, but we use dylib= here as workaround to avoid
# rust --tests to use /WHOLEARCHIVE.
# https://github.com/rust-lang/rust/issues/116910
MSVCRT_ARGS: T.Mapping[str, T.List[str]] = {
'none': [],
'md': [], # this is the default, no need to inject anything
'mdd': ['-l', 'dylib=msvcrtd'],
'mt': ['-l', 'dylib=libcmt'],
'mtd': ['-l', 'dylib=libcmtd'],
}
def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice,
is_cross: bool, info: 'MachineInfo',
exe_wrapper: T.Optional['ExternalProgram'] = None,
@ -177,6 +188,11 @@ class RustCompiler(Compiler):
# Rust handles this for us, we don't need to do anything
return []
def get_crt_link_args(self, crt_val: str, buildtype: str) -> T.List[str]:
if self.linker.id not in {'link', 'lld-link'}:
return []
return self.MSVCRT_ARGS[self.get_crt_val(crt_val, buildtype)]
def get_colorout_args(self, colortype: str) -> T.List[str]:
if colortype in {'always', 'never', 'auto'}:
return [f'--color={colortype}']

Loading…
Cancel
Save