diff options
| author | Paolo Bonzini <pbonzini@redhat.com> | 2025-10-24 10:24:45 +0200 |
|---|---|---|
| committer | Paolo Bonzini <pbonzini@redhat.com> | 2025-12-22 11:59:07 +0100 |
| commit | 7a1aa179087a274d6f6b13c2c666043ac9760ea5 (patch) | |
| tree | b9bf5eed53e6a3ff41dee74b6429ef2916dae37a | |
| parent | 9752def1c96eb32dc37c32398a0fe8802392fbc9 (diff) | |
| download | meson-7a1aa179087a274d6f6b13c2c666043ac9760ea5.tar.gz | |
modules: rust: implement workspace.package()
Note that, as shown in the testcase, package() works in the subproject
as well. This means that in the future the Cargo code generator can be
changed to reduce the amount of generated code and instead rely on the
package object.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
| -rw-r--r-- | docs/markdown/Rust-module.md | 29 | ||||
| -rw-r--r-- | mesonbuild/cargo/interpreter.py | 15 | ||||
| -rw-r--r-- | mesonbuild/modules/rust.py | 29 | ||||
| -rw-r--r-- | test cases/rust/31 rust.workspace package/meson.build | 15 | ||||
| -rw-r--r-- | test cases/rust/31 rust.workspace package/subprojects/answer-2.1/meson.build | 4 | ||||
| -rw-r--r-- | test cases/rust/32 rust.workspace workspace/meson.build | 15 | ||||
| -rw-r--r-- | test cases/rust/32 rust.workspace workspace/subprojects/answer-2.1/meson.build | 4 |
7 files changed, 100 insertions, 11 deletions
diff --git a/docs/markdown/Rust-module.md b/docs/markdown/Rust-module.md index fbe65f1b6..ba500e7ee 100644 --- a/docs/markdown/Rust-module.md +++ b/docs/markdown/Rust-module.md @@ -241,6 +241,19 @@ packages = ws.packages() Returns a list of package names in the workspace. +### workspace.package() + +```meson +pkg = ws.package([package_name]) +``` + +Returns a package object for the given package member. If empty, returns +the object for the root package. + +Arguments: +- `package_name`: (str, optional) Name of the package; not needed for the + root package of a workspace + ### workspace.subproject() ```meson @@ -258,15 +271,15 @@ Positional arguments: The package object returned by `workspace.subproject()` provides methods for working with individual packages in a Cargo workspace. -### subproject.name() +### package.name(), subproject.name() ```meson name = pkg.name() ``` -Returns the name of the subproject. +Returns the name of a package or subproject. -### subproject.version() +### package.version(), subproject.version() ```meson version = pkg.version() @@ -274,7 +287,7 @@ version = pkg.version() Returns the normalized version number of the subproject. -### subproject.api() +### package.api(), subproject.api() ```meson api = pkg.api() @@ -283,21 +296,21 @@ api = pkg.api() Returns the API version of the subproject, that is the version up to the first nonzero element. -### subproject.features() +### package.features(), subproject.features() ```meson features = pkg.features() ``` -Returns selected features for a specific subproject. +Returns selected features for a specific package or subproject. -### subproject.all_features() +### package.all_features(), subproject.all_features() ```meson all_features = pkg.all_features() ``` -Returns all defined features for a specific subproject. +Returns all defined features for a specific package or subproject. ### subproject.dependency() diff --git a/mesonbuild/cargo/interpreter.py b/mesonbuild/cargo/interpreter.py index 30639f526..dc5cdef2a 100644 --- a/mesonbuild/cargo/interpreter.py +++ b/mesonbuild/cargo/interpreter.py @@ -298,6 +298,21 @@ class Interpreter: for feature in self.features: self._enable_feature(pkg, feature) + def load_package(self, ws: WorkspaceState, package_name: T.Optional[str]) -> PackageState: + if package_name is None: + if not ws.workspace.root_package: + raise MesonException('no root package in workspace') + path = '.' + else: + try: + path = ws.packages_to_member[package_name] + except KeyError: + raise MesonException(f'workspace member "{package_name}" not found') + + if is_parent_path(self.subprojects_dir, path): + raise MesonException('argument to package() cannot be a subproject') + return ws.packages[path] + def interpret(self, subdir: str, project_root: T.Optional[str] = None) -> mparser.CodeBlockNode: filename = os.path.join(self.environment.source_dir, subdir, 'Cargo.toml') build = builder.Builder(filename) diff --git a/mesonbuild/modules/rust.py b/mesonbuild/modules/rust.py index 29d1b1fbb..186774413 100644 --- a/mesonbuild/modules/rust.py +++ b/mesonbuild/modules/rust.py @@ -101,6 +101,7 @@ class RustWorkspace(ModuleObject): self.ws = ws self.methods.update({ 'packages': self.packages_method, + 'package': self.package_method, 'subproject': self.subproject_method, }) @@ -111,6 +112,12 @@ class RustWorkspace(ModuleObject): package_names = [pkg.manifest.package.name for pkg in self.ws.packages.values()] return sorted(package_names) + @typed_pos_args('workspace.package', optargs=[str]) + def package_method(self, state: 'ModuleState', args: T.List, kwargs: TYPE_kwargs) -> RustPackage: + """Returns a package object.""" + package_name = args[0] if args else None + return RustPackage(self, self.interpreter.cargo.load_package(self.ws, package_name)) + def _do_subproject(self, pkg: cargo.PackageState) -> None: kw: _kwargs.DoSubproject = { 'required': True, @@ -138,8 +145,8 @@ class RustWorkspace(ModuleObject): return RustSubproject(self, pkg) -class RustSubproject(ModuleObject): - """Represents a Rust package within a workspace.""" +class RustCrate(ModuleObject): + """Abstract base class for Rust crate representations.""" def __init__(self, rust_ws: RustWorkspace, package: cargo.PackageState) -> None: super().__init__() @@ -148,7 +155,6 @@ class RustSubproject(ModuleObject): self.methods.update({ 'all_features': self.all_features_method, 'api': self.api_method, - 'dependency': self.dependency_method, 'features': self.features_method, 'name': self.name_method, 'version': self.version_method, @@ -184,6 +190,23 @@ class RustSubproject(ModuleObject): """Returns chosen features for specific package.""" return sorted(list(self.package.cfg.features)) + +class RustPackage(RustCrate): + """Represents a Rust package within a workspace.""" + + def __init__(self, rust_ws: RustWorkspace, package: cargo.PackageState) -> None: + super().__init__(rust_ws, package) + + +class RustSubproject(RustCrate): + """Represents a Cargo subproject.""" + + def __init__(self, rust_ws: RustWorkspace, package: cargo.PackageState) -> None: + super().__init__(rust_ws, package) + self.methods.update({ + 'dependency': self.dependency_method, + }) + @noPosargs @typed_kwargs('package.dependency', KwargInfo('rust_abi', (str, NoneType), default=None, validator=in_set_validator({'rust', 'c', 'proc-macro'}))) diff --git a/test cases/rust/31 rust.workspace package/meson.build b/test cases/rust/31 rust.workspace package/meson.build index d6e9aa42d..ec37a33d7 100644 --- a/test cases/rust/31 rust.workspace package/meson.build +++ b/test cases/rust/31 rust.workspace package/meson.build @@ -6,6 +6,13 @@ cargo_ws = rust.workspace() # Test workspace.packages() method assert(cargo_ws.packages() == ['answer', 'hello', 'package_test']) +main_pkg = cargo_ws.package() +assert(main_pkg.name() == 'package_test') +assert(main_pkg.version() == '0.1.0') +assert(main_pkg.api() == '0.1') +assert(main_pkg.all_features() == ['answer', 'default', 'feature1', 'feature2']) +assert(main_pkg.features() == ['default', 'feature1']) + hello_rs = cargo_ws.subproject('hello') assert(hello_rs.name() == 'hello') assert(hello_rs.version() == '1.0.0') @@ -25,6 +32,14 @@ e = executable('package-test', 'src/main.rs', ) test('package-test', e) +# failure test cases for package() +testcase expect_error('argument to package() cannot be a subproject') + cargo_ws.package('hello') +endtestcase +testcase expect_error('workspace member "nonexistent" not found') + cargo_ws.package('nonexistent') +endtestcase + # failure test cases for dependency() testcase expect_error('package.dependency.*must be one of c, proc-macro, rust.*', how: 're') hello_rs.dependency(rust_abi: 'something else') diff --git a/test cases/rust/31 rust.workspace package/subprojects/answer-2.1/meson.build b/test cases/rust/31 rust.workspace package/subprojects/answer-2.1/meson.build index e8d10117f..ece234f27 100644 --- a/test cases/rust/31 rust.workspace package/subprojects/answer-2.1/meson.build +++ b/test cases/rust/31 rust.workspace package/subprojects/answer-2.1/meson.build @@ -4,6 +4,10 @@ rust = import('rust') cargo_ws = rust.workspace() assert(cargo_ws.packages() == ['answer']) +answer_pkg = cargo_ws.package() +assert(answer_pkg.all_features() == ['default', 'large']) +assert(answer_pkg.features() == ['default', 'large']) + l = static_library('answer', 'src/lib.rs', rust_args: ['--cfg', 'feature="large"']) dep = declare_dependency(link_with: l) meson.override_dependency('answer-2-rs', dep) diff --git a/test cases/rust/32 rust.workspace workspace/meson.build b/test cases/rust/32 rust.workspace workspace/meson.build index 2626d3d50..185759413 100644 --- a/test cases/rust/32 rust.workspace workspace/meson.build +++ b/test cases/rust/32 rust.workspace workspace/meson.build @@ -6,6 +6,13 @@ cargo_ws = rust.workspace() # Test workspace.packages() method assert(cargo_ws.packages() == ['answer', 'hello', 'workspace_test']) +main_pkg = cargo_ws.package() +assert(main_pkg.name() == 'workspace_test') +assert(main_pkg.version() == '0.1.0') +assert(main_pkg.api() == '0.1') +assert(main_pkg.all_features() == ['answer', 'default', 'feature1', 'feature2']) +assert(main_pkg.features() == ['default', 'feature1']) + hello_rs = cargo_ws.subproject('hello') assert(hello_rs.name() == 'hello') assert(hello_rs.version() == '1.0.0') @@ -25,6 +32,14 @@ e = executable('workspace-test', 'src/main.rs', ) test('workspace-test', e) +# failure test cases for package() +testcase expect_error('argument to package() cannot be a subproject') + cargo_ws.package('hello') +endtestcase +testcase expect_error('workspace member "nonexistent" not found') + cargo_ws.package('nonexistent') +endtestcase + # failure test cases for dependency() testcase expect_error('package.dependency.*must be one of c, proc-macro, rust.*', how: 're') hello_rs.dependency(rust_abi: 'something else') diff --git a/test cases/rust/32 rust.workspace workspace/subprojects/answer-2.1/meson.build b/test cases/rust/32 rust.workspace workspace/subprojects/answer-2.1/meson.build index e8d10117f..ece234f27 100644 --- a/test cases/rust/32 rust.workspace workspace/subprojects/answer-2.1/meson.build +++ b/test cases/rust/32 rust.workspace workspace/subprojects/answer-2.1/meson.build @@ -4,6 +4,10 @@ rust = import('rust') cargo_ws = rust.workspace() assert(cargo_ws.packages() == ['answer']) +answer_pkg = cargo_ws.package() +assert(answer_pkg.all_features() == ['default', 'large']) +assert(answer_pkg.features() == ['default', 'large']) + l = static_library('answer', 'src/lib.rs', rust_args: ['--cfg', 'feature="large"']) dep = declare_dependency(link_with: l) meson.override_dependency('answer-2-rs', dep) |
