Chapter 2. Cargo

Cargo is a tool for development using the Rust programming language. Cargo serves as:

  • Build tool and frontend for the Rust compiler rustc.

    Note

    Consider using Cargo over rustc.

  • Package and dependency manager.

    Cargo allows Rust projects to declare dependencies with specific version requirements. Cargo will resolve the full dependency graph, download packages as needed, and build and test the entire project.

Rust Toolset is distributed with Cargo 1.43.0.

2.1. Creating a new Rust project

To create a Rust program on the command line, run the cargo tool as follows:

  • For Red Hat Enterprise Linux 7:

    $ scl enable rust-toolset-1.43 'cargo new --bin project_name'
  • For Red Hat Enterprise Linux 8:

    $ cargo new --bin project_name

There is a specific convention that defines directory structure and file placement within a Cargo package. Running the cargo new command generates the package directory structure and templates for both a manifest and a project file. By default, it also initializes a new Git repository in the package root directory.

For a binary program, it creates a directory project_name containing a text file named Cargo.toml and a subdirectory src containing a text file named main.rs.

To configure the project and add dependencies, edit the manifest file Cargo.toml. This file contains all the metadata needed during project compilation. See Section 2.6, “Configuring Rust project dependencies”.

To edit the project code, edit the main executable file main.rs and add new source files in the src subdirectory as needed.

In the command above, the option --bin was used to create a binary program. To create a library for a Cargo package instead of a program, run the cargo tool on the command line and pass the --lib option as follows:

  • For Red Hat Enterprise Linux 7:

    $ scl enable rust-toolset-1.43 'cargo new --lib project_name'
  • For Red Hat Enterprise Linux 8:

    $ cargo new --lib project_name

As in the previous case, this will create a package directory structure with a root directory project_name containing a library file named lib.rs located in the src subdirectory.

Note

You can execute any command using the scl utility on Red Hat Enterprise Linux 7, causing it to be run with the Rust binaries available. To use Rust Toolset on Red Hat Enterprise Linux 7 without a need to use scl enable with every command, run a shell session with:

$ scl enable rust-toolset-1.43 'bash'

Example 2.1. Creating a Rust project using Cargo

Create a new Rust project called helloworld:

  • For Red Hat Enterprise Linux 7:

    $ scl enable rust-toolset-1.43 'cargo new --bin helloworld'
         Created binary (application) helloworld project
  • For Red Hat Enterprise Linux 8:

    $ cargo new --bin helloworld
         Created binary (application) helloworld project

Examine the result:

$ cd helloworld
$ tree
.
├── Cargo.toml
└── src
    └── main.rs

1 directory, 2 files
$ cat src/main.rs
fn main() {
    println!("Hello, world!");
}

A directory helloworld is created for the project, with a file Cargo.toml for tracking project metadata, and a subdirectory src containing the main source code file main.rs.

The source code file main.rs has been initialized by Cargo to a sample hello world program.

Note

The tree tool is available from the default Red Hat Enterprise Linux repositories. To install it:

# yum install tree

2.2. Building a Rust project

To build a Rust project on the command line, change to the project directory and run the cargo tool as follows:

  • For Red Hat Enterprise Linux 7:

    $ scl enable rust-toolset-1.43 'cargo build'
  • For Red Hat Enterprise Linux 8:

    $ cargo build

Running the cargo build command resolves all dependencies of the project, downloads the missing dependencies, and compiles the project using the rustc compiler.

By default, the project is built and compiled in debug mode. This mode is used for normal development and debugging, when you need to compile the source code quickly and do not need the code optimization.

To build the project in release mode, run the cargo tool with the --release option as follows:

  • For Red Hat Enterprise Linux 7:

    $ scl enable rust-toolset-1.43 'cargo build --release'
  • For Red Hat Enterprise Linux 8:

    $ cargo build --release

Compilation time is increased in this mode due to optimizations of the source code. As a result, the compiled binary will run faster. Use this mode to produce optimized artifacts suitable for release and production.

Example 2.2. Building a Rust project using Cargo

This example assumes that you have successfully created the Rust project helloworld according to Example 2.1, “Creating a Rust project using Cargo”.

