Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
a90592a
cargo: add --check-cfg cfg(test) unconditionally
bonzini Nov 28, 2025
6096481
cargo: include the implicit feature for dependencies in the manifest
bonzini Nov 28, 2025
7438e4e
cargo: allow overriding Meson's Cargo interpreter
bonzini Oct 26, 2025
cb61d06
cargo: show nice exception if Cargo.toml missing
bonzini Nov 18, 2025
adc2b0c
rust: add rust.workspace() skeleton implementation
bonzini Oct 17, 2025
9b5e71a
cargo: add configurable features to Interpreter
bonzini Oct 17, 2025
7c86833
modules: rust: implement workspace.subproject() and package.dependency()
bonzini Oct 26, 2025
01f8789
docs: add release notes for rust.workspace()
bonzini Oct 22, 2025
e8c4eb7
ast: printer: give a precedence to all kinds of functions
bonzini Oct 24, 2025
3596367
cargo: use cargo.subproject().dependency()
bonzini Oct 28, 2025
a17100f
modules: rust: implement workspace.packages()
bonzini Oct 1, 2025
653574a
modules: rust: implement more package accessors
bonzini Oct 22, 2025
8f7e196
modules: rust: implement workspace.package()
bonzini Oct 24, 2025
e04e56c
test: rust.workspace: add another member to the workspace
bonzini Oct 24, 2025
cdf1042
modules: rust: add workspace methods returning arguments for build ta…
bonzini Oct 24, 2025
92b63b9
dependencies: make arguments to InternalDependency.__init__ optional
bonzini Oct 26, 2025
97e8a2b
rust: add to_system_dependency
bonzini Oct 26, 2025
904e9e3
cargo: use rust.to_system_dependency
bonzini Oct 26, 2025
f89b799
cargo: use rust.workspace() to build the arguments
bonzini Oct 24, 2025
83348fa
modules: allow passing an array for dependency versions
bonzini Oct 27, 2025
65c6685
modules: rust: add dependencies() method to package object
bonzini Oct 28, 2025
9239a7e
modules: rust: invoke subprojects automatically from dependencies()
bonzini Oct 28, 2025
686c50c
cargo: use dependencies() method to get dependencies
bonzini Oct 27, 2025
f410831
modules: rust: add package.library/package.proc_macro methods
bonzini Oct 28, 2025
6a4a24b
cargo: populate bin table from src/bin/
bonzini Oct 28, 2025
b91d68e
modules: rust: add package.executable
bonzini Oct 29, 2025
2df2a48
modules: rust: add package.shared_module method
bonzini Nov 12, 2025
6444de9
docs: update info on Cargo workspace object
bonzini Nov 18, 2025
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
290 changes: 290 additions & 0 deletions docs/markdown/Rust-module.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ authors:
- name: Dylan Baker
email: [email protected]
years: [2020, 2021, 2022, 2024]
- name: Paolo Bonzini
email: [email protected]
years: [2025]
...

# Rust module
Expand Down Expand Up @@ -168,3 +171,290 @@ Only a subset of [[shared_library]] keyword arguments are allowed:
- link_depends
- link_with
- override_options

### to_system_dependency()

```meson
rustmod.to_system_dependency(dep[, name])
```

Create and return an internal dependency that wraps `dep` and
defines `cfg(system_deps_have_NAME)`. This is compatible with
how the `system-deps` crate reports the availability of a system
dependency to Rust code.

If omitted, the name defaults to the name of the dependency.

### workspace()

Basic usage:

```
cargo = rustmod.workspace()
```

With custom features:

```
feature_list = get_feature('f1') ? ['feature1'] : []
feature_list += get_feature('f2') ? ['feature2'] : []
cargo = rust.workspace(features: feature_list)
```

*Since 1.11.0*

Create and return a `workspace` object for managing the project's Cargo
workspace.

Keyword arguments:
- `default_features`: (`bool`, optional) Whether to enable default features.
- `features`: (`list[str]`, optional) List of additional features to enable globally.

A project that wishes to use Cargo subprojects should have `Cargo.lock` and `Cargo.toml`
files in the root source directory, and should call this function before using
Cargo subprojects.

The first invocation of `workspace()` establishes the *Cargo interpreter*
that resolves dependencies and features for both the toplevel project (the one
containing `Cargo.lock`) and all subprojects that are invoked with the `cargo` method,

You can optionally customize the feature set, by providing `default_features`
and `features` when the Cargo interpreter is established. If any of these
arguments is not specified, `default_features` is taken as `true` and
`features` as the empty list.

