DEV Community

Subesh Yadav
Subesh Yadav

Posted on

Day 26 of #100DaysOfRust: Cargo Workspaces, Installing Binaries & Custom Commands

Welcome to Day 26! πŸš€ Today was all about managing Rust projects more efficiently and expanding what Cargo can do for us. I explored:

  • Cargo Workspaces for managing multi-package projects
  • Installing binaries via cargo install
  • Extending Cargo using custom subcommands

Let’s break each of them down!


🧱 Cargo Workspaces

A workspace allows you to manage multiple related packages (crates) with a shared Cargo.lock and target directory.

βœ… Why Workspaces?

  • Share dependencies efficiently
  • Compile shared code only once
  • Keep related crates organized

πŸ”§ Creating a Workspace

  1. Create root folder and Cargo.toml without [package]:
[workspace]
resolver = "3"
members = ["adder"]
Enter fullscreen mode Exit fullscreen mode
  1. Create a binary crate:
cargo new adder
Enter fullscreen mode Exit fullscreen mode

This auto-adds adder to the members list.

Your file structure now looks like:

add/
β”œβ”€β”€ Cargo.toml (workspace root)
β”œβ”€β”€ adder/
β”‚   └── src/main.rs
└── target/
Enter fullscreen mode Exit fullscreen mode

βž• Adding More Crates

cargo new add_one --lib
Enter fullscreen mode Exit fullscreen mode

Then update the workspace Cargo.toml:

members = ["adder", "add_one"]
Enter fullscreen mode Exit fullscreen mode

In add_one/src/lib.rs:

pub fn add_one(x: i32) -> i32 {
    x + 1
}
Enter fullscreen mode Exit fullscreen mode

And in adder/Cargo.toml:

[dependencies]
add_one = { path = "../add_one" }
Enter fullscreen mode Exit fullscreen mode

πŸ§ͺ Add a test in add_one/src/lib.rs

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_works() {
        assert_eq!(add_one(2), 3);
    }
}
Enter fullscreen mode Exit fullscreen mode

Build and test the whole workspace from root:

cargo build
cargo test
Enter fullscreen mode Exit fullscreen mode

Run a specific crate:

cargo run -p adder
cargo test -p add_one
Enter fullscreen mode Exit fullscreen mode

πŸ“¦ Depending on External Crates

If you add a crate like rand to multiple crates in the workspace, Cargo ensures they use the same version and stores a single entry in the workspace-wide Cargo.lock.

# add_one/Cargo.toml
[dependencies]
rand = "0.8.5"
Enter fullscreen mode Exit fullscreen mode
use rand; // You must actually use it or get a warning
Enter fullscreen mode Exit fullscreen mode

To use rand in adder too, add it to its Cargo.toml. Dependencies are isolated per crate.


πŸ“¦ Publishing Crates from Workspace

Each crate needs to be published separately using -p:

cargo publish -p add_one
Enter fullscreen mode Exit fullscreen mode

πŸ›  Installing Binaries with cargo install

Use this to install Rust programs published to crates.io:

cargo install ripgrep
Enter fullscreen mode Exit fullscreen mode

It installs the binary to $HOME/.cargo/bin, so make sure it’s in your $PATH.

Run it like any other binary:

rg --help
Enter fullscreen mode Exit fullscreen mode

Only crates with binary targets (i.e., have a main.rs) can be installed this way.


🧩 Extending Cargo with Custom Commands

Cargo lets you define custom subcommands. If a binary is named cargo-something, you can invoke it with:

cargo something
Enter fullscreen mode Exit fullscreen mode

For example, after installing a custom tool with cargo install, you can run it as if it were built-in:

cargo expand
Enter fullscreen mode Exit fullscreen mode

Check all installed commands:

cargo --list
Enter fullscreen mode Exit fullscreen mode

This extensibility makes Cargo incredibly flexible!


🧠 Summary

  • Workspaces simplify multi-crate projects
  • cargo install gives you access to tools like ripgrep, cargo-edit, etc.
  • Custom commands help extend your workflow

πŸ“Œ Stay tuned as I continue my #100DaysOfRust journey. Follow me @SubeshDev for updates, and check out the full post on dev.to!

Top comments (0)