Sling Academy
Home/Rust/Defining a Library Crate vs a Binary Crate in Rust

Defining a Library Crate vs a Binary Crate in Rust

Last updated: January 04, 2025

Rust is a systems programming language that is blazing fast and guarantees memory safety. One of the key features in Rust is its package manager and build system called Cargo, which manages projects called 'crates'. In this article, we’ll explore the differences between library crates and binary crates and how you can get started with both in Rust.

What is a Crate in Rust?

A crate in Rust is a compilation unit, essentially a project. You can define a new crate with Cargo, and it encapsulates Rust code that can be compiled into a library or an executable. The source code for each crate can be in a single file or multiple files.

Binary Crates

Binary crates compile to executable programs. They contain a main function as the entry point of the program. When you create a binary crate, you can run it as a stand-alone application.

Here is how you can create a new binary crate:

cargo new my_binary_crate

This command will create a new directory called my_binary_crate with a folder structure similar to this:


my_binary_crate
├── Cargo.toml
└── src
    └── main.rs

The main.rs file should contain the entry point of your program, such as:

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

To compile and run your binary crate, you use the following command:

cargo run

Library Crates

Contrasting binary crates, library crates don’t typically compile into an executable but rather into a .rlib file that other crates can use as a dependency. Library crates do not have a main function.

To create a library crate, you can run the following command:

cargo new my_library_crate --lib

This will create a new project directory called my_library_crate with a basic folder structure:


my_library_crate
├── Cargo.toml
└── src
    └── lib.rs

The lib.rs file is the entry point for your library, where you define all the functions and modules to export. For example:

pub fn add(a: i32, b: i32) -> i32 {
    a + b
}

You can build the library crate using the following command:

cargo build

To use your library crate as a dependency in another crate, you just need to add it to your Cargo.toml under the [dependencies] section:


[dependencies]
my_library_crate = { path = "../my_library_crate" }

Working with Both Crate Types

A project can contain both binary and library crates. To have them within the same crate, typically, the binary crate's main.rs could use the functionalities defined in the lib.rs by declaring it in the src/lib.rs file with:

use my_library_crate;

fn main() {
    let result = my_library_crate::add(5, 10);
    println!("The sum is: {}", result);
}

This setup is useful if you want extensive sharing of functionalities between the library and the binary executable part of the same crate.

Conclusion

Understanding binary crates and library crates is crucial for efficient and modular Rust development. Binary crates execute programs while library crates serve as reusable code that you can integrate across different projects. Leveraging both allows Rust developers to write versatile and reusable code systematically. With Cargo, managing these crates is quite seamless, contributing significantly to productivity and code maintainability. Dive in, experiment with creating both, and refine your Rust prowess!

Next Article: Rust - Exploring the Cargo.toml File: Dependencies, Versions, and Features

Previous Article: Creating a Minimal Rust Project with Cargo and Default Package Structure

Series: Packages, Crates, and Modules in Rust

Rust

You May Also Like

  • E0557 in Rust: Feature Has Been Removed or Is Unavailable in the Stable Channel
  • Network Protocol Handling Concurrency in Rust with async/await
  • Using the anyhow and thiserror Crates for Better Rust Error Tests
  • Rust - Investigating partial moves when pattern matching on vector or HashMap elements
  • Rust - Handling nested or hierarchical HashMaps for complex data relationships
  • Rust - Combining multiple HashMaps by merging keys and values
  • Composing Functionality in Rust Through Multiple Trait Bounds
  • E0437 in Rust: Unexpected `#` in macro invocation or attribute
  • Integrating I/O and Networking in Rust’s Async Concurrency
  • E0178 in Rust: Conflicting implementations of the same trait for a type
  • Utilizing a Reactor Pattern in Rust for Event-Driven Architectures
  • Parallelizing CPU-Intensive Work with Rust’s rayon Crate
  • Managing WebSocket Connections in Rust for Real-Time Apps
  • Downloading Files in Rust via HTTP for CLI Tools
  • Mocking Network Calls in Rust Tests with the surf or reqwest Crates
  • Rust - Designing advanced concurrency abstractions using generic channels or locks
  • Managing code expansion in debug builds with heavy usage of generics in Rust
  • Implementing parse-from-string logic for generic numeric types in Rust
  • Rust.- Refining trait bounds at implementation time for more specialized behavior