Once established, the Cargo interpreter's configuration is locked. Later calls to
`workspace()` must either omit all arguments (accepting the existing configuration)
or provide the same set of features as the first call. Mismatched arguments will cause
a build error.

The recommendation is to not specify any keyword arguments in a subproject, so
that they simply inherit the parent's configuration. Be careful about the
difference between specifying arguments and not doing so:

```
# always works regardless of parent configuration
cargo = rustmod.workspace()

# fails if parent configured different features
cargo = rustmod.workspace(default_features: true)
cargo = rustmod.workspace(features: [])
```

The first form says "use whatever features are configured," while the latter forms
say "require this specific configuration," which may conflict with the parent project.

## Workspace object

### workspace.packages()

```meson
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

Example usage:
```meson
rust = import('rust')
cargo = rust.workspace()
pkg = cargo.package()
pkg.executable(install: true)
```

### workspace.subproject()

```meson
package = ws.subproject(package_name, api)
```

Returns a `package` object for managing a specific package within the workspace.

Positional arguments:
- `package_name`: (`str`) The name of the package to retrieve
- `api`: (`str`, optional) The version constraints for the package in Cargo format

## Package object

The package object returned by `workspace.subproject()` provides methods
for working with individual packages in a Cargo workspace.

### package.name(), subproject.name()

```meson
name = pkg.name()
```

Returns the name of a package or subproject.

### package.version(), subproject.version()

```meson
version = pkg.version()
```

Returns the normalized version number of the subproject.

### package.api(), subproject.api()

```meson
api = pkg.api()
```

Returns the API version of the subproject, that is the version up to the first
nonzero element.

### package.features(), subproject.features()

```meson
features = pkg.features()
```

Returns selected features for a specific package or subproject.

### package.all_features(), subproject.all_features()

```meson
all_features = pkg.all_features()
```

Returns all defined features for a specific package or subproject.

### Packages only

Package objects are able to extract information from `Cargo.toml` files,
and provide methods to query how Cargo would build this package. They
also contain convenience wrappers for non-Rust-specific functions
(`executable`, `library`, `meson.override_dependency`, etc.), that
automatically add dependencies and compiler arguments from `Cargo.toml`
information.

#### package.rust_args()

```meson
args = pkg.rustc_args()
```

Returns rustc arguments for this package.

#### package.env()

```meson
env_vars = pkg.env()
```

Returns environment variables for this package.

#### package.rust_dependency_map()

```meson
dep_map = pkg.rust_dependency_map()
```

Returns rust dependency mapping for this package.

#### package.dependencies()

```meson
deps = pkg.dependencies(...)
```

Returns a list of dependency objects for all the dependencies required by this
Rust package, including both Rust crate dependencies and system dependencies.
The returned dependencies can be used directly in build target declarations.

Keyword arguments:
- `dependencies`: (`bool`, default: true) Whether to include regular Rust crate dependencies
- `dev_dependencies`: (`bool`, default: false) Whether to include development dependencies (not yet implemented)
- `system_dependencies`: (`bool`, default: true) Whether to include system dependencies

#### package.library()

```meson
lib = pkg.library(...)
```

Builds library targets for a workspace package. The method requires that
the package's `Cargo.toml` file contains the `[lib]` section or that it
is discovered from the contents of the file system. Static vs. shared library is
decided based on the crate types in `Cargo.toml`

Positional arguments:
- `target_name`: (`str`, optional) Name of the binary target to build.
- `sources`: (`StructuredSources`, optional) Source files for the executable. If omitted,
uses the path specified in the `[lib]` section of `Cargo.toml`.

Accepts all keyword arguments from [[shared_library]] and [[static_library]].
`rust_abi` must match the crate types and is mandatory if more than one
ABI is exposed by the crate.

#### package.shared_module()

```meson
lib = pkg.shared_module(...)
```

Builds the `cdylib` for a workspace package as a shared module.

Accepts all keyword arguments from [[shared_module]].

#### package.proc_macro()

```meson
lib = pkg.proc_macro(...)
```

Builds a proc-macro crate for a workspace package.

Accepts all keyword arguments from [[shared_library]].

#### package.executable()

```meson
exe = pkg.executable([target_name], [sources], ...)
```

Builds an executable target for a workspace package. The method requires that the
package has at least one `[[bin]]` section defined in its `Cargo.toml` file,
or one binary discovered from the contents of the file system.

Positional arguments:
- `target_name`: (`str`, optional) Name of the binary target to build. If the package
has multiple `[[bin]]` sections in `Cargo.toml`, this argument is required and must
match one of the binary names. If omitted and there's only one binary, that binary
will be built automatically.
- `sources`: (`StructuredSources`, optional) Source files for the executable. If omitted,
uses the path specified in the corresponding `[[bin]]` section of `Cargo.toml`.

Accepts all keyword arguments from [[executable]].

### Subprojects only

#### subproject.dependency()

```meson
dep = subproject.dependency(...)
```

Returns a dependency object for the subproject that can be used with other Meson targets.

*Note*: right now, this method is implemented on top of the normal Meson function
[[dependency]]; this is subject to change in future releases. It is recommended
to always retrieve a Cargo subproject's dependency object via this method.

Keyword arguments:
- `rust_abi`: (`str`, optional) The ABI to use for the dependency. Valid values are
`'rust'`, `'c'`, or `'proc-macro'`. The package must support the specified ABI.
53 changes: 53 additions & 0 deletions docs/markdown/Rust.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,56 @@ target name. First, dashes, spaces and dots are replaced with underscores. Sec
*since 1.10.0* anything after the first `+` is dropped. This allows creating multiple
targets for the same crate name, for example when the same crate is built multiple
times with different features, or for both the build and the host machine.

## Cargo interaction

*Since 1.10.0*

In most cases, a Rust program will use Cargo to download crates. Meson is able
to build Rust library crates based on a `Cargo.toml` file; each external crate
corresponds to a subproject. Rust module's ` that do not need a `build.rs` file
need no intervention, whereas if a `build.rs` file is present it needs to be
converted manually to Meson code.

