Let’s Rust (2nd part): Cargo, a package manager used by Rust language.

in-n-out.cloud
LetsRust
Published in
5 min readJan 3, 2023

Hey There,

It's the second day of 2023, a good day to publish 2nd part of the #letsrust series.

What is Cargo?

Cargo is a build system. It is a package-management system that automates managing Rust artifacts (packages), installs them, keeps them up-to-date, handles duplicates, and more.

A package manager, in general, is used to reduce the time spent getting an environment ready in an automated fashion.

Create a new package using Cargo

To create a new package using cargo, use the command cargo new followed by the package name. A new directory will be created, which will contain a file called Cargo.toml, also called cargo manifest, the src directory, and main.rs file in the src directory.

~/letsrust  =>cargo new p2
Created binary (application) `p2` package
~/letsrust =>ll
total 0
drwxr-xr-x 4 devnull staff 128B Jan 2 18:39 ./
drwxr-xr-x+ 81 devnull staff 2.5K Jan 2 18:06 ../
drwxr-xr-x 4 devnull staff 128B Jan 2 18:32 p1/
drwxr-xr-x 6 devnull staff 192B Jan 2 18:39 p2/
~/letsrust =>
total 8
drwxr-xr-x 4 devnull staff 128B Jan 2 18:37 .
drwxr-xr-x 5 devnull staff 160B Jan 2 18:37 ..
-rw-r--r-- 1 devnull staff 171B Jan 2 18:37 Cargo.toml
drwxr-xr-x 3 devnull staff 96B Jan 2 18:37 src
~/letsrust =>tree p2/
p2/
├── Cargo.toml
└── src
└── main.rs

1 directory, 2 files

If the source code is already written, use the command cargo initto create a new cargo package in an existing directory. The --name option can provide a desired package name. Let’s use the p1 project repository from the previous post :

~/letsrust/p1  =>ll
total 8
drwxr-xr-x 3 devnull staff 96B Dec 16 23:28 ./
drwxr-xr-x 5 devnull staff 160B Dec 16 23:28 ../
-rw-r--r-- 1 devnull staff 51B Dec 16 23:28 p1.rs
~/letsrust/p1 =>cd ..
~/letsrust =>ll
total 0
drwxr-xr-x 5 devnull staff 160B Jan 2 18:19 ./
drwxr-xr-x+ 81 devnull staff 2.5K Jan 2 18:06 ../
drwxr-xr-x 6 devnull staff 192B Dec 16 23:28 p1/

As a result of executing the cargo init command, the project directory structure will look like this:

~/letsrust =>cargo init p1
Created binary (application) package
~/letsrust/p1 =>ll
total 24
drwxr-xr-x 6 devnull staff 192B Jan 2 18:21 ./
drwxr-xr-x 5 devnull staff 160B Jan 2 18:19 ../
drwxr-xr-x 9 devnull staff 288B Jan 2 18:21 .git/
-rw-r--r-- 1 devnull staff 8B Jan 2 18:21 .gitignore
-rw-r--r-- 1 devnull staff 207B Jan 2 18:21 Cargo.toml
-rw-r--r-- 1 devnull staff 51B Dec 16 23:28 p1.rs

Cargo.toml

Created Cargo.toml is a configuration file for the Rust package called manifest. This file defines all the metadata and all the package dependencies that cargo needs to compile the p1 package.

The first heading [package] contains two required fields name and version

  • name, which is the package name
  • version the version of the package

The second heading, called[dependencies] lists all package or program dependencies. Dependencies can be marked optional using an optional key; this way, they will not be compiled by default.

Dependencies also can have features defined by using features keyword.

~/letsrust/p2  =>cat Cargo.toml 
[package]
name = "p2"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
toml = { version = "0.5", features = ["preserve_order"], optional = true }

Rust packages can have a library, binary, example, test, and benchmark targets. Full list of targets is described here. Every target defined for a Cargo package is a crate.

Rust crate is either a library or an executable program.

main.rs

In the src/main.rs the main function will be created

fn main() {
println!("Stand with Ukraine!");
}

Cargo.toml file format and all the keywords are defined here.

Generate a program with Cargo

The cargo build command executed from the package's root is used to build a package binary.

~/letsrust/p2 =>cargo build
Compiling p2 v0.1.0 (/Users/devnull/letsrust/p2)
Finished dev [unoptimized + debuginfo] target(s) in 1.01s

Cargo will create the binary named after the package in./target/debug directory.

