Skip to content

Latest commit

 

History

History
90 lines (72 loc) · 3.99 KB

ch07-01-packages-and-crates.md

File metadata and controls

90 lines (72 loc) · 3.99 KB

Packages and Crates

The first parts of the module system we’ll cover are packages and crates.

A crate is a binary or library.

The crate root is a source file that the Rust compiler starts from, and makes up the root module of your crate (we'll be explaining modules in depth in the "Defining Modules to Control Scope and Privacy" section). A package is one or more crates that, together, provide a set of functionality. A package contains a Cargo.toml that describes how to build those crates.

There are several rules about what a package can contain. A package must contain zero or one library crates, and no more. It can contain as many binary crates as you’d like, but it must contain at least one crate (either library or binary).

Now let’s walk through what happens when you create a package. First, we enter the command cargo new:

$ cargo new my-project
     Created binary (application) `my-project` package
$ ls my-project
Cargo.toml
src
$ ls my-project/src
main.rs

When we entered the command, Cargo created a Cargo.toml, giving us a package. If we look at the contents of Cargo.toml, there’s no mention of src/main.rs because Cargo follows a convention that src/main.rs is the crate root of a binary crate with the same name as the package. Likewise, Cargo knows that if the package directory contains src/lib.rs, then the package contains a library crate with the same name as the package, and src/lib.rs is its crate root. Cargo passes the crate root files to rustc to actually build the library or binary.

Here, we have a package that only contains src/main.rs, meaning it only contains a binary crate named my-project. If a package contains both src/main.rs and src/lib.rs, then it has two crates: a library and a binary, both with the same name as the package. A package can have multiple binary crates by placing files in the src/bin directory: each file will be a separate binary crate.

A crate groups related functionality together in a scope so that the functionality is easy to share between multiple projects. For example, the rand crate that we used in Chapter 2 provides functionality having to do with generating random numbers. We can use that functionality in our own projects by bringing the rand crate into our project’s scope. All of the functionality provided by the rand crate is accessible through the crate’s name, rand.

In addition to making it clear whether functionality is defined in our crate or the rand crate, keeping a crate’s functionality in its own scope prevents conflicts that could arise. For example, the rand crate provides a trait named Rng. We can also define a struct named Rng in our own crate. Because a crate’s functionality is namespaced in its own scope, when we add rand as a dependency, the compiler isn’t confused about what the name Rng refers to. In our crate, it refers to the struct Rng that we defined. The Rng trait from the rand crate is accessible as rand::Rng.

Now that we’ve covered crates, let’s talk about the module system!