Skip to content

Commit fd75b05

Browse files
committed
Workspaces
1 parent 13ce5dc commit fd75b05

1 file changed

Lines changed: 135 additions & 59 deletions

File tree

‎content/en/docs/d5.workspaces.md‎

Lines changed: 135 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -3,78 +3,154 @@ title: Workspaces
33
slug: workspaces
44
---
55

6-
> [!caution]
7-
> This needs a refresh!
8-
9-
When the code base is getting larger, you might need to work with **multiple crates on the same project**. Rust supports this via Workspaces. You can **analyze (`cargo check`), build, run tests or generate docs for all crates** at once by running `cargo` commands from the project root.
10-
11-
⭐️ When working on multiple crates same time, there is a higher possibility of having shared dependencies on crates. To prevent downloading and compiling the same dependency multiple times, Rust uses a **shared build directory** under the project root, while running `cargo build` from the project root.
12-
13-
Let's create a library crate with a simple hello world function and a binary crate which uses the library crate.
14-
15-
Assume we run,
16-
```bash
17-
mkdir greetings
18-
touch greetings/Cargo.toml
19-
cargo new greetings/lib --lib
20-
cargo new greetings/examples/hello
6+
## Rust Workspaces
7+
8+
- Rust workspaces provide a convenient way to manage multiple related crates together as a single project or monorepo.
9+
- A Rust workspace uses a shared `Cargo.lock` file and a common `target` directory to efficiently build and manage shared dependencies, reducing build times.
10+
- 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.
11+
12+
## Simple
13+
14+
Let's build a sample Rust workspace with two simple crates.
15+
16+
> [!lab]
17+
> ```shell
18+
> mkdir my_project && cd my_project
19+
> echo -e "[workspace]\nresolver = \"3\"" > ./Cargo.toml
20+
> cargo new app_bar && cargo new app_buzz
21+
> cargo add uuid -F v7 -p app_bar && cargo add uuid -F v7 -p app_buzz
22+
>
23+
> echo 'fn main() {
24+
> \tprintln!("Bar ID: {}", uuid::Uuid::now_v7());
25+
> }' > app_bar/src/main.rs
26+
>
27+
> echo 'fn main() {
28+
> \tprintln!("Buzz ID: {}", uuid::Uuid::now_v7());
29+
> }' > app_buzz/src/main.rs
30+
> ```
31+
32+
```shell {title="Folder Structure"}
33+
my_project
34+
├── app_bar
35+
│ ├── Cargo.toml
36+
│ └── src
37+
│ └── main.rs
38+
├── app_buzz
39+
│ ├── Cargo.toml
40+
│ └── src
41+
│ └── main.rs
42+
├── Cargo.lock
43+
└── Cargo.toml
2144
```
2245
23-
That generates,
24-
```bash
25-
greetings
26-
├── Cargo.toml
27-
├── examples
28-
│ └── hello
29-
│ ├── Cargo.toml
30-
│ └── src
31-
│ └── main.rs
32-
└── lib
33-
├── Cargo.toml
34-
└── src
35-
└── lib.rs
46+
{{< tabs count=3 label="Select File" >}}
47+
{{< tab label="app_bar → main.rs" >}}
48+
```rust {title="my_project/app_bar/src/main.rs"}
49+
fn main() {
50+
println!("Bar ID: {}", uuid::Uuid::now_v7());
51+
}
3652
```
37-
38-
We have to modify the following files,
39-
```rust
40-
// 01. greetings/Cargo.toml to mark as a workspace and to add members
53+
{{< /tab >}}
54+
{{< tab label="app_buzz → main.rs" >}}
55+
```rust {title="my_project/app_buzz/src/main.rs"}
56+
fn main() {
57+
println!("Buzz ID: {}", uuid::Uuid::now_v7());
58+
}
59+
```
60+
{{< /tab >}}
61+
{{< tab label="Cargo.toml" >}}
62+
```toml {title="my_project/Cargo.toml"}
4163
[workspace]
42-
members = [
43-
"lib",
44-
"examples/hello"
45-
]
64+
resolver = "3"
65+
members = ["app_bar", "app_buzz"]
66+
```
67+
{{< /tab >}}
68+
{{< /tabs >}}
69+
70+
As you can see,
71+
- Cargo commands can automatically add workspace members to the `Cargo.toml` file in the workspace root(`my_project`).
72+
- Try running `cargo build` and observe how each dependency is compiled only once through the shared `target` directory in the workspace root.
73+
74+
> [!assignment]
75+
> - Examine the `Cargo.toml` files in the workspace root and in each crate, and identify the main tables(sections) they contain.
76+
> - Examine the `Cargo.lock` file in the workspace root and identify how the `app_buzz` and `app_bar` crates record their dependencies.
77+
> - Run `cargo run -p app_bar` and `cargo run -p app_buzz` commands from the workspace root.
78+
79+
## Advanced
80+
81+
> [!lab]
82+
> ```
83+
> mkdir my_project2 && cd my_project2
84+
> echo -e "[workspace]\nresolver = \"3\"\nmembers = [\"crates/*\"]" > ./Cargo.toml
85+
> cargo new crates/bar && cargo new crates/buzz
86+
> cargo new crates/common --lib
87+
> ```
88+
89+
```shell {title="Folder Structure"}
90+
my_project
91+
├── crates
92+
│ ├── bar
93+
│ │ ├── Cargo.toml
94+
│ │ └── src
95+
│ │ └── main.rs
96+
│ ├── buzz
97+
│ │ ├── Cargo.toml
98+
│ │ └── src
99+
│ │ └── main.rs
100+
│ └── common
101+
│ ├── Cargo.toml
102+
│ └── src
103+
│ └── lib.rs
104+
├── Cargo.toml
105+
└── Cargo.lock
106+
```
46107
47-
// 02.1 greetings/lib/Cargo.toml to change the package name to greetings
108+
- To use the `common` crate from `crates/bar` and `crates/buzz`,
109+
- We have to add `common` crate as a dependency in both `crates/bar/Cargo.toml` and `crates/buzz/Cargo.toml`.
110+
```toml
111+
[dependencies]
112+
common = { path = "../common" }
113+
```
114+
- Then, we can use the `common` crate like any other dependency in `crates/bar` and `crates/buzz`.
115+
```rust
116+
fn main() {
117+
let x = common::add(1, 1);
118+
println!("{x}");
119+
}
120+
```
121+
122+
{{< tabs count=3 label="Select File" >}}
123+
{{< tab label="bar → Cargo.toml" >}}
124+
```toml {title="my_project2/crates/bar/Cargo.toml"}
48125
[package]
49-
name = "greetings"
126+
name = "bar"
50127
version = "0.1.0"
51-
authors = ["Dumindu Madunuwan"]
128+
edition = "2024"
52129