To enable automatic configuration of Cargo dependencies, your project must
have `Cargo.toml` and `Cargo.lock` files in the root source directory;
this enables proper feature resolution across crates. You can then
create a workspace object using the Rust module, and retrieve specific
packages from the workspace:

```meson
rust = import('rust')
cargo = rust.workspace()
anyhow_dep = ws.subproject('anyhow').dependency()
```

The workspace object also enables configuration of Cargo features, for example
from Meson options:

```meson
cargo = rust.workspace(
features: ['feature1', 'feature2'])
```

Finally, the workspace object is able to build targets specified in `[lib]`
or `[[bins]]` sections, extracting compiler arguments for dependencies and
diagnostics from the Cargo.toml file. The simplest case is that of building
a simple binary crate:

```meson
cargo.package().executable(install: true)
```

Or for a workspace:

```meson
cargo.package('myproject-lib').library(install: false)
cargo.package().executable(install: true)
```

Sources are automatically discovered, but can be specified as a
[[@structured_src]] if they are partly generated.

It is still possible to use keyword arguments to link non-Rust build targets,
or even to use the usual Meson functions such as [[static_library]] or
[[executable]].
5 changes: 1 addition & 4 deletions docs/markdown/Wrap-dependency-system-manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -368,10 +368,7 @@ Since *1.5.0* Cargo wraps can also be provided with `Cargo.lock` file at the roo
of (sub)project source tree. Meson will automatically load that file and convert
it into a series of wraps definitions.

Since *1.10.0* Workspace Cargo.toml are supported. For the time being it is
recommended to regroup all Cargo dependencies inside a single workspace invoked
from the main Meson project. When invoking multiple different Cargo subprojects
from Meson, feature resolution of common dependencies might be wrong.
Since *1.10.0* Workspace Cargo.toml are supported.

## Using wrapped projects

Expand Down
14 changes: 14 additions & 0 deletions docs/markdown/snippets/cargo-workspace-object.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
## Cargo workspace object

Meson now is able to parse the toplevel `Cargo.toml` file of the
project when the `workspace()` method of the Rust module is called.
This guarantees that features are resolved according to what is
in the `Cargo.toml` file, and in fact enables configuration of
features for the build.

The returned object allows retrieving features and dependencies
for Cargo subprojects, and contains method to build targets
declared in `Cargo.toml` files.

While Cargo subprojects remain experimental, the Meson project will
try to keep the workspace object reasonably backwards-compatible.
2 changes: 1 addition & 1 deletion mesonbuild/ast/printer.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def precedence_level(node: mparser.BaseNode) -> int:
return 6
elif isinstance(node, (mparser.NotNode, mparser.UMinusNode)):
return 7
elif isinstance(node, mparser.FunctionNode):
elif isinstance(node, (mparser.FunctionNode, mparser.IndexNode, mparser.MethodNode)):
return 8
elif isinstance(node, (mparser.ArrayNode, mparser.DictNode)):
return 9
Expand Down
Loading
Loading