Change to the directory helloworld and build the project:

  • For Red Hat Enterprise Linux 7:

    $ scl enable rust-toolset-1.43 'cargo build'
       Compiling helloworld v0.1.0 (file:///home/vslavik/helloworld)
        Finished dev [unoptimized + debuginfo] target(s) in 0.51 secs
  • For Red Hat Enterprise Linux 8:

    $ cargo build
       Compiling helloworld v0.1.0 (file:///home/vslavik/helloworld)
        Finished dev [unoptimized + debuginfo] target(s) in 0.51 secs

Examine the result:

$ tree
.
├── Cargo.lock
├── Cargo.toml
├── src
│   └── main.rs
└── target
    └── debug
        ├── build
        ├── deps
        │   └── helloworld-b7c6fab39c2d17a7
        ├── examples
        ├── helloworld
        ├── helloworld.d
        ├── incremental
        └── native

8 directories, 6 files

A subdirectory structure has been created, starting with the directory target. Since the project was built in debug mode, the actual build output is contained in a further subdirectory debug. The actual resulting executable file is target/debug/helloworld.

Note

The tree tool is available from the default Red Hat Enterprise Linux repositories. To install it:

# yum install tree

2.3. Verifying that a Rust project compiles

To verify that a Rust program managed by Cargo can be built, on the command line change to the project directory and run the cargo tool as follows:

  • For Red Hat Enterprise Linux 7:

    $ scl enable rust-toolset-1.43 'cargo check'
  • For Red Hat Enterprise Linux 8:

    $ cargo check
Note

Consider using the cargo check command instead of the cargo build command to verify the validity of a Rust program when you do not need to build an executable. The cargo check command is faster than a full project build using the cargo build command, because it does not generate the executable code.

By default, the project is checked in debug mode. To check the project in release mode, run the cargo tool with the --release option as follows:

  • For Red Hat Enterprise Linux 7:

    $ scl enable rust-toolset-1.43 'cargo check --release'
  • For Red Hat Enterprise Linux 8:

    $ cargo check --release

Example 2.3. Verifying that a Rust project compiles with Cargo

This example assumes that you have successfully built the Rust project helloworld according to Example 2.2, “Building a Rust project using Cargo”.

Change to the directory helloworld and check the project:

  • For Red Hat Enterprise Linux 7:

    $ scl enable rust-toolset-1.43 'cargo check'
       Compiling helloworld v0.1.0 (file:///home/vslavik/helloworld)
        Finished dev [unoptimized + debuginfo] target(s) in 0.5 secs
  • For Red Hat Enterprise Linux 8:

    $ cargo check
       Compiling helloworld v0.1.0 (file:///home/vslavik/helloworld)
        Finished dev [unoptimized + debuginfo] target(s) in 0.5 secs

The project is checked, with output similar to that of the cargo build command. However, the executable file is not generated. You can verify this by comparing the current time with the time stamp of the executable file:

$ date
Fri Oct 13 08:53:21 CEST 2017
$ ls -l target/debug/helloworld
-rwxrwxr-x. 2 vslavik vslavik 252624 Oct 13 08:48 target/debug/helloworld

2.4. Running a Rust program

To run a Rust program managed as a project by Cargo on the command line, change to the project directory and run the cargo tool as follows:

  • For Red Hat Enterprise Linux 7:

    $ scl enable rust-toolset-1.43 'cargo run'
  • For Red Hat Enterprise Linux 8:

    $ cargo run

If the program has not been built yet, Cargo will run a build before running the program.

Note

Consider using Cargo to run a Rust program during development. It will correctly resolve the output path independently of the build mode.

By default, the project is built in debug mode. To build the project in release mode before running, run the cargo tool with the --release option as follows:

  • For Red Hat Enterprise Linux 7:

    $ scl enable rust-toolset-1.43 'cargo run --release'
  • For Red Hat Enterprise Linux 8:

    $ cargo run --release

Example 2.4. Running a Rust program with Cargo

This example assumes that you have successfully built the Rust project helloworld according to Example 2.2, “Building a Rust project using Cargo”.

Change to the directory helloworld and run the project:

  • For Red Hat Enterprise Linux 7:

    $ scl enable rust-toolset-1.43 'cargo run'
        Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
         Running target/debug/helloworld
    Hello, world!
  • For Red Hat Enterprise Linux 8:

    $ cargo run
        Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
         Running target/debug/helloworld
    Hello, world!

Cargo first rebuilds the project, and then runs the resulting executable file.

In this example, there were no changes to the source code since last build. As a result, Cargo did not have to rebuild the executable file, but merely accepted it as current.

2.5. Testing a Rust project

To run tests for a Cargo project on the command line, change to the project directory and run the cargo tool as follows:

  • For Red Hat Enterprise Linux 7:

    $ scl enable rust-toolset-1.43 'cargo test'
  • For Red Hat Enterprise Linux 8:

    $ cargo test

By default, the project is tested in debug mode. To test the project in release mode, run the cargo tool with the --release option as follows:

  • For Red Hat Enterprise Linux 7:

    $ scl enable rust-toolset-1.43 'cargo test --release'
  • For Red Hat Enterprise Linux 8:

    $ cargo test --release

Example 2.5. Testing a Rust project with Cargo

This example assumes that you have successfully built the Rust project helloworld according to Example 2.2, “Building a Rust project using Cargo”.

Change to the directory helloworld, and edit the file src/main.rs so that it contains the following source code:

fn main() {
    println!("Hello, world!");
}

#[test]
fn my_test() {
    assert_eq!(21+21, 42);
}

The function my_test marked as a test has been added.

Save the file, and run the test:

  • For Red Hat Enterprise Linux 7:

    $ scl enable rust-toolset-1.43 'cargo test'
       Compiling helloworld v0.1.0 (file:///home/vslavik/Documentation/rusttest/helloworld)
        Finished dev [unoptimized + debuginfo] target(s) in 0.26 secs
         Running target/debug/deps/helloworld-9dd6b83647b49aec
    
    running 1 test
    test my_test ... ok
    
    test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
  • For Red Hat Enterprise Linux 8:

    $ cargo test
       Compiling helloworld v0.1.0 (file:///home/vslavik/Documentation/rusttest/helloworld)
        Finished dev [unoptimized + debuginfo] target(s) in 0.26 secs
         Running target/debug/deps/helloworld-9dd6b83647b49aec
    
    running 1 test
    test my_test ... ok
    
    test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured

Cargo first rebuilds the project, and then runs the tests found in the project. The helloworld project has passed the test my_test successfully.

2.6. Configuring Rust project dependencies

To specify dependencies for a Cargo project, edit the file Cargo.toml in the project directory. The section [dependencies] contains a list of the project dependencies. Each dependency is listed on a new line in the following format:

crate_name = version

Rust code packages are called crates.

Example 2.6. Adding a dependency to a Rust project and building it with Cargo

This example assumes that you have successfully built the Rust project helloworld according to Example 2.2, “Building a Rust project using Cargo”.

Change to the directory helloworld and edit the file src/main.rs so that it contains the following source code:

extern crate time;

fn main() {
    println!("Hello, world!");
    println!("Time is: {}", time::now().rfc822());
}

The code now requires an external crate time. Add this dependency to project configuration by editing the file Cargo.toml so that it contains the following code:

[package]
name = "helloworld"
version = "0.1.0"
authors = ["Your Name <yourname@example.com>"]

[dependencies]
time = "0.1"

Run the cargo run command to build the project and run the resulting executable file:

  • For Red Hat Enterprise Linux 7:

    $ scl enable rust-toolset-1.43 'cargo run'
        Updating registry `https://github.com/rust-lang/crates.io-index`
     Downloading time v0.1.38
     Downloading libc v0.2.32
        Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
         Running `target/debug/helloworld`
    Hello, world!
    Time is: Fri, 13 Oct 2017 11:08:57
  • For Red Hat Enterprise Linux 8:

    $ cargo run
        Updating registry `https://github.com/rust-lang/crates.io-index`
     Downloading time v0.1.38
     Downloading libc v0.2.32
        Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
         Running `target/debug/helloworld`
    Hello, world!
    Time is: Fri, 13 Oct 2017 11:08:57

Cargo downloads the time crate and its dependencies (crate libc), stores them locally, builds all of the project source code including the dependency crates, and finally runs the resulting executable.

Additional resources

2.7. Building documentation for a Rust project

Note

Consider using the cargo doc command over rustdoc. The command cargo doc utilizes the rustdoc utility.

Note

cargo doc extracts documentation comments only for public functions, variables, and members.

Rust code can contain comments marked for extraction into documentation. The comments support the Markdown language.

To build project documentation using the Cargo tool, change to the project directory and run cargo tool:

  • For Red Hat Enterprise Linux 7:

    $ scl enable rust-toolset-1.43 'cargo doc --no-deps'
  • For Red Hat Enterprise Linux 8:

    $ cargo doc --no-deps

This extracts documentation stored from the special comments in the source code of your project and writes the documentation in HTML format.

  • Omit the --no-deps option to include dependencies in the generated documentation, including third-party libraries.
  • Add the --open option to open the generated documentation in your browser.

Example 2.7. Building documentation for a Rust project with Cargo

This example assumes that you have successfully built the Rust project helloworld with dependencies, according to Example 2.6, “Adding a dependency to a Rust project and building it with Cargo”.

Change to the directory helloworld and edit the file src/main.rs so that it contains the following source code:

//! This is a hello-world program.
extern crate time;

/// Prints a greeting to `stdout`.
pub fn print_output() {
    println!("Hello, world!");
    println!("Time is: {}", time::now().rfc822());
}

/// The program entry point.
fn main() {
    print_output();
}

The code now contains a public function print_output(). The whole helloworld program, the print_output() function, and the main() function have documentation comments.

Run the cargo doc command to build the project documentation:

  • For Red Hat Enterprise Linux 7:

    $ scl enable rust-toolset-1.43 'cargo doc --no-deps'
     Documenting helloworld v0.1.0 (file:///home/vslavik/helloworld)
        Finished dev [unoptimized + debuginfo] target(s) in 0.31 secs
  • For Red Hat Enterprise Linux 8:

    $ cargo doc --no-deps
     Documenting helloworld v0.1.0 (file:///home/vslavik/helloworld)
        Finished dev [unoptimized + debuginfo] target(s) in 0.31 secs

Install the tree tool that is available in the default Red Hat Enterprise Linux repositories, if not already installed:

# yum install tree

Examine the result:

$ tree
.
├── Cargo.lock
├── Cargo.toml
├── src
│   └── main.rs
└── target
...
    └── doc
...
        ├── helloworld
        │   ├── fn.print_output.html
        │   ├── index.html
        │   ├── print_output.v.html
        │   └── sidebar-items.js
...
        └── src
            └── helloworld
                └── main.rs.html

12 directories, 32 files

Cargo builds the project documentation. To view the documentation, open the file target/doc/helloworld/index.html in your browser. The generated documentation does not contain any mention of the main() function, because it is not public.

Run the cargo doc command without the --no-deps option to build the project documentation, including the dependency libraries time and libc:

  • For Red Hat Enterprise Linux 7:

    $ scl enable rust-toolset-1.43 'cargo doc'
     Documenting libc v0.2.32
     Documenting time v0.1.38
     Documenting helloworld v0.1.0 (file:///home/vslavik/helloworld)
        Finished dev [unoptimized + debuginfo] target(s) in 3.41 secs
  • For Red Hat Enterprise Linux 8:

    $ cargo doc
     Documenting libc v0.2.32
     Documenting time v0.1.38
     Documenting helloworld v0.1.0 (file:///home/vslavik/helloworld)
        Finished dev [unoptimized + debuginfo] target(s) in 3.41 secs

Examine the resulting directory structure with the tree command:

$ tree
...
92 directories, 11804 files
$ ls -d target/doc/*/
target/doc/helloworld/  target/doc/implementors/  target/doc/libc/  target/doc/src/  target/doc/time/

The resulting documentation now covers the dependency libraries time and libc, with each present as another subdirectory in the target/doc/ directory.

Additional resources

A detailed description of the cargo doc tool and its features is beyond the scope of this document. For more information, see the resources listed below.

2.8. Vendoring Rust project dependencies

Vendoring project dependencies means creating a local copy of the dependencies for offline redistribution and reuse. Vendored dependencies can be used by the Cargo build tool without any connection to the internet.

Note that the cargo-vendor package is included in Cargo, but there has been no change in the way it works.

Example 2.8. Vendoring Rust project dependencies

This example assumes that you have successfully built the Rust project helloworld with dependencies, according to Example 2.6, “Adding a dependency to a Rust project and building it with Cargo”.

Change to the directory helloworld and run the cargo vendor command to vendor the project with dependencies:

  • For Red Hat Enterprise Linux 7:

    $ scl enable rust-toolset-1.43 'cargo vendor'
     Downloading kernel32-sys v0.2.2
     Downloading redox_syscall v0.1.31
     Downloading winapi-build v0.1.1
     Downloading winapi v0.2.8
       Vendoring kernel32-sys v0.2.2 (/home/vslavik/.cargo/registry/src/github.com-1ecc6299db9ec823/kernel32-sys-0.2.2) to vendor/kernel32-sys
       Vendoring libc v0.2.32 (/home/vslavik/.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.32) to vendor/libc
       Vendoring redox_syscall v0.1.31 (/home/vslavik/.cargo/registry/src/github.com-1ecc6299db9ec823/redox_syscall-0.1.31) to vendor/redox_syscall
       Vendoring time v0.1.38 (/home/vslavik/.cargo/registry/src/github.com-1ecc6299db9ec823/time-0.1.38) to vendor/time
       Vendoring winapi v0.2.8 (/home/vslavik/.cargo/registry/src/github.com-1ecc6299db9ec823/winapi-0.2.8) to vendor/winapi
       Vendoring winapi-build v0.1.1 (/home/vslavik/.cargo/registry/src/github.com-1ecc6299db9ec823/winapi-build-0.1.1) to vendor/winapi-build
    To use vendored sources, add this to your .cargo/config for this project:
    
        [source.crates-io]
        replace-with = "vendored-sources"
    
        [source.vendored-sources]
        directory = "/home/vslavik/helloworld/vendor"
  • For Red Hat Enterprise Linux 8:

    $ cargo vendor

Examine the result:

$ ls
Cargo.lock  Cargo.toml  src  target  vendor
$ tree vendor
vendor
├── kernel32-sys
│   ├── build.rs
│   ├── Cargo.toml
│   ├── README.md
│   └── src
│       └── lib.rs
├── libc
│   ├── appveyor.yml
│   ├── Cargo.toml
...
75 directories, 319 files

The vendor directory contains copies of all the dependency crates needed to build the helloworld program. Note that the crates for building the project on the Windows operating system have been vendored, too, despite running this command on Red Hat Enterprise Linux.

Note

The tree tool is available from the default Red Hat Enterprise Linux repositories. To install it:

# yum install tree

2.9. Additional resources

A detailed description of the Cargo tool and its features is beyond the scope of this document. For more information, see the resources listed below.

Cargo documentation

  • cargo(1) — The manual page for the cargo tool provides detailed information on its usage. To display the manual page for the version included in Rust Toolset:

    • For Red Hat Enterprise Linux 7:

      $ scl enable rust-toolset-1.43 'man cargo'
    • For Red Hat Enterprise Linux 8:

      $ man cargo
  • Cargo, Rust’s Package Manager HTML book is provided as a package:

    • On Red Hat Enterprise Linux 7:

      # yum install rust-toolset-1.43-cargo-doc

      The HTML is available at /opt/rh/rust-toolset-1.43/root/usr/share/doc/cargo/html/index.html.

    • On Red Hat Enterprise Linux 8:

      # yum install cargo-doc

      The HTML is available at /usr/share/doc/cargo/html/index.html.

Online Cargo documentation

See also

  • Chapter 1, Rust — An overview of Rust Toolset and more information on how to install it on your system.