summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDylan Baker <dylan@pnwbakers.com>2025-11-04 11:15:36 -0800
committerDylan Baker <dylan@pnwbakers.com>2025-11-05 10:02:16 -0800
commit9f9481224aa30104c89adec729272398d6a9ba86 (patch)
tree90dfdc6f3de0d4f44df57e815b3717b308dd5799
parent96481b170854b6d65dc140a3308b8faf73f13aa9 (diff)
downloadmeson-9f9481224aa30104c89adec729272398d6a9ba86.tar.gz
interpreter: move rust_api/rust_crate_type interaction to the interpreter
These are two ways to implement the same thing, and at the DSL level the `rust_abi` provides needed flexability, but at the lower level where a target is a thing, the `rust_crate_type` is still proving to be more useful. So, keep the `rust_abi` in the Interpreter and don't let it leak into the build layer.
-rw-r--r--mesonbuild/build.py50
-rw-r--r--mesonbuild/interpreter/interpreter.py49
-rw-r--r--test cases/rust/4 polyglot/meson.build2
3 files changed, 57 insertions, 44 deletions
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index ddf258f8c..3b68bc23c 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -48,13 +48,13 @@ if T.TYPE_CHECKING:
from .linkers.linkers import StaticLinker
from .mesonlib import ExecutableSerialisation, FileMode, FileOrString
from .mparser import BaseNode
- from .interpreter.kwargs import RustAbi
GeneratedTypes: TypeAlias = T.Union['CustomTarget', 'CustomTargetIndex', 'GeneratedList']
LibTypes: TypeAlias = T.Union['SharedLibrary', 'StaticLibrary', 'CustomTarget', 'CustomTargetIndex']
BuildTargetTypes: TypeAlias = T.Union['BuildTarget', 'CustomTarget', 'CustomTargetIndex']
ObjectTypes: TypeAlias = T.Union[str, 'File', 'ExtractedObjects', 'GeneratedTypes']
AnyTargetType: TypeAlias = T.Union['Target', 'CustomTargetIndex']
+ RustCrateType: TypeAlias = Literal['bin', 'lib', 'rlib', 'dylib', 'cdylib', 'staticlib', 'proc-macro']
class DFeatures(TypedDict):
@@ -99,8 +99,7 @@ if T.TYPE_CHECKING:
resources: T.List[str]
swift_interoperability_mode: Literal['c', 'cpp']
swift_module_name: str
- rust_abi: Literal['c', 'rust']
- rust_crate_type: Literal['bin', 'lib', 'rlib', 'dylib', 'cdylib', 'staticlib', 'proc-macro']
+ rust_crate_type: RustCrateType
rust_dependency_map: T.Dict[str, str]
vala_gir: T.Optional[str]
vala_header: T.Optional[str]
@@ -119,7 +118,6 @@ if T.TYPE_CHECKING:
class SharedModuleKeywordArguments(BuildTargetKeywordArguments, total=False):
vs_module_defs: T.Union[str, File, CustomTarget, CustomTargetIndex]
- rust_abi: T.Optional[RustAbi]
class SharedLibraryKeywordArguments(SharedModuleKeywordArguments, total=False):
@@ -131,7 +129,6 @@ if T.TYPE_CHECKING:
pic: bool
prelink: bool
- rust_abi: T.Optional[RustAbi]
DEFAULT_STATIC_LIBRARY_NAMES: T.Mapping[str, T.Tuple[str, str]] = {
'unix': ('lib', 'a'),
@@ -765,6 +762,7 @@ class BuildTarget(Target):
known_kwargs = known_build_target_kwargs
install_dir: T.List[T.Union[str, Literal[False]]]
+ rust_crate_type: RustCrateType
# This set contains all the languages a linker can link natively
# without extra flags. For instance, nvcc (cuda) can link C++
@@ -2193,6 +2191,7 @@ class Executable(BuildTarget):
compilers: T.Dict[str, 'Compiler'],
kwargs: ExecutableKeywordArguments):
self.export_dynamic = kwargs.get('export_dynamic', False)
+ self.rust_crate_type = kwargs.get('rust_crate_type', 'bin')
super().__init__(name, subdir, subproject, for_machine, sources, structured_sources, objects,
environment, compilers, kwargs)
self.win_subsystem = kwargs.get('win_subsystem') or 'console'
@@ -2282,13 +2281,6 @@ class Executable(BuildTarget):
name += '_' + self.suffix
self.debug_filename = name + '.pdb'
- def process_kwargs(self, kwargs: ExecutableKeywordArguments) -> None:
- super().process_kwargs(kwargs)
-
- self.rust_crate_type = kwargs.get('rust_crate_type') or 'bin'
- if self.rust_crate_type != 'bin':
- raise InvalidArguments('Invalid rust_crate_type: must be "bin" for executables.')
-
def get_default_install_dir(self) -> T.Union[T.Tuple[str, str], T.Tuple[None, None]]:
return self.environment.get_bindir(), '{bindir}'
@@ -2352,6 +2344,7 @@ class StaticLibrary(BuildTarget):
compilers: T.Dict[str, 'Compiler'],
kwargs: StaticLibraryKeywordArguments):
self.prelink = kwargs.get('prelink', False)
+ self.rust_crate_type = kwargs.get('rust_crate_type', 'rlib')
super().__init__(name, subdir, subproject, for_machine, sources, structured_sources, objects,
environment, compilers, kwargs)
self.pic = self._extract_pic_pie(kwargs, 'pic', 'b_staticpic')
@@ -2438,23 +2431,6 @@ class StaticLibrary(BuildTarget):
def type_suffix(self):
return "@rlib" if self.uses_rust_abi() else "@sta"
- def process_kwargs(self, kwargs: StaticLibraryKeywordArguments) -> None:
- super().process_kwargs(kwargs)
-
- rust_abi = kwargs.get('rust_abi')
- rust_crate_type = kwargs.get('rust_crate_type')
- if rust_crate_type:
- if rust_abi:
- raise InvalidArguments('rust_abi and rust_crate_type are mutually exclusive.')
- if rust_crate_type == 'lib':
- self.rust_crate_type = 'rlib'
- elif rust_crate_type in {'rlib', 'staticlib'}:
- self.rust_crate_type = rust_crate_type
- else:
- raise InvalidArguments(f'Crate type {rust_crate_type!r} invalid for static libraries; must be "rlib" or "staticlib"')
- else:
- self.rust_crate_type = 'staticlib' if rust_abi == 'c' else 'rlib'
-
def is_linkable_target(self) -> bool:
return True
@@ -2504,6 +2480,7 @@ class SharedLibrary(BuildTarget):
self.debug_filename = None
# Use by the pkgconfig module
self.shared_library_only = False
+ self.rust_crate_type = kwargs.get('rust_crate_type', 'dylib')
super().__init__(name, subdir, subproject, for_machine, sources, structured_sources, objects,
environment, compilers, kwargs)
@@ -2685,20 +2662,6 @@ class SharedLibrary(BuildTarget):
# Visual Studio module-definitions file
self.process_vs_module_defs_kw(kwargs)
- rust_abi = kwargs.get('rust_abi')
- rust_crate_type = kwargs.get('rust_crate_type')
- if rust_crate_type:
- if rust_abi:
- raise InvalidArguments('rust_abi and rust_crate_type are mutually exclusive.')
- if rust_crate_type == 'lib':
- self.rust_crate_type = 'dylib'
- elif rust_crate_type in {'dylib', 'cdylib', 'proc-macro'}:
- self.rust_crate_type = rust_crate_type
- else:
- raise InvalidArguments(f'Crate type {rust_crate_type!r} invalid for shared libraries; must be "dylib", "cdylib" or "proc-macro"')
- else:
- self.rust_crate_type = 'cdylib' if rust_abi == 'c' else 'dylib'
-
def get_import_filename(self) -> T.Optional[str]:
"""
The name of the import library that will be outputted by the compiler
@@ -3226,6 +3189,7 @@ class Jar(BuildTarget):
known_kwargs = known_jar_kwargs
typename = 'jar'
+ rust_crate_type = '' # type: ignore[assignment]
def __init__(self, name: str, subdir: str, subproject: str, for_machine: MachineChoice,
sources: T.List[SourceOutputs], structured_sources: T.Optional['StructuredSources'],
diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py
index 89647adee..1c109bc2b 100644
--- a/mesonbuild/interpreter/interpreter.py
+++ b/mesonbuild/interpreter/interpreter.py
@@ -3357,6 +3357,40 @@ class Interpreter(InterpreterBase, HoldableObject):
d.extend(deps)
kwargs['language_args'] = new_args
+ @staticmethod
+ def _handle_rust_abi(abi: T.Optional[Literal['c', 'rust']],
+ crate_type: T.Optional[build.RustCrateType],
+ default_rust_type: build.RustCrateType,
+ default_c_type: build.RustCrateType, typename: str,
+ extra_valid_types: T.Optional[T.Set[build.RustCrateType]] = None,
+ ) -> build.RustCrateType:
+ """Handle the interactions between the rust_abi and rust_crate_type keyword arguments.
+
+ :param abi: Is this using Rust ABI or C ABI
+ :param crate_type: Is there an explicit crate type set
+ :param default_rust_type: The default crate type to use for Rust ABI
+ :param default_c_type: the default crate type to use for C ABI
+ :param typename: The name of the type this argument is for
+ :param extra_valid_types: additional valid crate types, defaults to None
+ :raises InvalidArguments: If the crate_type argument is set, but not valid
+ :raises InvalidArguments: If both crate_type and abi are set
+ :return: The finalized crate type
+ """
+ if abi is not None:
+ if crate_type is not None:
+ raise InvalidArguments('rust_abi and rust_crate_type are mutually exclusive')
+ crate_type = default_rust_type if abi == 'rust' else default_c_type
+ elif crate_type is not None:
+ if crate_type == 'lib':
+ crate_type = default_rust_type
+ valid_types = {default_rust_type, default_c_type} | (extra_valid_types or set())
+ if crate_type not in valid_types:
+ choices = ", " .join(f'"{c}"' for c in sorted(valid_types))
+ raise InvalidArguments(f'Crate type for {typename} must be one of {choices}, but got "{crate_type}"')
+ else:
+ crate_type = default_rust_type
+ return crate_type
+
@T.overload
def build_target(self, node: mparser.BaseNode, args: T.Tuple[str, SourcesVarargsType],
kwargs: kwtypes.Executable, targetclass: T.Type[build.Executable]) -> build.Executable: ...
@@ -3415,15 +3449,30 @@ class Interpreter(InterpreterBase, HoldableObject):
self.check_sources_exist(os.path.join(self.source_root, self.subdir), sources)
self.__process_language_args(kwargs)
if targetclass is build.StaticLibrary:
+ kwargs = T.cast('kwtypes.StaticLibrary', kwargs)
for lang in compilers.all_languages - {'java'}:
deps, args = self.__convert_file_args(kwargs.get(f'{lang}_static_args', []))
kwargs['language_args'][lang].extend(args)
kwargs['depend_files'].extend(deps)
+ kwargs['rust_crate_type'] = self._handle_rust_abi(
+ kwargs['rust_abi'], kwargs['rust_crate_type'], 'rlib', 'staticlib', targetclass.typename)
+
elif targetclass is build.SharedLibrary:
+ kwargs = T.cast('kwtypes.SharedLibrary', kwargs)
for lang in compilers.all_languages - {'java'}:
deps, args = self.__convert_file_args(kwargs.get(f'{lang}_shared_args', []))
kwargs['language_args'][lang].extend(args)
kwargs['depend_files'].extend(deps)
+ kwargs['rust_crate_type'] = self._handle_rust_abi(
+ kwargs['rust_abi'], kwargs['rust_crate_type'], 'dylib', 'cdylib', targetclass.typename,
+ extra_valid_types={'proc-macro'})
+
+ elif targetclass is build.Executable:
+ kwargs = T.cast('kwtypes.Executable', kwargs)
+ if kwargs['rust_crate_type'] not in {None, 'bin'}:
+ raise InvalidArguments('Crate type for executable must be "bin"')
+ kwargs['rust_crate_type'] = 'bin'
+
if targetclass is not build.Jar:
self.check_for_jar_sources(sources, targetclass)
kwargs['d_import_dirs'] = self.extract_incdirs(kwargs, 'd_import_dirs')
diff --git a/test cases/rust/4 polyglot/meson.build b/test cases/rust/4 polyglot/meson.build
index 97b7bcdb7..29af73f28 100644
--- a/test cases/rust/4 polyglot/meson.build
+++ b/test cases/rust/4 polyglot/meson.build
@@ -18,7 +18,7 @@ foreach crate_type : ['lib', 'rlib', 'dylib', 'cdylib', 'staticlib', 'proc-macro
# Note: in the both_libraries() case it is possible that the static part
# is still being built because the shared part raised an error but we
# don't rollback correctly.
- testcase expect_error('(Crate type .* invalid for .*)|(.*must be one of.*not invalid)', how: 're')
+ testcase expect_error('(Crate type .* must be .*)|(.*must be one of.*not invalid)', how: 're')
build_target(name, src,
target_type: target_type,
rust_crate_type: crate_type,