A crate root is the entry point file that defines the scope of a Rust crate, determining whether it compiles as a binary (using main.rs) or a library (using lib.rs). The compiler automatically looks for src/main.rs to find the main function for executables, or src/lib.rs to define public APIs for reusable libraries.
If you create a binary crate with cargo new my_app, Cargo generates src/main.rs. This file must contain a fn main() entry point and serves as the root for the entire binary's namespace. Any code you write here is part of the binary's internal scope unless explicitly re-exported, though binaries typically don't expose public APIs.
For library crates created via cargo new --lib my_lib, Cargo generates src/lib.rs. This file acts as the root for the library's public interface. It does not require a main function. Instead, it uses pub items to define what other crates can import. You can organize your library code into modules within this file, and lib.rs controls what gets exposed to the outside world.
Here is a practical example of a library crate structure where lib.rs exposes a public function:
// src/lib.rs
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
mod internal {
pub fn secret_calc(x: i32) -> i32 {
x * 2
}
}
// Note: 'internal' is private by default, so 'secret_calc' is not exposed
// unless we explicitly re-export it with 'pub use internal::secret_calc;'.
You can then use this library in a separate binary crate:
// Cargo.toml in the binary project
[dependencies]
my_lib = { path = "../my_lib" }
// src/main.rs
use my_lib::add;
fn main() {
let result = add(5, 10);
println!("Result: {}", result);
}
You can also have a single project contain both a library and a binary by adding a [[bin]] section to Cargo.toml or creating a src/bin directory. In this setup, src/lib.rs remains the library root, while src/bin/main.rs (or src/bin/my_app.rs) becomes the root for the specific binary, allowing the binary to depend on the library within the same crate.
Remember that lib.rs is the default root for any crate intended to be imported as a dependency, while main.rs is strictly for standalone executables. If you need to switch a project from a binary to a library, simply rename main.rs to lib.rs and remove the main function, then update your Cargo.toml if necessary.