Skip to content

Proposal: rust.workspace() Cargo integration #14639

@bonzini

Description

@bonzini

This is a proposal for more complete integration of Cargo.toml parsing in the Rust module. For simple projects (without complex build.rs scripts), building becomes straightforward:

cargo = import('rust').workspace()
cargo.library()  # For library crates
# or
cargo.executables()  # For binary crates

Any build.rs scripts are ignored. Subprojects with complex build scripts will need manual configuration, unless the script is unnecessary when building with Meson. Extremely common crates (anyhow, thiserror, libc, serde, proc_macro2, unicode_ident, syn, quote, etc.) could be distributed as wraps to minimize manual dependency management.

Module-level Method

rust.workspace(default_features: bool = true, features: list[str] |dict[bool|feature], dev_dependencies: bool | list[str] = true, build_dependencies: bool | list[str] = false)

Returns a new workspace object corresponding to the Cargo.toml file in the root of the source tree. Optionally disable default features and set a desired list of features instead.

Feature objects can be used to modify default features (enabled = force true, auto = true if part of the default features, disabled = force false).

Optionally add some or all dev_dependencies/build_dependencies. build_dependencies are built for the BUILD machine, you generally want some of them (e.g. phf_codegen) but not all of them (e.g. not cc).

#15158 implements methods marked with "✅"

Workspace Object

All methods accept a name parameter that can be omitted or '' to refer to the root package of the workspace (or the sole package if not a workspace).

Additional features compared to built-in functions

  • rust_args for --cfg, --check-cfg, and lint options from Cargo.toml and feature resolution are added automatically
  • [dependencies] sections are used to build a rust_dependency_map
  • If a dependency has not yet been built, library targets are attempted to build automatically.
  • An extra cfg: list[str] parameter is converted into --cfg options

Accessor Methods

workspace.packages()

Returns the chosen set of packages in the workspace.

workspace.package([name][, native: bool])

Returns a package object for the given package. Name is empty for the root package, not empty for workspace packages.

workspace.subproject(name[, api][, native: bool])

Returns a read-only package object for the given dependency. (Could possibly be used by the generated meson.build for Cargo subprojects?).

Package object for subprojects

package.features()

Returns the resolved set of features for the given package.

package.all_features()

Returns all features defined by the given package.

package.dependency([rust_abi: 'rust|c|proc-macro'])

Return the dep object for the given package.

Package object for toplevel Cargo.toml packages

package.rustc_args()

Returns compiler arguments from Cargo.toml lints and from feature resolution

package.env()

Returns environment variables that Cargo would set.

package.rust_dependency_map()

Return the dependency map built from the Cargo.toml [dependencies] section

rust_abi must be specified in the rare case where both Rust and C libraries are built

package.library(cfg: list[str] = [], rust_abi: 'rust'|'c', **kwargs) (rlib/dylib)

package.proc_macro(cfg: list[str] = [], **kwargs)

Build the library target for the specified package (or root package if name is empty) and ABI. Pass extra arguments to the underlying Meson library function.

Shared/static/both libraries is obtained from [lib] section. Fails if the given kind of library is not found in [lib].

Executable Building Methods

package.executables(list[str] = (all targets), cfg: list[str] = [], **kwargs)

Build binary targets for the specified package. If positional arguments are absent, builds all binaries. Extra arguments are passed to executable().

Returns a dictionary mapping target names to executable objects.

Test and Example Methods

package.tests(list[str] = (all targets), cfg: list[str] = [], **kwargs)

package.benchmarks(list[str] = (all targets), cfg: list[str] = [], **kwargs)

package.examples(list[str] = (all targets), cfg: list[str] = [], **kwargs)

Build test/benchmark/example targets for the specified package. If targets is absent, builds all targets of that type. Extra arguments are passed to executable().

Tests/benchmarks are automatically passed to rust.test()/rust.benchmark() and extra arguments can be passed to those functions as well - complete list of arguments TBD.

Returns a dictionary mapping target names to executable objects.

package.doctest(**kwargs)

Build doctests for the specified package. Extra arguments are passed to rust.doctest(). The doc suite is automatically added.

Usage Examples

Simple Library Crate

cargo = import('rust').workspace()
cargo.package().library()

CLI Application

cargo = import('rust').workspace()
cargo.package().executables()

Workspace with Multiple Packages

cargo = import('rust').workspace()
cargo.package('myproject-core').library(install: false)
cargo.package('myproject-cli').executables()

With Custom Configuration

cargo = import('rust').workspace(default_features: get_option('default'),
  features: {
    'f1': get_option('f1'),
    'f2': get_option('f2'),
  })
cargo.package().executables()

See also

Sub-issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    dependencies:cargoIssues related to using cargo subprojectsdesign discussionDiscussions about meson design and featuresmodule:rustSpecific to the Rust module

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions