Skip to content

Commit

Permalink
rust: Override the default MSVCRT when linking Rust and !rust together
Browse files Browse the repository at this point in the history
Rust by default links with the default MSVCRT, (dynamic, release).
MSVCRT's cannot be mixed, so if Meson compiles a C or C++ library and
links it with the debug MSVCRT, then tries to link that with the Rust
library there will be failures. There is no built-in way to fix this for
rustc, so as a workaround we inject the correct arguments early in the
linker line (before any libs at least) to change the runtime. This seems
to work and is recommended as workaround in the upstream rust bug
report: rust-lang/rust#39016.

Given that this bug report has been opened since 2017, it seems unlikely
to be fixed anytime soon, and affects all (currently) released versions
of Rust.
  • Loading branch information
dcbaker committed Jun 23, 2023
1 parent b34562d commit 9ad8156
Showing 1 changed file with 39 additions and 1 deletion.
40 changes: 39 additions & 1 deletion mesonbuild/backend/ninjabackend.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
from .. import compilers
from ..arglist import CompilerArgs
from ..compilers import Compiler
from ..compilers.mixins.visualstudio import VisualStudioLikeCompiler
from ..linkers import ArLinker, RSPFileSyntax
from ..mesonlib import (
File, LibType, MachineChoice, MesonException, OrderedSet, PerMachine,
Expand Down Expand Up @@ -1944,6 +1945,31 @@ def generate_rust_target(self, target: build.BuildTarget) -> None:
args += output
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
# https://github.com/rust-lang/rust/issues/39016#issuecomment-853964918
comp = mesonlib.first((self.environment.coredata.compilers[target.for_machine].get(l) for l in ['c', 'cpp', 'fortran']),
lambda x: x is not None and isinstance(x, VisualStudioLikeCompiler))
crt_args_injected = comp is None

buildtype = self.environment.coredata.options[OptionKey('buildtype')].value
try:
crt = self.environment.coredata.options[OptionKey('b_vscrt')].value
except KeyError:
crt = 'fake'

# TODO: we likely need to use verbatim to handle name_prefix and name_suffix
for d in target.link_targets:
linkdirs.add(d.subdir)
Expand All @@ -1957,7 +1983,14 @@ def generate_rust_target(self, target: build.BuildTarget) -> None:
d_name = self._get_rust_dependency_name(target, d)
args += ['--extern', '{}={}'.format(d_name, os.path.join(d.subdir, d.filename))]
project_deps.append(RustDep(d_name, self.rust_crates[d.name].order))
elif isinstance(d, build.StaticLibrary):
continue

if not crt_args_injected and not {'c', 'cpp', 'fortran'}.isdisjoint(d.compilers):
for larg in comp.get_crt_link_args(crt, buildtype):
args += ['-C', f'link-arg={larg}']
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
# manually handle that.
Expand Down Expand Up @@ -1997,6 +2030,11 @@ 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):
for larg in comp.get_crt_link_args(crt, buildtype):
args += ['-C', f'link-arg={larg}']
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

0 comments on commit 9ad8156

Please sign in to comment.