Skip to content

Commit 9ad8156

Browse files
committed
rust: Override the default MSVCRT when linking Rust and !rust together
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.
1 parent b34562d commit 9ad8156

File tree

1 file changed

+39
-1
lines changed

1 file changed

+39
-1
lines changed

mesonbuild/backend/ninjabackend.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
from .. import compilers
3838
from ..arglist import CompilerArgs
3939
from ..compilers import Compiler
40+
from ..compilers.mixins.visualstudio import VisualStudioLikeCompiler
4041
from ..linkers import ArLinker, RSPFileSyntax
4142
from ..mesonlib import (
4243
File, LibType, MachineChoice, MesonException, OrderedSet, PerMachine,
@@ -1944,6 +1945,31 @@ def generate_rust_target(self, target: build.BuildTarget) -> None:
19441945
args += output
19451946
linkdirs = mesonlib.OrderedSet()
19461947
external_deps = target.external_deps.copy()
1948+
1949+
# Have we already injected msvc-crt args?
1950+
#
1951+
# If we don't have A C, C++, or Fortran compiler that is
1952+
# VisualStudioLike treat this as if we've already injected them
1953+
#
1954+
# We handle this here rather than in the rust compiler because in
1955+
# general we don't want to link rust targets to a non-default crt.
1956+
# However, because of the way that MSCRTs work you can only link to one
1957+
# per target, so if A links to the debug one, and B links to the normal
1958+
# one you can't link A and B. Rust is hardcoded to the default one,
1959+
# so if we compile C/C++ code and link against a non-default MSCRT then
1960+
# linking will fail. We can work around this by injecting MSCRT link
1961+
# arguments early in the rustc command line
1962+
# https://github.com/rust-lang/rust/issues/39016#issuecomment-853964918
1963+
comp = mesonlib.first((self.environment.coredata.compilers[target.for_machine].get(l) for l in ['c', 'cpp', 'fortran']),
1964+
lambda x: x is not None and isinstance(x, VisualStudioLikeCompiler))
1965+
crt_args_injected = comp is None
1966+
1967+
buildtype = self.environment.coredata.options[OptionKey('buildtype')].value
1968+
try:
1969+
crt = self.environment.coredata.options[OptionKey('b_vscrt')].value
1970+
except KeyError:
1971+
crt = 'fake'
1972+
19471973
# TODO: we likely need to use verbatim to handle name_prefix and name_suffix
19481974
for d in target.link_targets:
19491975
linkdirs.add(d.subdir)
@@ -1957,7 +1983,14 @@ def generate_rust_target(self, target: build.BuildTarget) -> None:
19571983
d_name = self._get_rust_dependency_name(target, d)
19581984
args += ['--extern', '{}={}'.format(d_name, os.path.join(d.subdir, d.filename))]
19591985
project_deps.append(RustDep(d_name, self.rust_crates[d.name].order))
1960-
elif isinstance(d, build.StaticLibrary):
1986+
continue
1987+
1988+
if not crt_args_injected and not {'c', 'cpp', 'fortran'}.isdisjoint(d.compilers):
1989+
for larg in comp.get_crt_link_args(crt, buildtype):
1990+
args += ['-C', f'link-arg={larg}']
1991+
crt_args_injected = True
1992+
1993+
if isinstance(d, build.StaticLibrary):
19611994
# Rustc doesn't follow Meson's convention that static libraries
19621995
# are called .a, and import libraries are .lib, so we have to
19631996
# manually handle that.
@@ -1997,6 +2030,11 @@ def generate_rust_target(self, target: build.BuildTarget) -> None:
19972030
args += ['--extern', '{}={}'.format(d_name, os.path.join(d.subdir, d.filename))]
19982031
project_deps.append(RustDep(d_name, self.rust_crates[d.name].order))
19992032
else:
2033+
if not crt_args_injected and not {'c', 'cpp', 'fortran'}.isdisjoint(d.compilers):
2034+
for larg in comp.get_crt_link_args(crt, buildtype):
2035+
args += ['-C', f'link-arg={larg}']
2036+
crt_args_injected = True
2037+
20002038
if rustc.linker.id in {'link', 'lld-link'}:
20012039
if verbatim:
20022040
# If we can use the verbatim modifier, then everything is great

0 commit comments

Comments
 (0)