Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 28 additions & 7 deletions mesonbuild/compilers/detect.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,10 @@ def _handle_exceptions(
if exceptions:
errmsg += '\nThe following exception(s) were encountered:'
for c, e in exceptions.items():
errmsg += f'\nRunning `{c}` gave "{e}"'
if isinstance(e, MesonException):
errmsg += f'\nUsing `{c}` failed: {e}'
else:
errmsg += f'\nRunning `{c}` gave "{e}"'
raise EnvironmentException(errmsg)


Expand Down Expand Up @@ -1056,9 +1059,6 @@ def detect_rust_compiler(env: 'Environment', for_machine: MachineChoice) -> Rust
from ..linkers import linkers
popen_exceptions: T.Dict[str, Exception] = {}
compilers, _ = _get_compilers(env, 'rust', for_machine)

cc = detect_c_compiler(env, for_machine)
is_link_exe = isinstance(cc.linker, linkers.VisualStudioLikeLinkerMixin)
override = env.lookup_binary_entry(for_machine, 'rust_ld')

for compiler in compilers:
Expand Down Expand Up @@ -1101,12 +1101,33 @@ def detect_rust_compiler(env: 'Environment', for_machine: MachineChoice) -> Rust
if 'rustc' in out:
# On Linux and mac rustc will invoke gcc (clang for mac
# presumably) and it can do this windows, for dynamic linking.
# this means the easiest way to C compiler for dynamic linking.
# figure out what linker to use is to just get the value of the
# C compiler and use that as the basis of the rust linker.
# this means the easiest way to figure out what linker to use
# is to just get the value of the C compiler and use that as
# the basis of the rust linker.
#
# However, there are two things we need to change, if CC is not
# the default use that, and second add the necessary arguments
# to rust to use -fuse-ld
#
# For MSVC targets, require an MSVC-compatible C compiler to get
# the corresponding linker
rust_target = rust.parse_target(compiler)
if rust_target and rust_target.endswith('-msvc'):
try:
cc = _detect_c_or_cpp_compiler(env, 'c', for_machine,
override_compiler=['clang-cl', 'cl'])
except EnvironmentException:
popen_exceptions[join_args(compiler)] = \
EnvironmentException('No MSVC-compatible C compiler found for MSVC Rust target')
continue
else:
try:
cc = detect_c_compiler(env, for_machine)
except EnvironmentException as e:
popen_exceptions[join_args(compiler)] = e
continue

is_link_exe = isinstance(cc.linker, linkers.VisualStudioLikeLinkerMixin)

if any(a.startswith('linker=') for a in compiler):
mlog.warning(
Expand Down
32 changes: 32 additions & 0 deletions mesonbuild/compilers/rust.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from __future__ import annotations

import argparse
import functools
import os.path
import textwrap
Expand All @@ -24,6 +25,11 @@
from ..dependencies import Dependency
from ..build import BuildTarget

from typing_extensions import Protocol

class TargetParse(Protocol):
target: T.Optional[str]


rust_optimization_args: T.Dict[str, T.List[str]] = {
'plain': [],
Expand All @@ -35,6 +41,32 @@
's': ['-C', 'opt-level=s'],
}


class _TargetParser:

"""Helper for bindgen to look for --target in various command line arguments.

Storing this as a helper class avoids the need to set up the ArgumentParser
multiple times, and simplifies it's use as well as the typing.
"""

def __init__(self) -> None:
parser = argparse.ArgumentParser(add_help=False, allow_abbrev=False)
parser.add_argument('--target', action='store', default=None)
self._parser = parser

def parse(self, args: T.List[str]) -> T.Optional[str]:
"""Parse arguments looking for --target

:param args: A list of arguments to search
:return: the argument to --target if it exists, otherwise None
"""
parsed = T.cast('TargetParse', self._parser.parse_known_args(args)[0])
return parsed.target


parse_target = _TargetParser().parse

def get_rustup_run_and_args(exelist: T.List[str]) -> T.Optional[T.Tuple[T.List[str], T.List[str]]]:
"""Given the command for a rustc executable, check if it is invoked via
"rustup run" and if so separate the "rustup [OPTIONS] run TOOLCHAIN"
Expand Down
38 changes: 4 additions & 34 deletions mesonbuild/modules/rust.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
# Copyright © 2020-2025 Intel Corporation

from __future__ import annotations
import argparse
import itertools
import os
import re
Expand All @@ -16,6 +15,7 @@
from ..build import (BothLibraries, BuildTarget, CustomTargetIndex, Executable, ExtractedObjects, GeneratedList,
CustomTarget, InvalidArguments, Jar, StructuredSources, SharedLibrary, StaticLibrary)
from ..compilers.compilers import are_asserts_disabled_for_subproject, lang_suffixes
from ..compilers.rust import parse_target
from ..interpreter.type_checking import (
DEPENDENCIES_KW, LINK_WITH_KW, LINK_WHOLE_KW, SHARED_LIB_KWS, TEST_KWS, TEST_KWS_NO_ARGS,
OUTPUT_KW, INCLUDE_DIRECTORIES, SOURCES_VARARGS, NoneType, in_set_validator
Expand All @@ -38,7 +38,7 @@
from ..programs import Program
from ..interpreter.type_checking import SourcesVarargsType

from typing_extensions import TypedDict, Literal, Protocol
from typing_extensions import TypedDict, Literal

ArgsType = T.TypeVar('ArgsType')

Expand All @@ -65,10 +65,6 @@ class FuncBindgen(TypedDict):
language: T.Optional[Literal['c', 'cpp']]
bindgen_version: T.List[str]

class TargetParse(Protocol):

target: T.Optional[str]


RUST_TEST_KWS: T.List[KwargInfo] = [
KwargInfo(
Expand All @@ -82,32 +78,6 @@ class TargetParse(Protocol):
]


class _TargetParser:

"""Helper for bindgen to look for --target in various command line arguments.

Storing this as a helper class avoids the need to set up the ArgumentParser
multiple times, and simplifies it's use as well as the typing.
"""

def __init__(self) -> None:
parser = argparse.ArgumentParser(add_help=False, allow_abbrev=False)
parser.add_argument('--target', action='store', default=None)
self._parser = parser

def parse(self, args: T.List[str]) -> T.Optional[str]:
"""Parse arguments looking for --target

:param args: A list of arguments to search
:return: the argument to --target if it exists, otherwise None
"""
parsed = T.cast('TargetParse', self._parser.parse_known_args(args)[0])
return parsed.target


_parse_target = _TargetParser().parse


def no_spaces_validator(arg: T.Optional[T.Union[str, T.List]]) -> T.Optional[str]:
if any(bool(re.search(r'\s', x)) for x in arg):
return 'must not contain spaces due to limitations of rustdoc'
Expand Down Expand Up @@ -370,10 +340,10 @@ def bindgen(self, state: ModuleState, args: T.List, kwargs: FuncBindgen) -> Modu
clang_args = state.environment.properties.host.get_bindgen_clang_args().copy()

# Look for --target in the rust command itself if there isn't one passed in clang_args
target_arg = _parse_target(clang_args)
target_arg = parse_target(clang_args)
if not target_arg:
rust_args = state._interpreter.compilers.host['rust'].get_exe_args()
target_arg = _parse_target(rust_args)
target_arg = parse_target(rust_args)
if target_arg:
clang_args.append(f'--target={target_arg}')

Expand Down
Loading