本文 AI 產出,尚未審核

Cargo 專案設定(Cargo.toml

簡介

在 Rust 生態系統中,Cargo 是唯一官方的建置與套件管理工具。它不只負責編譯、測試與發佈,還透過 Cargo.toml 檔案提供完整的專案設定。掌握 Cargo.toml 的寫法與慣例,等於擁有了管理相依、版本、功能旗標、工作區等所有專案資訊的鑰匙。

對於剛踏入 Rust 的新手而言,Cargo.toml 看起來只是一個簡單的文字檔,但它實際上是 Cargo 與 Rust 編譯器之間的協議。若能正確設定,開發流程會變得流暢;若設定不當,則可能在相依衝突、編譯失敗或發佈錯誤上耗費大量時間。本文將一步步說明 Cargo.toml 的核心概念,並提供實務範例,協助讀者從「會用」升級到「會寫」的階段。

核心概念

1. 基本結構

Cargo.toml 採用 TOML(Tom's Obvious, Minimal Language) 格式,分為多個表格(table),每個表格以方括號 [] 包住。最常見的表格包括 [package][dependencies][dev-dependencies][features] 等。

[package]
name = "my_app"          # 套件名稱,Cargo 會以此建立 crate 名稱
version = "0.1.0"        # 依照 semver 規則的版本號
edition = "2021"         # Rust edition,建議使用最新的 2021
authors = ["Alice <alice@example.com>"]
description = "示範 Cargo.toml 設定的範例專案"
license = "MIT"

Tipedition 只需要在第一次建立專案時指定,之後若要升級到更高的 edition,需要手動修改並確保程式碼相容。

2. 相依套件 ([dependencies])

相依套件是專案最重要的部分。可以指定 版本範圍來源(crates.io、Git、路徑)以及 可選功能

[dependencies]
serde = "1.0"                     # 只要符合 1.0.x 的最新版本
rand = { version = "0.8", features = ["std"] }   # 同時啟用 std 功能
log = { git = "https://github.com/rust-lang/log.git", rev = "a1b2c3d" } # 從 Git 取得特定提交
my_local_lib = { path = "../my_local_lib" } # 使用相對路徑的本地 crate
  • 版本範圍"1.0" 等同於 ^1.0,代表「兼容 1.x 但不跨越 2.0」;若想鎖定精確版本,可寫 "=1.0.3"
  • Git 相依revtagbranch 任選其一,Cargo 會根據提供的資訊檢出對應的 commit。

3. 開發相依 ([dev-dependencies])

僅在測試、範例或 cargo bench 時需要的套件,放在 dev-dependencies,不會被最終二進位檔帶入。

[dev-dependencies]
assert_cmd = "2.0"
tempfile = "3.3"

4. 功能旗標 ([features])

功能旗標讓 crate 可以 條件式地啟用 可選相依或程式碼區塊。每個功能本質上是一組相依的集合。

[features]
default = ["json"]               # 預設啟用的功能
json = ["serde_json"]            # 啟用 json 時會自動拉入 serde_json
tls = ["native-tls"]             # TLS 功能

在程式碼中使用:

#[cfg(feature = "json")]
fn parse_json(s: &str) -> serde_json::Result<serde_json::Value> {
    serde_json::from_str(s)
}

5. 工作區 ([workspace])

當專案包含多個子 crate 時,使用 工作區 讓 Cargo 共享 target 目錄與相依解析,提升建置速度。

[workspace]
members = [
    "core",
    "cli",
    "utils",
]

每個子 crate 仍保有自己的 Cargo.toml,但根目錄的 Cargo.toml 僅負責宣告工作區成員與共用設定。

6. 替代相依 ([patch][replace])

在測試新版本或臨時覆寫相依時,可使用 patchreplace

[patch.crates-io]
serde = { git = "https://github.com/serde-rs/serde.git", branch = "master" }

此設定會讓所有依賴 serde 的 crate 改為使用指定的 Git 分支。

程式碼範例

範例 1:最小可執行的 Cargo.toml

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

[dependencies]

只要 cargo run 就能產生 Hello, world!

範例 2:啟用可選功能的相依

[dependencies]
serde = { version = "1.0", features = ["derive"] }

[features]
default = []          # 不自動啟用任何功能
json = ["serde_json"] # 手動啟用時會拉入 serde_json

Cargo.toml 中加入 --features json,即可在程式碼中使用 serde_json

範例 3:工作區與共享相依

# 根目錄 Cargo.toml
[workspace]
members = ["app", "lib"]

[dependencies]
log = "0.4"   # 工作區所有成員共用此相依
# app/Cargo.toml
[package]
name = "app"
version = "0.1.0"
edition = "2021"

[dependencies]
lib = { path = "../lib" }   # 依賴工作區內的 lib
# lib/Cargo.toml
[package]
name = "lib"
version = "0.1.0"
edition = "2021"

[dependencies]
log = { version = "0.4", optional = true } # 讓 lib 可以在不需要 log 時被使用

範例 4:使用 Git 相依與特定 commit

[dependencies]
regex = { git = "https://github.com/rust-lang/regex.git", rev = "a1b2c3d4e5" }

此設定確保每次建置都使用相同的 commit,避免因上游變更導致不預期的錯誤。

範例 5:Patch 取代 crates.io 版本(臨時測試)

[patch.crates-io]
tokio = { git = "https://github.com/tokio-rs/tokio.git", branch = "master" }

在本地測試新功能時,不必等官方發佈新版本。

常見陷阱與最佳實踐

陷阱 可能的結果 解決方案 / 最佳實踐
版本範圍寫錯(如 1.0^1.0 混淆) Cargo 可能自動升級到不相容的次要版本,導致編譯錯誤。 明確使用 ^~=,必要時鎖定精確版本。
功能旗標未列入 default 使用 cargo build 時功能不會被啟用,導致缺少相依。 [features] 中將常用功能加入 default,或在 CI 中明確指定 --features
工作區成員路徑錯誤 cargo build 找不到子 crate,報錯 could not find Cargo.toml 使用相對路徑或絕對路徑,並在根目錄的 members 中保持一致。
Git 相依未鎖定 commit 每次建置可能拉到不同的 commit,產生不可重現的錯誤。 使用 revtagbranch(配合 CI)來固定版本。
[replace][patch] 同時使用 兩者的行為衝突,導致 Cargo 無法解析相依圖。 只保留 patch(較新且較安全),除非確定需要 replace 的特殊情境。

最佳實踐

  1. 使用 cargo audit 定期檢查相依的安全性。
  2. 在 CI 中鎖定功能旗標cargo test --all-features,確保所有可選功能都能通過測試。
  3. 保持 Cargo.lock:對於應用程式(binary)必須提交 Cargo.lock,確保部署環境與開發環境一致。對於 library 則可不提交。
  4. 利用 cargo metadata 觀察相依圖,快速定位衝突。

實際應用場景

  1. 微服務專案:使用工作區管理 api-gatewayauth-servicedata-service 三個子 crate,所有服務共享 logserde 等基礎相依,減少重複編譯時間。
  2. CLI 工具 + Library:將核心演算法抽成 my_lib,CLI 包裝在 my_cli 中。透過 [features] 提供 jsonyaml 輸出選項,使用者可自行決定是否安裝額外的序列化套件。
  3. 嵌入式開發:在 Cargo.toml 中加入 default = ["std"]no_std 功能,讓同一套程式碼同時支援桌面與裸機環境。
  4. 第三方套件測試:開發新功能時,使用 [patch.crates-io] 暫時把 tokio 指向 Git master,驗證相容性後再回到正式發佈版。

總結

Cargo.toml 不只是記錄套件名稱與版本的檔案,它是 Rust 專案的配置中心,掌握其語法與慣例能讓開發者在相依管理、功能切換、工作區協作上事半功倍。本文從基本結構、相依設定、功能旗標、工作區、以及進階的 patch/replace 機制,提供了完整且實務導向的說明與範例。

記得:在寫 Cargo.toml 時,清晰、可重現 是最重要的原則。透過嚴謹的版本鎖定、功能預設與 CI 測試,你的 Rust 專案將能在團隊協作與持續部署中保持穩定與可維護。祝你在 Cargo 的世界裡開發順利!