Introduction
Real Rust programs often reuse focused libraries instead of implementing every feature from scratch. A published Rust library is called a crate, and a crate used by your package is a dependency. Choosing and adding one safely is a normal part of Rust development.
In this lab, you will add the clap command-line parser to a prepared greeting program. You will make two small source edits, observe the generated help and validation, and learn the different jobs of Cargo.toml and Cargo.lock. The dependency is pre-downloaded during setup so your first build stays fast, but adding it to the learner project remains your task.
Add the Dependency with Cargo
In this step, you will add clap to the prepared package and inspect the manifest change Cargo makes for you.
The project is /home/labex/project/hello-cli. Move into it before running Cargo commands:
cd /home/labex/project/hello-cli
Open the package manifest with nano:
nano Cargo.toml
Cargo.toml describes the package and its direct dependencies. The empty [dependencies] table means this project currently uses only the Rust standard library. Press Ctrl+X to leave nano without changing the file.
The cargo add command safely updates the dependency table. Add clap version 4.6.7 and enable its derive feature:
cargo add clap@4.6.7 --features derive
A feature enables an optional part of a crate. Here, derive enables the macros that turn Rust structs and enums into command-line parsers. Cargo prints enabled features with + and disabled features with -; disabled features are not errors.
Open the manifest again:
nano Cargo.toml
The dependency table now contains a line shaped like this:
clap = { version = "4.6.7", features = ["derive"] }
The version is a compatibility requirement. Cargo may select a newer compatible 4.x release, while the exact selected versions are recorded separately in Cargo.lock. Press Ctrl+X to close nano.
Derive a Command-Line Parser
In this step, you will connect the Cli struct to clap with a derive macro and command metadata.
Open the prepared source file:
nano src/main.rs
You already used #[derive(Debug)] in the beginner course. A derive macro asks a crate to generate a trait implementation from the shape of a type. Replace the first TODO comment above struct Cli with these two lines:
#[derive(Parser)]
#[command(version, about = "Create a friendly greeting")]
#[derive(Parser)] generates the parsing behavior. The #[command(...)] attribute supplies information about the whole command: version reads the package version from Cargo.toml, and about provides a short description.
Save with Ctrl+O, press Enter, and exit with Ctrl+X. Check the program without running it:
cargo check
The first check compiles clap and its supporting crates, so it may show several Compiling and Checking lines. A final line beginning with Finished means the dependency and generated parser compile together.
Now ask the program for help. The -- separates Cargo options from arguments for your program:
cargo run --quiet -- --help
The output includes the description, a required <NAME> value, and automatically generated help and version options:
Create a friendly greeting
Usage: hello-cli <NAME>
...
You wrote the data shape; clap produced consistent help and argument validation from it.
Add an Optional Repetition Flag
In this step, you will add a typed option and use the parsed value in a small loop.
Run the command with one positional name first:
cargo run --quiet -- Ada
Hello, Ada!
name: String becomes a required positional value because it has no #[arg(...)] attribute. Open the source again:
nano src/main.rs
Replace the second TODO comment inside Cli with:
/// Number of greetings to print
#[arg(short, long, default_value_t = 1)]
times: u8,
The doc comment becomes help text. short creates -t, long creates --times, and default_value_t = 1 supplies a typed default when the option is absent. Because the field is u8, clap also rejects values that are not valid unsigned 8-bit integers.
Replace the final TODO comment and the single println! line with:
for _ in 0..cli.times {
println!("Hello, {}!", cli.name);
}
The underscore means the loop count itself is intentionally unused. Save and exit nano, then run three greetings:
cargo run --quiet -- Ada --times 3
Hello, Ada!
Hello, Ada!
Hello, Ada!
Try an invalid value as well:
cargo run --quiet -- Ada --times many
This command is expected to fail. clap writes an error explaining that many is not a valid u8 and exits nonzero before main uses an invalid value.
Inspect and Reuse the Locked Dependency Graph
In this step, you will inspect Cargo's resolved dependency graph and prove that the lock file can reproduce it without network access.
clap is your direct dependency, but it uses supporting crates of its own. Display the first level of the resolved graph:
cargo tree --depth 1
The exact patch version may be newer than the compatible requirement in Cargo.toml. The important shape is:
hello-cli v0.1.0 (...)
└── clap v4...
Open the generated lock file:
nano Cargo.lock
Cargo.lock is generated data, so you normally do not edit it by hand. It records the exact versions and checksums Cargo selected for the entire graph. For an application such as this CLI, keep the lock file with the project so teammates and automated builds can reuse the same resolution. Press Ctrl+X to close nano.
Now require both the existing lock and the local crate cache:
cargo check --locked --offline
--locked refuses to change Cargo.lock. --offline prevents network access. A final Finished line proves this project can be checked from the already downloaded dependency graph without silently resolving different versions.
Summary
You added a direct crate dependency with Cargo, enabled an optional feature, derived a typed clap parser, and observed automatic help and validation. You also separated the compatible requirement in Cargo.toml from the exact dependency graph in Cargo.lock, then proved the locked graph works offline.


