Skip to content

Latest commit

 

History

History
156 lines (138 loc) · 4.42 KB

File metadata and controls

156 lines (138 loc) · 4.42 KB
title Workspaces
slug workspaces

Rust Workspaces

  • Rust workspaces provide a convenient way to manage multiple related crates together as a single project or monorepo.
  • A Rust workspace uses a shared Cargo.lock file and a common target directory to efficiently build and manage shared dependencies, reducing build times.
  • Cargo commands such as cargo test, cargo build, cargo check, cargo fmt, cargo clippy, and cargo clean can be run once from the workspace root to apply to all workspace members.

Simple

Let's build a sample Rust workspace with two simple crates.

[!lab]

mkdir my_project && cd my_project
echo -e "[workspace]\nresolver = \"3\"" > ./Cargo.toml
cargo new app_bar && cargo new app_buzz
cargo add uuid -F v7 -p app_bar && cargo add uuid -F v7 -p app_buzz

echo 'fn main() {
\tprintln!("Bar ID: {}", uuid::Uuid::now_v7());
}' > app_bar/src/main.rs

echo 'fn main() {
\tprintln!("Buzz ID: {}", uuid::Uuid::now_v7());
}' > app_buzz/src/main.rs
my_project
├── app_bar
│   ├── Cargo.toml
│   └── src
│       └── main.rs
├── app_buzz
│   ├── Cargo.toml
│   └── src
│       └── main.rs
├── Cargo.lock
└── Cargo.toml

{{< tabs count=3 label="Select File" >}} {{< tab label="app_bar → main.rs" >}}

fn main() {
    println!("Bar ID: {}", uuid::Uuid::now_v7());
}

{{< /tab >}} {{< tab label="app_buzz → main.rs" >}}

fn main() {
    println!("Buzz ID: {}", uuid::Uuid::now_v7());
}

{{< /tab >}} {{< tab label="Cargo.toml" >}}

[workspace]
resolver = "3"
members = ["app_bar", "app_buzz"]

{{< /tab >}} {{< /tabs >}}

As you can see,

  • Cargo commands can automatically add workspace members to the Cargo.toml file in the workspace root(my_project).
  • Try running cargo build and observe how each dependency is compiled only once through the shared target directory in the workspace root.

[!assignment]

  • Examine the Cargo.toml files in the workspace root and in each crate, and identify the main tables(sections) they contain.
  • Examine the Cargo.lock file in the workspace root and identify how the app_buzz and app_bar crates record their dependencies.
  • Run cargo run -p app_bar and cargo run -p app_buzz commands from the workspace root.

Advanced

[!lab]

mkdir my_project2 && cd my_project2
echo -e "[workspace]\nresolver = \"3\"\nmembers = [\"crates/*\"]" > ./Cargo.toml
cargo new crates/bar && cargo new crates/buzz
cargo new crates/common --lib
my_project
├── crates
│   ├── bar
│   │   ├── Cargo.toml
│   │   └── src
│   │       └── main.rs
│   ├── buzz
│   │   ├── Cargo.toml
│   │   └── src
│   │       └── main.rs
│   └── common
│       ├── Cargo.toml
│       └── src
│           └── lib.rs
├── Cargo.toml
└── Cargo.lock
  • To use the common crate from crates/bar and crates/buzz,
    • We have to add common crate as a dependency in both crates/bar/Cargo.toml and crates/buzz/Cargo.toml.
      [dependencies]
      common = { path = "../common" }
    • Then, we can use the common crate like any other dependency in crates/bar and crates/buzz.
      fn main() {
          let x = common::add(1, 1);
          println!("{x}");
      }

{{< tabs count=3 label="Select File" >}} {{< tab label="bar → Cargo.toml" >}}

[package]
name = "bar"
version = "0.1.0"
edition = "2024"

[dependencies]
common = { path = "../common" }

{{< /tab >}} {{< tab label="buzz → Cargo.toml" >}}

[package]
name = "buzz"
version = "0.1.0"
edition = "2024"

[dependencies]
common = { path = "../common" }

{{< /tab >}} {{< tab label="my_project2 → Cargo.toml" >}}

[workspace]
resolver = "3"
members = ["crates/*"]

{{< /tab >}} {{< /tabs >}}

👨‍🏫 Before going to the next...