53130
[dependencies]
54-
55-
// 02.2 greetings/lib/src/lib.rs to add a simple hello world function
56-
pub fn hello() {
57-
println!("Hello, world!");
58-
}
59-
60-
// 03.1 greetings/examples/hello/Cargo.toml to add the `greetings` lib as a dependency
131+
common = { path = "../common" }
132+
```
133+
{{< /tab >}}
134+
{{< tab label="buzz → Cargo.toml" >}}
135+
```toml {title="my_project2/crates/buzz/Cargo.toml"}
61136
[package]
62-
name = "hello"
137+
name = "buzz"
63138
version = "0.1.0"
64-
authors = ["Dumindu Madunuwan"]
139+
edition = "2024"
65140

66141
[dependencies]
67-
greetings = { path = "../../lib" }
68-
69-
// 03.2 greetings/examples/hello/src/main.rs to import the `greetings` lib and call its hello world function
70-
extern crate greetings;
71-
72-
fn main() {
73-
greetings::hello();
74-
}
142+
common = { path = "../common" }
75143
```
144+
{{< /tab >}}
145+
{{< tab label="my_project2 → Cargo.toml" >}}
146+
```toml {title="my_project/Cargo.toml"}
147+
[workspace]
148+
resolver = "3"
149+
members = ["crates/*"]
150+
```
151+
{{< /tab >}}
152+
{{< /tabs >}}
76153

77-
💡 On Linux and Mac, you can run `cargo` commands on each crate without changing the working directory all the times via Subshells (A command list embedded between parentheses). For example, if you are in the `greetings` directory, even you run `(cd examples/hello && cargo run)` your working directory will be kept as same in `greetings` folder.
154+
## 👨‍🏫 Before going to the next...
78155

79-
> [!assignment]
80-
> [rust-lang/rust library folder](https://github.com/rust-lang/rust/tree/main/library) is a good example for a workspace.
156+
- [rust-lang/rust library folder](https://github.com/rust-lang/rust/tree/main/library) is a good example for a workspace. Explore and identify Rust library workspace structure.

0 commit comments

Comments
 (0)