Chuyển tới nội dung chính

📦 Packages và Crates

🎯 Mục Tiêu Bài Học

Sau khi hoàn thành bài học này, bạn sẽ:

  • ✅ Hiểu được package và crate là gì
  • ✅ Phân biệt binary và library crates
  • ✅ Quản lý dependencies trong Cargo.toml
  • ✅ Tạo workspace cho multi-crate projects
  • ✅ Hiểu crate publishing basics

🤔 Package vs Crate

Ẩn Dụ Cuộc Sống: Hộp và Sản Phẩm

📦 Package - Hộp đựng:

  • Một hoặc nhiều crates
  • Có file Cargo.toml
  • Quản lý dependencies

📚 Crate - Sản phẩm bên trong:

  • Binary crate → Chương trình chạy được
  • Library crate → Code tái sử dụng

Cấu Trúc Package

my_package/
├── Cargo.toml
├── src/
│ ├── main.rs # Binary crate root
│ └── lib.rs # Library crate root
└── tests/
└── integration_test.rs

📂 Binary Crates

Tạo Binary Crate

cargo new my_app
cd my_app

Cargo.toml:

[package]
name = "my_app"
version = "0.1.0"
edition = "2021"

[dependencies]

src/main.rs:

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

Multiple Binary Crates

my_package/
├── Cargo.toml
└── src/
├── main.rs
└── bin/
├── tool1.rs
└── tool2.rs
cargo run               # Chạy main.rs
cargo run --bin tool1 # Chạy tool1.rs
cargo run --bin tool2 # Chạy tool2.rs

📚 Library Crates

Tạo Library Crate

cargo new my_lib --lib
cd my_lib

src/lib.rs:

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

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_add() {
assert_eq!(add(2, 3), 5);
}
}

Sử Dụng Library

# Cargo.toml
[dependencies]
my_lib = { path = "../my_lib" }
// main.rs
use my_lib::add;

fn main() {
let result = add(5, 3);
println!("Result: {}", result);
}

🔧 Cargo.toml

Dependencies

[dependencies]
serde = "1.0" # Từ crates.io
rand = { version = "0.8", features = ["small_rng"] }
my_lib = { path = "../my_lib" } # Local path
my_git_dep = { git = "https://github.com/user/repo" }

Dev Dependencies

[dev-dependencies]
criterion = "0.5" # Chỉ dùng cho tests/benchmarks

Build Dependencies

[build-dependencies]
cc = "1.0" # Chỉ dùng cho build scripts

Features

[features]
default = ["feature1"]
feature1 = []
feature2 = ["dep:some_dependency"]

[dependencies]
some_dependency = { version = "1.0", optional = true }

🏢 Workspaces

Tạo Workspace

my_workspace/
├── Cargo.toml (workspace)
├── app/
│ ├── Cargo.toml
│ └── src/
│ └── main.rs
└── lib/
├── Cargo.toml
└── src/
└── lib.rs

Cargo.toml (root):

[workspace]
members = [
"app",
"lib",
]

app/Cargo.toml:

[package]
name = "app"
version = "0.1.0"
edition = "2021"

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

Quản Lý Workspace

cargo build              # Build tất cả
cargo build -p app # Build specific package
cargo test # Test tất cả
cargo run -p app # Run specific binary

📌 Versions

Semantic Versioning

MAJOR.MINOR.PATCH
1.2.3
  • MAJOR: Breaking changes
  • MINOR: New features (backward compatible)
  • PATCH: Bug fixes

Version Requirements

[dependencies]
serde = "1.0" # >= 1.0.0, < 2.0.0
serde = "1.0.100" # >= 1.0.100, < 2.0.0
serde = "=1.0.100" # Exactly 1.0.100
serde = ">=1.0" # >= 1.0.0
serde = "*" # Any version (không khuyến khích!)

🌐 Publishing to crates.io

Chuẩn Bị

[package]
name = "my_awesome_crate"
version = "0.1.0"
edition = "2021"
authors = ["Your Name <[email protected]>"]
license = "MIT"
description = "A short description"
homepage = "https://github.com/you/repo"
repository = "https://github.com/you/repo"
keywords = ["cli", "tool"]
categories = ["command-line-utilities"]

Publish

# Login
cargo login YOUR_API_TOKEN

# Publish
cargo publish

# Dry run
cargo publish --dry-run

🎯 Ví Dụ Thực Tế

Ví Dụ 1: App + Library

workspace/Cargo.toml:

[workspace]
members = ["math_lib", "calculator"]

math_lib/src/lib.rs:

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

pub fn multiply(a: i32, b: i32) -> i32 {
a * b
}

calculator/src/main.rs:

use math_lib::{add, multiply};

fn main() {
println!("5 + 3 = {}", add(5, 3));
println!("5 * 3 = {}", multiply(5, 3));
}

Ví Dụ 2: Features

Cargo.toml:

[package]
name = "my_crate"
version = "0.1.0"

[features]
default = ["basic"]
basic = []
advanced = ["dep:serde"]

[dependencies]
serde = { version = "1.0", optional = true }

src/lib.rs:

#[cfg(feature = "basic")]
pub fn basic_function() {
println!("Basic feature");
}

#[cfg(feature = "advanced")]
pub fn advanced_function() {
println!("Advanced feature with serde");
}

💻 Bài Tập Thực Hành

Bài 1: Tạo Workspace

Tạo workspace với 2 crates:

  • utils library
  • app binary sử dụng utils
💡 Gợi ý
mkdir my_workspace
cd my_workspace

# Root Cargo.toml
cat > Cargo.toml << EOF
[workspace]
members = ["utils", "app"]
EOF

# Create crates
cargo new utils --lib
cargo new app

# utils/src/lib.rs
# pub fn greet(name: &str) { println!("Hello, {}!", name); }

# app/Cargo.toml - add dependency
# [dependencies]
# utils = { path = "../utils" }

# app/src/main.rs
# use utils::greet;
# fn main() { greet("World"); }

🎯 Tóm Tắt

ConceptMô TảVí Dụ
PackageChứa một hoặc nhiều cratescargo new my_app
Binary crateExecutable programsrc/main.rs
Library crateReusable codesrc/lib.rs
WorkspaceMulti-crate project[workspace]
DependenciesExternal crates[dependencies]
FeaturesOptional functionality[features]

Quy tắc vàng:

  • ✅ Binary crate cho applications
  • ✅ Library crate cho reusable code
  • ✅ Workspace cho large projects
  • ✅ Semantic versioning cho versions
  • ✅ Features cho optional functionality

🔗 Liên Kết Hữu Ích


Bài tiếp theo: Use và Paths →

Trong bài tiếp theo, chúng ta sẽ tìm hiểu về use keyword và paths để import items!

Loading comments...