Mục lục
Mục Tiêu Bài Học
Sau bài học, bạn sẽ:
- Định nghĩa được Cargo là gì và 6 vai trò bao trùm trong vòng đời một project Rust (build, package, test, doc, workspace, bench).
- Hiểu vì sao Cargo đi kèm rustup mặc định và không bao giờ phải cài rời như các language tooling khác.
- Phân biệt rõ 4 vai trò chính: build system (gọi rustc + link + incremental), package manager (resolve dep + lock file), test runner (cargo test built-in), doc generator (cargo doc + docs.rs).
- So sánh được Cargo với npm (Node), pip (Python), CMake (C/C++), Maven/Gradle (Java) để hiểu vị thế "all-in-one" là điểm khác biệt cốt lõi.
- Có bản đồ subcommand quan trọng (build, run, check, test, doc, add, install, fmt, clippy, expand, bench…) để biết bài tiếp theo nào trong Nhóm 3 sẽ học sâu cái gì.
- Biết cách dùng
cargo --listđể khám phá subcommand built-in và third-party đã cài quacargo install.
Bài này KHÔNG lặp lại "tổng quan ecosystem" đã có ở Bài 7: Hệ Sinh Thái Rust. Trọng tâm ở đây là chính bản thân Cargo — định nghĩa, vai trò, lệnh.
Định Nghĩa Cargo
Cargo là CLI tool chính thức của Rust, gom 6 vai trò trong một binary duy nhất:
- Build system — gọi
rustcđúng flag, link binary, quản lý incremental compilation. - Package manager — khai báo và resolve dependency, fetch từ crates.io / git / path.
- Test runner —
cargo testchạy mọi hàm có thuộc tính#[test], kèm integration test và doc test. - Documentation generator —
cargo docdùng rustdoc build HTML từ comment///. - Workspace manager — quản lý project nhiều crate chung target/ và Cargo.lock.
- Benchmark runner —
cargo benchchạy micro-benchmark (built-in cần nightly, hoặc dùng cratecriteriontrên stable).
Cargo do chính Rust team duy trì, được viết bằng Rust và mã nguồn ở repo rust-lang/cargo. Phiên bản đi cùng rustc theo cùng release train 6 tuần.
Lịch sử ngắn: Cargo ra mắt cùng Rust 0.9 vào tháng 1/2014 và trở thành công cụ build mặc định kể từ Rust 1.0 (5/2015). Tài liệu chính thức là The Cargo Book (thường được gọi là cargo-the-book) tại doc.rust-lang.org/cargo/.
Vì sao Cargo đi kèm rustup theo mặc định: khi cài Rust qua rustup-init, bạn nhận được bộ ba rustc (compiler), cargo (tool quản lý project), rustup (toolchain manager) cùng lúc. Không có khái niệm "cài Cargo riêng" — Cargo luôn được phân phối cùng compiler. Lý do thiết kế: đảm bảo mọi developer Rust trên thế giới đều có Cargo identical về behavior, version khớp với rustc đang dùng. Tránh tình trạng phân mảnh "team A dùng tool build này, team B dùng tool kia" như hệ JavaScript với npm / yarn / pnpm / bun, hay hệ C/C++ với make / cmake / meson / bazel / xmake.
Kiểm tra version Cargo:
cargo --version
cargo --help
Output cargo --version dạng cargo 1.83.0 (xxxxxxxx 2026-xx-xx) — version đi cùng rustc cùng release.
Vai Trò 1: Build System
Vai trò đầu tiên và cơ bản nhất của Cargo là build system. Bạn không gọi trực tiếp rustc như khi học hello world ở giai đoạn rất sớm — bạn gọi cargo build và Cargo tự lo phần còn lại.
Cargo chịu trách nhiệm:
- Gọi rustc với flag đúng — đọc
Cargo.tomlđể biết edition (2015 / 2018 / 2021 / 2024), profile (dev / release), feature flag, target triple, sau đó dịch sang chuỗi argument truyền vàorustc. Bạn không phải nhớ-C opt-level=3 -C lto -C codegen-units=1 --edition 2024 .... - Link binary — sau khi compile từng crate ra object/rlib, Cargo gọi linker hệ thống (ld trên Linux, link.exe trên Windows MSVC, ld64 trên macOS) để tạo executable hoặc library cuối cùng.
- Incremental compilation qua
target/— thư mụctarget/lưu kết quả compile của từng crate (target/debug/,target/release/, fingerprint, dep-info, build-script output). Lần build sau, Cargo so sánh fingerprint để biết file nào đổi, chỉ rebuild đúng phần cần thiết. Lần đầu build thường lâu (mọi dependency phải compile), từ lần thứ 2 trở đi rất nhanh. - Theo dõi dependency graph — biết crate nào phụ thuộc crate nào, build theo topo order, parallel hoá compile khi không có conflict (mặc định dùng số CPU core).
Khi bạn sửa 1 dòng trong main.rs của crate gốc, Cargo chỉ recompile crate gốc — không recompile lại 200 dependency. Khi bạn sửa Cargo.toml đổi version một dependency, Cargo recompile crate đó cùng các crate downstream phụ thuộc nó. Quy tắc đúng giúp dev loop ngắn.
Vai Trò 2: Package Manager
Vai trò thứ hai: package manager. Trong Rust, một gói (package) được gọi là một crate. Cargo lo việc khai báo, fetch, resolve và lock dependency.
- Khai báo dependency trong
Cargo.toml— section[dependencies],[dev-dependencies](chỉ cho test),[build-dependencies](cho build script). Mỗi dòng dạngtokio = "1"hoặcaxum = { version = "0.7", features = ["macros"] }. - Fetch nguồn linh hoạt — mặc định từ crates.io. Cũng hỗ trợ git (
{ git = "https://github.com/...", branch = "main" }), path local ({ path = "../core" }), hoặc registry tự host. Bạn có thể trộn cả 3 trong cùng project. - Resolve version theo SemVer —
"1"nghĩa là>=1.0.0, <2.0.0. Cargo dùng SAT solver chọn ra một version cho mỗi crate sao cho thoả mãn toàn bộ constraint trong cây dependency. - Lock file để reproducible — sau khi resolve, version cụ thể được ghi vào
Cargo.lock. Lần build sau, nếu file lock có sẵn, Cargo dùng đúng version trong lock — build cho ra binary giống hệt nhau dù 6 tháng sau dependency có release version mới. - Lệnh quản lý dependency —
cargo add <crate>thêm,cargo remove <crate>xoá,cargo updateregenerate Cargo.lock theo phiên bản mới nhất thoả constraint,cargo treein dependency graph dạng cây.
Khác biệt với npm: Cargo không có node_modules nằm trong project. Dependency tải về một lần vào ~/.cargo/registry/, dùng chung cho mọi project — tiết kiệm disk và bandwidth. Khi build, Cargo copy/link vào target/ riêng của project.
Khác biệt với pip: Cargo có lock file mặc định, không cần thêm tool như pip-tools hay poetry. Chính Cargo lo workspace multi-crate, không cần plugin.
Vai Trò 3: Test Runner
Vai trò thứ ba: test runner built-in. Không cần cài Jest, Mocha, Pytest hay JUnit riêng — Cargo có sẵn test framework.
cargo testchạy mọi hàm có#[test]— bất kỳ hàm nào trong codebase được đánh dấu#[test]đều được phát hiện và chạy. Test thường viết trong cùng file với code (module#[cfg(test)] mod tests { ... }) hoặc thư mục riêng.- Unit test — bên trong cùng module, có thể truy cập item private. Idiom Rust khuyến khích viết test ngay cạnh code.
- Integration test trong
tests/— mỗi file.rstrong thư mụctests/là một test crate độc lập, chỉ thấy public API của crate. Mô phỏng cách "user thật" sử dụng library. - Doc test trong
///— code block trong comment///được compile và chạy như test. Đảm bảo ví dụ trong tài liệu luôn cập nhật, không bao giờ lỗi thời. - Parallel execution — test chạy song song trên nhiều thread mặc định, dùng
--test-threads=1để chạy serial khi có shared state. cargo bench— chạy hàm có thuộc tính#[bench]. Built-in cần nightly; trên stable dùng cratecriterion(cài qua[dev-dependencies]) cho output thống kê chi tiết.
Một lệnh cargo test chạy hết cả 3 loại test (unit + integration + doc). Không cần config nào — convention over configuration triệt để.
Vai Trò 4: Documentation Generator
Vai trò thứ tư: documentation generator. Lệnh cargo doc chạy rustdoc để build HTML doc từ comment /// trong source code, đưa vào target/doc/. Thêm --open để mở trình duyệt ngay sau khi build.
- Comment
///(outer doc) cho item bên dưới,//!(inner doc) cho module / crate chứa nó. Cả hai đều viết bằng Markdown — heading, list, code block, link đều render đẹp. - Doc bao gồm cả dependency — chạy
cargo doc --openbạn thấy doc cho crate của mình kèm doc cho mọi dependency trong cây. Đọc offline, không cần internet, version khớp vớiCargo.lock. - Mỗi crate publish auto build trên docs.rs — sau khi
cargo publishđẩy crate lên crates.io, docs.rs tự chạycargo doctrong sandbox và host kết quả ởhttps://docs.rs/<ten-crate>/<version>. Bạn không phải tự host doc. Ví dụ mởhttps://docs.rs/tokiolà thấy API doc đầy đủ của Tokio version mới nhất; mởhttps://docs.rs/tokio/1.40.0để xem đúng version bạn dùng. - Doc test — code block trong
///đượccargo testchạy như test. Documentation và test gắn liền nhau.
So với hệ Node phải dùng JSDoc / TypeDoc rời, hay Python phải dùng Sphinx config bằng tay, Cargo + rustdoc + docs.rs là một pipeline auto từ "viết comment" → "publish" → "đọc online" mà không cần cấu hình thêm.
So Với Tool Cộng Đồng Khác
Để hiểu rõ vị thế "all-in-one" của Cargo, so với toolchain các ngôn ngữ khác:
- npm (Node.js) — chỉ lo dependency và run script. Cần ESLint cho lint, Prettier cho format, Jest/Vitest cho test, tsc cho typecheck, esbuild/tsup/webpack cho bundle, TypeDoc cho doc. Mỗi tool config riêng, version riêng, đôi khi conflict version giữa các tool. Cargo gom hết.
- pip (Python) — package manager đơn giản, thiếu workspace (multi-package trong cùng repo), lock file chỉ có một phần (qua
pip freezehoặc thêmpip-tools/poetry/uv). Test riêng (pytest), lint riêng (ruff/flake8), doc riêng (sphinx). Cargo có sẵn tất cả. - CMake (C/C++) — chỉ build và link. Dependency management hoàn toàn riêng: vcpkg, conan, hunter, hoặc thủ công git submodule. Test phải config thêm CTest. Không có doc generator built-in. C/C++ ecosystem nổi tiếng vì sự rời rạc — Cargo là một bước nhảy về integration.
- Maven / Gradle (Java) — gần Cargo nhất về phạm vi (build + dependency + test + plugin doc). Khác biệt: XML/Groovy/Kotlin DSL phức tạp hơn TOML của Cargo nhiều lần. Build cycle phức tạp (phase, goal, lifecycle). Cargo đơn giản hơn về mô hình, nhanh hơn về incremental build, và không cần JVM warmup.
Một số ngôn ngữ mới (Go, Deno, Bun) học theo Cargo về tinh thần "tooling tích hợp": go build, go test, go mod, go fmt, go doc đi cùng compiler — minh chứng cho hướng đi này được công nhận trong industry.
Subcommand Quan Trọng Overview
Đây là bản đồ subcommand bạn sẽ chạm thường nhất. Mỗi cái sẽ có bài riêng học sâu trong Nhóm 3 hoặc các nhóm sau:
cargo new <name>— tạo project mới với cấu trúc chuẩn (Bài 18).cargo init— biến thư mục hiện tại thành Cargo project (Bài 18).cargo build— compile project, output ratarget/debug/hoặctarget/release/(Bài 21).cargo run— build và chạy binary luôn (Bài 21).cargo check— typecheck nhanh, không gen binary — vòng feedback ngắn nhất khi đang viết code (Bài 21).cargo test— chạy unit + integration + doc test.cargo doc— build HTML doc bằng rustdoc,--openđể mở trình duyệt.cargo add <crate>— thêm dependency vàoCargo.tomltự động (built-in từ Cargo 1.62).cargo update— regenerateCargo.locktheo phiên bản mới nhất thoả constraint (Bài 23).cargo publish— đẩy crate lên crates.io.cargo install <crate>— cài binary crate global vào~/.cargo/bin/(kháccargo addchỉ thêm vào project hiện tại).cargo clean— xoátarget/, giải phóng disk khi cần.cargo fmt— format code theo rustfmt (componentrustfmt).cargo clippy— chạy linter với hơn 700 rule (componentclippy).cargo expand— mở rộng macro để xem code thực sự sinh ra (cài quacargo install cargo-expand).cargo bench— chạy benchmark.
Workflow tối thiểu để tạo và chạy một app:
cargo new my-app
cd my-app
cargo run
3 lệnh trên đủ để có một binary "Hello, world!" chạy được. Không cần tạo file bằng tay, không cần config build tool. Học chi tiết flow Hello World ở Bài 24 trong Nhóm 3.
cargo --list Khám Phá Subcommand
Lệnh cargo --list in ra toàn bộ subcommand mà Cargo nhận diện được trên máy bạn — bao gồm cả built-in lẫn third-party.
cargo --list
Output chia 2 nhóm:
- Built-in commands — đến từ binary
cargochính:build,check,run,test,doc,add,remove,update,publish,install,clean,fetch,tree,vendor,search,yank,login... - External subcommands — bất kỳ executable nào trong
$PATHcó tên dạngcargo-<ten>sẽ được Cargo tự nhận diện. Gọicargo foosẽ exec filecargo-foo.
Cơ chế "external subcommand" cho phép cộng đồng mở rộng Cargo mà không cần fork. Cài bằng cargo install <crate>, binary tự rơi vào ~/.cargo/bin/ (đã có sẵn trong PATH sau khi rustup setup), và xuất hiện ngay trong cargo --list.
Vài subcommand third-party quen thuộc:
cargo-edit— bộ subcommandadd,rm,upgrade(trước Cargo 1.62 không có sẵn). Hiệnadd/removeđã built-in,upgradevẫn từ crate này.cargo-watch— tự động chạy lại lệnh khi file thay đổi, rất hữu ích cho dev loop (cargo watch -x runkiểu nodemon của Node).cargo-machete— tìm dependency không dùng đến trongCargo.toml, gợi ý xoá để giảm build time.cargo-expand,cargo-audit,cargo-deny,cargo-nextest,cargo-flamegraph,cargo-llvm-cov… mỗi cái giải một bài toán cụ thể.
Cài thử một subcommand third-party:
cargo install cargo-watch
Sau khi cài xong, cargo --list sẽ có thêm dòng watch, và bạn dùng cargo watch -x check hay cargo watch -x run như subcommand chính thức. Đây là điểm extend rất sạch — không có cơ chế plugin phức tạp, chỉ là một binary trong PATH với tên đúng convention.
Tổng Kết
- Cargo là CLI all-in-one của Rust với 6 vai trò: build system, package manager, test runner, doc generator, workspace manager, benchmark runner.
- Cargo viết bằng Rust, đi cùng rustup mặc định, version khớp với rustc theo cùng release train 6 tuần — không cần cài rời.
- Build system: gọi rustc đúng flag, link binary, incremental compilation qua
target/, theo dõi dependency graph để rebuild đúng phần cần thiết. - Package manager: khai báo trong
Cargo.toml, fetch từ crates.io/git/path, resolve theo SemVer, lock vàoCargo.lock. - Test runner built-in:
cargo testchạy hết unit + integration + doc test trong một lệnh. - Doc generator:
cargo docdùng rustdoc, mỗi crate publish auto build trên docs.rs theo version. - So với npm / pip / CMake / Maven: Cargo là tích hợp nhất, đơn giản nhất về mô hình config (TOML).
- Subcommand quan trọng cần nhớ:
new,init,build,run,check,test,doc,add,update,install,fmt,clippy. cargo --listin built-in + third-party subcommand; extend bằng cách cài binary têncargo-<ten>quacargo install.- Cargo ra mắt cùng Rust 0.9 (1/2014), mặc định từ Rust 1.0 (5/2015). Tài liệu: The Cargo Book tại
doc.rust-lang.org/cargo/.
Bài Tập Củng Cố
Tự trả lời, đáp án ở cuối:
- Cargo gom 6 vai trò trong cùng một CLI. Liệt kê 6 vai trò đó và một subcommand đại diện cho mỗi vai trò.
- Một developer mới hỏi: "Sau khi cài rustup xong, có phải cài Cargo riêng không?". Trả lời và giải thích lý do thiết kế.
- So sánh ngắn gọn Cargo với npm (Node.js): điểm giống và điểm khác cốt lõi.
- Bạn cần một tool tự động chạy lại
cargo runmỗi khi file.rsthay đổi (giống nodemon). Có sẵn trong Cargo built-in không? Nếu không, làm sao có? - Mở terminal và chạy
cargo --list. Phân biệt được dòng nào là built-in command, dòng nào là third-party đã cài quacargo install. Cơ chế nào cho phép Cargo "thấy" được third-party subcommand?
Đáp án
- (1) Build system —
cargo build. (2) Package manager —cargo add/cargo update. (3) Test runner —cargo test. (4) Documentation generator —cargo doc. (5) Workspace manager — quản lý multi-crate qua[workspace]trong Cargo.toml. (6) Benchmark runner —cargo bench. - Không cần cài Cargo riêng. Khi cài Rust qua
rustup-initsẽ tự kèm cảrustc,cargovàrustup. Lý do thiết kế: đảm bảo mọi dev Rust có Cargo identical về behavior và version khớp với rustc đang dùng, tránh phân mảnh tooling như hệ npm/yarn/pnpm/bun của Node. - Giống: cả hai đều là CLI tool, lo dependency declared trong file manifest (
Cargo.tomlvspackage.json), có lock file (Cargo.lockvspackage-lock.json), publish lên registry chính thức (crates.io vs npmjs.com). Khác cốt lõi: Cargo gom build + test + doc + lint (qua clippy) + format (qua rustfmt) vào cùng workflow chính thức; npm chỉ lo dependency và run script — phần còn lại phải dùng ESLint + Prettier + Jest + tsc + TypeDoc + bundler rời. Cấu hình Cargo (TOML) đơn giản hơn rất nhiều so với hệ package.json + tsconfig + .eslintrc + jest.config + prettier.config. - Không có sẵn trong Cargo built-in. Cách có: cài crate
cargo-watchbằngcargo install cargo-watch, sau đó dùngcargo watch -x run. Đây là third-party subcommand — binarycargo-watchnằm trong~/.cargo/bin/(đã có trong PATH), được Cargo tự nhận diện qua convention tên file. - Output
cargo --listthường nhóm "Installed Commands" trước, bao gồm cả built-in lẫn external. Dòng built-in là các lệnh đến trực tiếp từ binarycargo(build, check, run, test, doc, add, remove, update, publish, install, clean, fetch, tree...). Dòng third-party là các lệnh bạn đã cài quacargo install(watch, expand, audit, deny, machete, nextest...). Cơ chế: bất kỳ executable trong$PATHcó tên dạngcargo-<ten>sẽ được Cargo tự nhận; gọicargo footương đương exec filecargo-foo.
Bài Tiếp Theo
Bài 18: cargo new vs cargo init — Tạo Project Mới — phân biệt cargo new my-app tạo thư mục mới và cargo init áp dụng vào thư mục hiện tại, các flag quan trọng --lib, --bin, --vcs, --edition 2024, --name, và khi nào dùng lệnh nào.