~/letsrust/p2 =>./target/debug/p2 
Stand with Ukraine!`

The same cargo buildcommand can fetch and build all the dependencies for the already exciting packages.

The package directory, after the running cargo build command:

~/letsrust/p2 =>tree
.
├── Cargo.lock
├── Cargo.toml
├── src
│ └── main.rs
└── target
├── CACHEDIR.TAG
└── debug
├── build
├── deps
│ ├── p2-cc3c2370fa85c364
│ ├── p2-cc3c2370fa85c364.10a8fj0yihj9adco.rcgu.o
│ ├── p2-cc3c2370fa85c364.2g16lso7g8wl1bpv.rcgu.o
│ ├── p2-cc3c2370fa85c364.2hf2mey4t6xy2628.rcgu.o
│ ├── p2-cc3c2370fa85c364.4divev10990tcgnm.rcgu.o
│ ├── p2-cc3c2370fa85c364.4wrnsxn6k56ogoup.rcgu.o
│ ├── p2-cc3c2370fa85c364.5b8hhr68rq878tld.rcgu.o
│ └── p2-cc3c2370fa85c364.d
├── examples
├── incremental
│ └── p2–32xqams6b3536
│ ├── s-ggxhlw7v1a-1jwr213–37xtz0x7h1cfw
│ │ ├── 10a8fj0yihj9adco.o
│ │ ├── 2g16lso7g8wl1bpv.o
│ │ ├── 2hf2mey4t6xy2628.o
│ │ ├── 4divev10990tcgnm.o
│ │ ├── 4wrnsxn6k56ogoup.o
│ │ ├── 5b8hhr68rq878tld.o
│ │ ├── dep-graph.bin
│ │ ├── query-cache.bin
│ │ └── work-products.bin
│ └── s-ggxhlw7v1a-1jwr213.lock
├── p2
└── p2.d
9 directories, 24 files

Execute a Rust package or program with Cargo

The cargo run command executed from the package's root is used to build a package binary.

~/letsrust/p2 =>cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.00s
Running `target/debug/p2`
Stand with Ukraine!

Modify a Rust package or program with Cargo

Let’s modify the project by adding a toml crat and the version “0.5” as a string to the Cargo.toml file, like so:

[package]
name = "p2"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
toml = { version = "0.5", features = ["preserve_order"] }

The output of the cargo build command will look different now:

~/letsrust/p2 =>cargo build
Updating crates.io index
Compiling autocfg v1.1.0
Compiling serde v1.0.152
Compiling hashbrown v0.12.3
Compiling indexmap v1.9.2
Compiling toml v0.5.10
Compiling p2 v0.1.0 (/Users/devnull/letsrust/p2)
Finished dev [unoptimized + debuginfo] target(s) in 6.55s

If Cargo.toml file was updated, but the binary(executable) was not built cargo run command will compile and run everything in one step:

~/letsrust/p2 =>cargo run
Updating crates.io index
Downloaded autocfg v1.1.0
Downloaded hashbrown v0.12.3
Downloaded toml v0.5.10
Downloaded serde v1.0.152
Downloaded indexmap v1.9.2
Downloaded 5 crates (303.2 KB) in 0.59s
Compiling autocfg v1.1.0
Compiling serde v1.0.152
Compiling hashbrown v0.12.3
Compiling indexmap v1.9.2
Compiling toml v0.5.10
Compiling p2 v0.1.0 (/Users/devnull/letsrust/p2)
Finished dev [unoptimized + debuginfo] target(s) in 28.14s
Running `target/debug/p2`
Stand with Ukraine!

Cargo crates

In the above example, toml dependencies are called crate in Cargo.

cargo is configured to use crates by default to find requested packages.

Based on the above definition, the Rust package can be described as a functional bundle of one or more crates.

My useful notes:

  • Note 1: Commandinit can be used with the option --vcs to initialize a new VCS repository for the given version control system (git, hg, pijul, or fossil).
  • Note 2: The name in the Cargo.toml file must use only alphanumeric characters or - or _, and cannot be empty. The package name can never contain numbers or special characters in its name.
  • Note 3: The other restrictions on the Rust package name are:
  1. Only ASCII characters are allowed
  2. Reserved names can’t be used
  3. Special Windows names can’t be used (e.g: “nul”.)
  4. It can’t be longer than 64 characters of length.

Happy New Year, and #letsrust more in 2023!

--

--

in-n-out.cloud
LetsRust

Staff Cloud Engineer working on k8s, cloud, microservices. Millennial. Coffeholik. Started #LetsRust on medium