Cargo and Package Management

Library Crates

A library crate defines reusable types, traits, functions, and macros intended to be linked into other Rust crates or exposed to C/FFI callers via a foreign interface. Unlike binary crates, a library crate has no fn main() entrypoint, and a Cargo package may contain at most one library crate (located by default at src/lib.rs).

src/lib.rs  ---[ `cargo build` ]--->  target/debug/libmy_crate.rlib
                                      (or .so / .dylib / .dll / .a depending on crate-type)

Library crate-type Options in [lib]

By default, Cargo compiles a library crate as crate-type = ["lib"] (producing a Rust-specific .rlib archive with metadata and compiled machine code). You can configure alternative linkage formats under the [lib] section of Cargo.toml:

crate-type Output Artifact (Linux / macOS / Windows) Primary Use Case
"lib" / "rlib" libfoo.rlib Standard static Rust library consumed by other Rust crates via Cargo.
"dylib" libfoo.so / libfoo.dylib / foo.dll Rust-to-Rust dynamic library (requires exact same rustc version across boundary).
"cdylib" libfoo.so / libfoo.dylib / foo.dll C-compatible dynamic shared library for FFI, Python extensions, WebAssembly (.wasm), or plugins.
"staticlib" libfoo.a / libfoo.a / foo.lib C-compatible static archive bundling the crate and all its Rust dependencies for linking into C/C++/iOS apps.
"proc-macro" Compiler plugin shared library Procedural macro crate (#[proc_macro], #[proc_macro_derive], #[proc_macro_attribute]).
[package]
name = "crypto_primitives"
version = "0.1.0"
edition = "2024"

[lib]
name = "crypto_primitives"
path = "src/lib.rs"
# Produce both a Rust library (.rlib) for Rust callers AND a C shared library (.dylib/.so/.dll)
crate-type = ["rlib", "cdylib"]

Designing a Clean Crate Root (src/lib.rs) with Re-Exports (pub use)

Internal module hierarchies (src/engine/parser/v2/ast.rs) are great for organizing implementation files, but forcing external callers to write use my_lib::engine::parser::v2::ast::Node; creates brittle coupling to your internal folder layout.

Instead, keep internal modules private (or document their high-level structure) and re-export primary public types at the crate root with pub use:

// Inside `src/lib.rs`:

// Private internal submodules
mod codec {
    #[derive(Debug, PartialEq, Eq)]
    pub struct PacketHeader {
        pub magic: u16,
        pub length: u16,
    }

    pub fn decode_header(bytes: [u8; 4]) -> PacketHeader {
        PacketHeader {
            magic: u16::from_be_bytes([bytes[0], bytes[1]]),
            length: u16::from_be_bytes([bytes[2], bytes[3]]),
        }
    }
}

// Re-export key public API items at the root of the library crate
pub use codec::{PacketHeader, decode_header};

/// Commonly imported traits and types grouped under a `prelude` module.
pub mod prelude {
    pub use crate::{PacketHeader, decode_header};
}

fn main() {
    // External consumers can simply write `use my_crate::prelude::*;`
    use prelude::*;

    let hdr = decode_header([0xCA, 0xFE, 0x00, 0x20]);
    println!("Decoded header: magic={:#x}, length={}", hdr.magic, hdr.length);
}
Decoded header: magic=0xcafe, length=32