diff options
| author | Dylan Baker <dylan@pnwbakers.com> | 2025-11-04 11:15:36 -0800 |
|---|---|---|
| committer | Dylan Baker <dylan@pnwbakers.com> | 2025-11-05 10:02:16 -0800 |
| commit | 9f9481224aa30104c89adec729272398d6a9ba86 (patch) | |
| tree | 90dfdc6f3de0d4f44df57e815b3717b308dd5799 | |
| parent | 96481b170854b6d65dc140a3308b8faf73f13aa9 (diff) | |
| download | meson-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.py | 50 | ||||
| -rw-r--r-- | mesonbuild/interpreter/interpreter.py | 49 | ||||
| -rw-r--r-- | test cases/rust/4 polyglot/meson.build | 2 |
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, |
