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
  • Loading branch information
dcbaker committed Jun 23, 2023
1 parent 812e5a6 commit 4f38329
Showing 1 changed file with 38 additions and 1 deletion.
39 changes: 38 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,30 @@ 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?
# On non-windows targets treat this as if we've already injected them
# Also, if we don't have A C, C++, or Fortran compiler 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 = not (self.environment.machines[target.for_machine].is_windows() or comp is None)

buildtype = self.environment.coredata.options[OptionKey('buildtype')].value
try:
crt = self.environment.coredata.options[OptionKey('b_scrt')].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 +1982,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 +2029,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 4f38329

Please sign in to comment.