Skip to content

Commit

Permalink
rust: Always link dll and exe with the correct vscrt
Browse files Browse the repository at this point in the history
This fixes missing flags in the link_whole case and link failure for
static libraries.
  • Loading branch information
xclaesse committed Oct 19, 2023
1 parent 361f748 commit e2a87af
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 41 deletions.
50 changes: 9 additions & 41 deletions mesonbuild/backend/ninjabackend.py
Original file line number Diff line number Diff line change
Expand Up @@ -1951,40 +1951,16 @@ def generate_rust_target(self, target: build.BuildTarget) -> None:
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:
Expand All @@ -2001,10 +1977,6 @@ def generate_rust_target(self, target: build.BuildTarget) -> None:
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
Expand Down Expand Up @@ -2045,10 +2017,6 @@ def generate_rust_target(self, target: build.BuildTarget) -> None:
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
Expand Down
16 changes: 16 additions & 0 deletions mesonbuild/compilers/rust.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -177,6 +188,11 @@ def get_crt_compile_args(self, crt_val: str, buildtype: str) -> T.List[str]:
# 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}']
Expand Down

0 comments on commit e2a87af

Please sign in to comment.