summaryrefslogtreecommitdiff
path: root/mesonbuild
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2025-10-28 18:16:05 +0100
committerPaolo Bonzini <pbonzini@redhat.com>2025-12-22 12:01:05 +0100
commit8cd91e1eb4c76e79eba589674af08229b1e02f90 (patch)
treed661153b32867d1eccc3ef07bd4b28b070f8a164 /mesonbuild
parent29bbbf65fa7432d3cfc741feb55c6a76c2460e08 (diff)
downloadmeson-8cd91e1eb4c76e79eba589674af08229b1e02f90.tar.gz
modules: rust: add package.library/package.proc_macro methods
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'mesonbuild')
-rw-r--r--mesonbuild/cargo/interpreter.py89
-rw-r--r--mesonbuild/modules/rust.py125
2 files changed, 161 insertions, 53 deletions
diff --git a/mesonbuild/cargo/interpreter.py b/mesonbuild/cargo/interpreter.py
index fcdc661a3..fcae28d27 100644
--- a/mesonbuild/cargo/interpreter.py
+++ b/mesonbuild/cargo/interpreter.py
@@ -47,15 +47,6 @@ def _dependency_name(package_name: str, api: str, suffix: str = '-rs') -> str:
return f'{basename}-{api}{suffix}'
-def _library_name(name: str, api: str, lib_type: Literal['rust', 'c', 'proc-macro'] = 'rust') -> str:
- # Add the API version to the library name to avoid conflicts when multiple
- # versions of the same crate are used. The Ninja backend removed everything
- # after the + to form the crate name.
- if lib_type == 'c':
- return name
- return f'{name}+{api.replace(".", "_")}'
-
-
def _extra_args_varname() -> str:
return 'extra_args'
@@ -87,7 +78,7 @@ class PackageConfiguration:
dep = manifest.dependencies[name]
dep_key = PackageKey(dep.package, dep.api)
dep_pkg = self.dep_packages[dep_key]
- dep_lib_name = _library_name(dep_pkg.manifest.lib.name, dep_pkg.manifest.package.api)
+ dep_lib_name = dep_pkg.library_name()
dep_crate_name = name if name != dep.package else dep_pkg.manifest.lib.name
dependency_map[dep_lib_name] = dep_crate_name
return dependency_map
@@ -109,6 +100,15 @@ class PackageState:
return None
return os.path.normpath(os.path.join(self.ws_subdir, self.ws_member))
+ def library_name(self, lib_type: RUST_ABI = 'rust') -> str:
+ # Add the API version to the library name to avoid conflicts when multiple
+ # versions of the same crate are used. The Ninja backend removed everything
+ # after the + to form the crate name.
+ name = fixup_meson_varname(self.manifest.package.name)
+ if lib_type == 'c':
+ return name
+ return f'{name}+{self.manifest.package.api.replace(".", "_")}'
+
def get_env_dict(self, environment: Environment, subdir: str) -> T.Dict[str, str]:
"""Get environment variables for this package."""
# Common variables for build.rs and crates
@@ -205,17 +205,33 @@ class PackageState:
def get_subproject_name(self) -> str:
return _dependency_name(self.manifest.package.name, self.manifest.package.api)
- def get_dependency_name(self, rust_abi: T.Optional[RUST_ABI]) -> str:
- """Get the dependency name for a package with the given ABI."""
+ def abi_resolve_default(self, rust_abi: T.Optional[RUST_ABI]) -> RUST_ABI:
supported_abis = self.supported_abis()
if rust_abi is None:
if len(supported_abis) > 1:
raise MesonException(f'Package {self.manifest.package.name} support more than one ABI')
- rust_abi = next(iter(supported_abis))
+ return next(iter(supported_abis))
else:
if rust_abi not in supported_abis:
raise MesonException(f'Package {self.manifest.package.name} does not support ABI {rust_abi}')
+ return rust_abi
+
+ def abi_has_shared(self, rust_abi: RUST_ABI) -> bool:
+ if rust_abi == 'proc-macro':
+ return True
+ return ('cdylib' if rust_abi == 'c' else 'dylib') in self.manifest.lib.crate_type
+
+ def abi_has_static(self, rust_abi: RUST_ABI) -> bool:
+ if rust_abi == 'proc-macro':
+ return False
+ crate_type = self.manifest.lib.crate_type
+ if rust_abi == 'c':
+ return 'staticlib' in crate_type
+ return 'lib' in crate_type or 'rlib' in crate_type
+ def get_dependency_name(self, rust_abi: T.Optional[RUST_ABI]) -> str:
+ """Get the dependency name for a package with the given ABI."""
+ rust_abi = self.abi_resolve_default(rust_abi)
package_name = self.manifest.package.name
api = self.manifest.package.api
@@ -354,17 +370,8 @@ class Interpreter:
crate_type = pkg.manifest.lib.crate_type
if 'dylib' in crate_type and 'cdylib' in crate_type:
raise MesonException('Cannot build both dylib and cdylib due to file name conflict')
- abis = pkg.supported_abis()
- if 'proc-macro' in abis:
- ast.extend(self._create_lib(pkg, build, subdir, 'proc-macro', shared=True))
- if 'rust' in abis:
- ast.extend(self._create_lib(pkg, build, subdir, 'rust',
- static=('lib' in crate_type or 'rlib' in crate_type),
- shared='dylib' in crate_type))
- if 'c' in abis:
- ast.extend(self._create_lib(pkg, build, subdir, 'c',
- static='staticlib' in crate_type,
- shared='cdylib' in crate_type))
+ for abi in pkg.supported_abis():
+ ast.extend(self._create_lib(pkg, build, subdir, abi))
return ast
@@ -796,46 +803,24 @@ class Interpreter:
]
def _create_lib(self, pkg: PackageState, build: builder.Builder, subdir: str,
- lib_type: RUST_ABI,
- static: bool = False, shared: bool = False) -> T.List[mparser.BaseNode]:
- pkg_dependencies = build.method('dependencies', build.identifier('pkg_obj'))
- extra_deps_ref = build.identifier(_extra_deps_varname())
- dependencies = build.plus(pkg_dependencies, extra_deps_ref)
-
- package_rust_args = build.method('rust_args', build.identifier('pkg_obj'))
- extra_args_ref = build.identifier(_extra_args_varname())
- rust_args = build.plus(package_rust_args, extra_args_ref)
-
- override_options: T.Dict[mparser.BaseNode, mparser.BaseNode] = {
- build.string('rust_std'): build.string(pkg.manifest.package.edition),
- }
-
+ lib_type: RUST_ABI) -> T.List[mparser.BaseNode]:
posargs: T.List[mparser.BaseNode] = [
- build.string(_library_name(pkg.manifest.lib.name, pkg.manifest.package.api, lib_type)),
- build.string(pkg.manifest.lib.path),
+ build.string(pkg.library_name(lib_type)),
]
kwargs: T.Dict[str, mparser.BaseNode] = {
- 'dependencies': dependencies,
- 'rust_dependency_map': build.method('rust_dependency_map', build.identifier('pkg_obj')),
- 'rust_args': rust_args,
- 'override_options': build.dict(override_options),
+ 'dependencies': build.identifier(_extra_deps_varname()),
+ 'rust_args': build.identifier(_extra_args_varname()),
}
depname_suffix = '' if lib_type == 'c' else '-rs'
depname = _dependency_name(pkg.manifest.package.name, pkg.manifest.package.api, depname_suffix)
- lib: mparser.BaseNode
if lib_type == 'proc-macro':
- lib = build.method('proc_macro', build.identifier('rust'), posargs, kwargs)
+ lib = build.method('proc_macro', build.identifier('pkg_obj'), posargs, kwargs)
else:
- if static and shared:
- target_type = 'both_libraries'
- else:
- target_type = 'shared_library' if shared else 'static_library'
-
kwargs['rust_abi'] = build.string(lib_type)
- lib = build.function(target_type, posargs, kwargs)
+ lib = build.method('library', build.identifier('pkg_obj'), posargs, kwargs)
# lib = xxx_library()
# dep = declare_dependency()
diff --git a/mesonbuild/modules/rust.py b/mesonbuild/modules/rust.py
index 974d50ae6..137d64099 100644
--- a/mesonbuild/modules/rust.py
+++ b/mesonbuild/modules/rust.py
@@ -19,7 +19,8 @@ from ..compilers.rust import RustSystemDependency
from ..dependencies import Dependency
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
+ OUTPUT_KW, INCLUDE_DIRECTORIES, SOURCES_VARARGS, NoneType, in_set_validator,
+ LIBRARY_KWS, _BASE_LANG_KW
)
from ..interpreterbase import ContainerTypeInfo, InterpreterException, KwargInfo, typed_kwargs, typed_pos_args, noKwargs, noPosargs, permittedKwargs
from ..interpreter.interpreterobjects import Doctest
@@ -75,6 +76,11 @@ if T.TYPE_CHECKING:
class FuncDependency(TypedDict):
rust_abi: T.Optional[RUST_ABI]
+ class RustPackageLibrary(_kwargs.Library):
+ dependencies: T.List[T.Union[Dependency, ExternalLibrary]]
+ link_with: T.List[LibTypes]
+ link_whole: T.List[LibTypes]
+
RUST_TEST_KWS: T.List[KwargInfo] = [
KwargInfo(
'rust_args',
@@ -234,6 +240,8 @@ class RustPackage(RustCrate):
super().__init__(rust_ws, package)
self.methods.update({
'dependencies': self.dependencies_method,
+ 'library': self.library_method,
+ 'proc_macro': self.proc_macro_method,
})
@noPosargs
@@ -271,6 +279,121 @@ class RustPackage(RustCrate):
return dependencies
+ @staticmethod
+ def validate_pos_args(name: str, args: T.Tuple[
+ T.Optional[T.Union[str, StructuredSources]],
+ T.Optional[StructuredSources]]) -> T.Tuple[T.Optional[str], T.Optional[StructuredSources]]:
+ if isinstance(args[0], str):
+ return args[0], args[1]
+ if args[1] is not None:
+ raise MesonException(f"{name} only accepts one StructuredSources parameter")
+ return None, args[0]
+
+ def merge_kw_args(self, state: ModuleState, kwargs: RustPackageLibrary) -> None:
+ deps = kwargs['dependencies']
+ kwargs['dependencies'] = self.dependencies_method(state, [], {})
+ kwargs['dependencies'].extend(deps)
+
+ depmap = kwargs['rust_dependency_map']
+ kwargs['rust_dependency_map'] = self.rust_dependency_map_method(state, [], {})
+ kwargs['rust_dependency_map'].update(depmap)
+
+ rust_args = kwargs['rust_args']
+ kwargs['rust_args'] = self.rust_args_method(state, [], {})
+ kwargs['rust_args'].extend(rust_args)
+
+ kwargs['override_options'].setdefault('rust_std', self.package.manifest.package.edition)
+
+ def _library_method(self, state: ModuleState, args: T.Tuple[
+ T.Optional[T.Union[str, StructuredSources]],
+ T.Optional[StructuredSources]], kwargs: RustPackageLibrary,
+ static: bool, shared: bool) -> T.Union[BothLibraries, SharedLibrary, StaticLibrary]:
+ tgt_args = self.validate_pos_args('package.library', args)
+ if not self.package.manifest.lib:
+ raise MesonException("no [lib] section in Cargo package")
+
+ sources: T.Union[StructuredSources, str]
+ tgt_name, sources = tgt_args
+ if not tgt_name:
+ rust_abi: RUST_ABI
+ if kwargs['rust_crate_type'] is not None:
+ rust_abi = 'rust' if kwargs['rust_crate_type'] in {'lib', 'rlib', 'dylib', 'proc-macro'} else 'c'
+ else:
+ rust_abi = kwargs['rust_abi']
+ tgt_name = self.package.library_name(rust_abi)
+ if not sources:
+ sources = self.package.manifest.lib.path
+
+ lib_args: T.Tuple[str, SourcesVarargsType] = (tgt_name, [sources])
+ self.merge_kw_args(state, kwargs)
+
+ if static and shared:
+ return state._interpreter.build_both_libraries(state.current_node, lib_args, kwargs)
+ elif shared:
+ return state._interpreter.build_target(state.current_node, lib_args,
+ T.cast('_kwargs.SharedLibrary', kwargs),
+ SharedLibrary)
+ else:
+ return state._interpreter.build_target(state.current_node, lib_args,
+ T.cast('_kwargs.StaticLibrary', kwargs),
+ StaticLibrary)
+
+ def _proc_macro_method(self, state: 'ModuleState', args: T.Tuple[
+ T.Optional[T.Union[str, StructuredSources]],
+ T.Optional[StructuredSources]], kwargs: RustPackageLibrary) -> SharedLibrary:
+ kwargs['native'] = MachineChoice.BUILD
+ kwargs['rust_abi'] = None
+ kwargs['rust_crate_type'] = 'proc-macro'
+ kwargs['rust_args'] = kwargs['rust_args'] + ['--extern', 'proc_macro']
+ result = self._library_method(state, args, kwargs, shared=True, static=False)
+ return T.cast('SharedLibrary', result)
+
+ @typed_pos_args('package.library', optargs=[(str, StructuredSources), StructuredSources])
+ @typed_kwargs(
+ 'package.library',
+ *LIBRARY_KWS,
+ DEPENDENCIES_KW,
+ LINK_WITH_KW,
+ LINK_WHOLE_KW,
+ _BASE_LANG_KW.evolve(name='rust_args'),
+ )
+ def library_method(self, state: ModuleState, args: T.Tuple[
+ T.Optional[T.Union[str, StructuredSources]],
+ T.Optional[StructuredSources]], kwargs: RustPackageLibrary) -> T.Union[BothLibraries, SharedLibrary, StaticLibrary]:
+ if not self.package.manifest.lib:
+ raise MesonException("no [lib] section in Cargo package")
+ if kwargs['rust_crate_type'] is not None:
+ static = kwargs['rust_crate_type'] in {'lib', 'rlib', 'staticlib'}
+ shared = kwargs['rust_crate_type'] in {'dylib', 'cdylib', 'proc-macro'}
+ else:
+ rust_abi = self.package.abi_resolve_default(kwargs['rust_abi'])
+ static = self.package.abi_has_static(rust_abi)
+ shared = self.package.abi_has_shared(rust_abi)
+ if rust_abi == 'proc-macro':
+ kwargs['rust_crate_type'] = 'proc-macro'
+ kwargs['rust_abi'] = None
+ else:
+ kwargs['rust_abi'] = rust_abi
+ return self._library_method(state, args, kwargs, static=static, shared=shared)
+
+ @typed_pos_args('package.proc_macro', optargs=[(str, StructuredSources), StructuredSources])
+ @typed_kwargs(
+ 'package.proc_macro',
+ *SHARED_LIB_KWS,
+ DEPENDENCIES_KW,
+ LINK_WITH_KW,
+ LINK_WHOLE_KW,
+ _BASE_LANG_KW.evolve(name='rust_args'),
+ )
+ def proc_macro_method(self, state: 'ModuleState', args: T.Tuple[
+ T.Optional[T.Union[str, StructuredSources]],
+ T.Optional[StructuredSources]], kwargs: RustPackageLibrary) -> SharedLibrary:
+ if not self.package.manifest.lib:
+ raise MesonException("no [lib] section in Cargo package")
+ if 'proc-macro' not in self.package.manifest.lib.crate_type:
+ raise MesonException("not a procedural macro crate")
+ return self._proc_macro_method(state, args, kwargs)
+
class RustSubproject(RustCrate):
"""Represents a Cargo subproject."""