cargo 除了 build, run, test 以外,還有更多功能
- 以 release profile 自訂 build process
- 發布 library 到 crates.io
- 以 workspace 組織大型專案
- 由 crates.io 安裝 binaries
- 擴充 cargo 的自訂指令
以 release profile 自訂 build process
rust 的 release profile 是 pre-defined 可自訂的,帶有不同的 options,每一個 profile 都是獨立的
cargo 有兩個主要的 profile:執行 cargo build
使用 dev profile,執行 cargo build --release
使用 release profile。
當專案的 Cargo.toml 中沒有任何 [profile.*] 時,cargo 會使用預設 profiles 設定。
opt-level
控制 Rust 會對代碼進行何種程度的優化,數值是 0~3,可在 Cargo.toml 增加這幾行設定,修改 opt-level
Cargo.toml
[profile.dev]
opt-level = 0
[profile.release]
opt-level = 3
發布 library 到 crates.io
crates.io 用來分發 library 的 source code。
rust, cargo 有提供讓別人更容易找到與使用我們發布的 library 的功能
提供有用的註解
// 是 rust 的註解
/// 是 documentation comments,可產生 html 文件,主要是用來撰寫如何 "使用" 這個 crate 的說明。支援 Mardown 格式的註解
一開始是函數的說明,然後是如何使用該函數的範例
src/lib.rs
/// 將給定的數字加一
///
/// # Examples
///
/// ```
/// let five = 5;
///
/// assert_eq!(6, my_crate::add_one(5));
/// ```
pub fn add_one(x: i32) -> i32 {
x + 1
}
cargo doc
會產生文件
cargo doc --open
會產生文件的 html 並打開 browser
常用的 documentation comments
Examples
範例
Panics
該函數可能會產生
panic!
Errors
如果函數回傳
Result
,這裡說明可能會出現的錯誤及錯誤訊息Safety
如果函數使用
unsafe
,希望呼叫函數者,支援確保 unsafe 區塊正常工作的不變條件 invariants
Documentation Comments as Tests
Examples 區塊說明如何使用library,而 cargo test
也會像測試一樣,執行該區塊的範例程式碼。如果程式被改變了,那麼測試也會發生問題。這可確保程式跟文件是同步的。
Doc-tests my_crate
running 1 test
test src/lib.rs - add_one (line 5) ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
Commenting Contained Items
//! 這是另一種文件註解,這是包含 items 的註解,通常用在 crate 根文件,也就是 src/lib.rs,或模塊的根文件為 crate 或模塊整體提供文件。
ex: 希望增加包含 add_one
函數的 my_crate
crate 文件,可在 src/lib.rs 增加 //! 開頭的註解
//! # My Crate
//!
//! `my_crate` 是一個使得特定計算更方便的
//! 工具集合
/// 將給定的數字加一。
// --snip--
使用 pub use
匯出 public api
chap 7 介紹了使用 mod
將程式整合到 module 中,及如何使用 pub
將 item 變成公有的,及如何使用 use
將 item 引入作用域。
但開發的文件結構,可能會是多層級,不方便使用者查詢,也會討厭使用 use my_crate::some_module::another_module::UsefulType;
而不是 use my_crate::UsefulType;
來使用類別。
公有 API 結構,是發布 crate 要考慮的事情
即使原始檔的結構複雜,可用 pub use
重新匯出不同的 public api 結構
ex: 有一個 art library,裡面有兩個 enum: PrimaryColor, SecondaryColor 的模塊 kinds,及一個包含函數 mix 的模塊 utils
src/lib.rs
//! # Art
//!
//! 一個描述美術信息的庫。
pub mod kinds {
/// 採用 RGB 色彩模式的主要顏色。
pub enum PrimaryColor {
Red,
Yellow,
Blue,
}
/// 採用 RGB 色彩模式的次要顏色。
pub enum SecondaryColor {
Orange,
Green,
Purple,
}
}
pub mod utils {
use crate::kinds::*;
/// 等量的混合兩個主要顏色
/// 來創建一個次要顏色。
pub fn mix(c1: PrimaryColor, c2: PrimaryColor) -> SecondaryColor {
// --snip--
SecondaryColor::Orange
}
}
main.rs
use art::kinds::PrimaryColor;
use art::utils::mix;
fn main() {
let red = PrimaryColor::Red;
let yellow = PrimaryColor::Yellow;
mix(red, yellow);
}
使用者要搞清楚 PrimaryColor 在 kinds 模塊,而 mix 在 utils 模塊
可以採用實例中的 art
crate 並增加 pub use
語句來重導出項到頂層結構
lib.rs
//! # Art
//!
//! 一個描述美術信息的庫。
pub use kinds::PrimaryColor;
pub use kinds::SecondaryColor;
pub use utils::mix;
pub mod kinds {
// --snip--
}
pub mod utils {
// --snip--
}
可改用 pub use
的結構
use art::PrimaryColor;
use art::mix;
fn main() {
// --snip--
}
建立 Crates.io 帳號
發布 crate 前,要先在 crates.io
註冊並獲取一個 API token
然後用 cargo login 登入
cargo login abcdefghijklmnopqrstuvwxyz012345
這個命令會通知 Cargo,你的 API token 並將其儲存在本地的 ~/.cargo/credentials 文件中。注意這個 token 是一個 秘密(secret)且不應該與其他人共享。
發布 crate 前
在 crate 的 Cargo.toml 的 [package] 部分增加這個 crate 的 metadata
crate 需要一個唯一的名稱,另外要填寫關於該 crate 用途的描述和用戶可能在何種條款下使用該 crate 的 license,可使用 Linux 基金會的 Software Package Data Exchange SPDX
Cargo.toml
[package]
name = "guessing_game"
license = "MIT"
如果要用自訂的 license,可放到一個文件,並改用 license-file
指定該文件名稱
很多 Rust 社區成員選擇與 Rust 自身相同的 license,這是一個雙許可的 MIT OR Apache-2.0
。
[package]
name = "guessing_game"
version = "0.1.0"
authors = ["Your Name <you@example.com>"]
description = "A fun game where you guess what number the computer has chosen."
license = "MIT OR Apache-2.0"
[dependencies]
發布到 Crates.io
因發布是 permanent 永久的,無法覆蓋舊版,也無法刪除。
cargo publish
用這個指令發布
新版就根據 語義化版本規則 來根據修改的類型決定下一個版本號,修改 version
的值,再 cargo publish
即可
使用 cargo yank
從 Crates.io 撤銷版本
雖不能刪除舊版 crate,但可阻止其他專案加入 dependencies 中
撤銷版本可阻止新專案依賴此版本的函式庫,但現存的依賴還是可以繼續使用。撤銷帶有 Cargo.lock 專案的依賴,不會發生問題,但新產生的 Cargo.lock 將不能使用已經被撤銷的版本。
cargo yank --vers 1.0.1
可撤銷版本 1.0.1
cargo yank --vers 1.0.1 --undo
允許再次依賴該版本
Cargo 的 workspace
如果 crate 持續擴大,可拆分成多個 library crate,cargo 提供 workspace 功能,可管理多個協同開發的 package
建立 workspace
workspace 是一系列共享同樣的 Cargo.lock 與輸出目錄的 package。
現在建立一個 workspace,有一個 binary project 及兩個 libraries,一個提供 addone,一個提供 addtwo function。
mkdir add
cd add
在 add 目錄產生 Cargo.toml 檔案。內容為
[workspace]
members = [
"adder",
]
產生 adder binary crate
$ cargo new adder
Created binary (application) `adder` package
現在可以用 cargo build
建構專案,目錄及檔案如下
├── Cargo.lock
├── Cargo.toml
├── adder
│ ├── Cargo.toml
│ └── src
│ └── main.rs
└── target
在 workspace 產生第二個 crate
修改 Cargo.toml
[workspace]
members = [
"adder",
"add-one",
]
產生 add-one library
$ cargo new add-one --lib
Created library `add-one` package
現在的目錄及檔案為
├── Cargo.lock
├── Cargo.toml
├── add-one
│ ├── Cargo.toml
│ └── src
│ └── lib.rs
├── adder
│ ├── Cargo.toml
│ └── src
│ └── main.rs
└── target
在 add-one/src/lib.rs 增加一個 add_one
函數:
pub fn add_one(x: i32) -> i32 {
x + 1
}
讓 adder
依賴 crate add-one
。首先需要在 adder/Cargo.toml 文件中增加 add-one
作為路徑依賴。工作空間中的 crate 不必相互依賴,所以仍需表明工作空間中 crate 的依賴關係。
adder/Cargo.toml
[dependencies]
add-one = { path = "../add-one" }
在 adder 使用 add_one
adder/src/main.rs
use add_one;
fn main() {
let num = 10;
println!("Hello, world! {} plus one is {}!", num, add_one::add_one(num));
}
build 專案
$ cargo build
Compiling add-one v0.1.0 (/Users/charley/project/add/add-one)
Compiling adder v0.1.0 (/Users/charley/project/add/adder)
Finished dev [unoptimized + debuginfo] target(s) in 0.78s
為了在頂層 add 目錄執行二進制 crate,需要通過 -p
參數和包名稱來運行 cargo run
指定工作空間中我們希望使用的包
$ cargo run -p adder
Finished dev [unoptimized + debuginfo] target(s) in 0.06s
Running `target/debug/adder`
Hello, world! 10 plus one is 11!
在 workspace 依賴外部 crate
注意:工作空間只在根目錄有一個 Cargo.lock,而不是在每一個 crate 目錄都有 Cargo.lock。
這確保了所有的 crate 都使用完全相同版本的依賴。如果在 Cargo.toml 和 add-one/Cargo.toml 中都增加 rand
crate,則 Cargo 會將其都解析為同一版本並記錄到唯一的 Cargo.lock 中。使得工作空間中的所有 crate 都使用相同的依賴意味著其中的 crate 都是相容的。
在 add-one/Cargo.toml 中的 [dependencies]
部分增加 rand
crate 以便能夠在 add-one
crate 中使用 rand
crate:
add-one/Cargo.toml
[dependencies]
rand = "0.3.14"
現在就可以在 add-one/src/lib.rs 中增加 use rand;
了,接著在 add 目錄運行 cargo build
構建整個工作空間就會引入並編譯 rand
crate
$ cargo build
Updating crates.io index
Downloaded libc v0.2.60
Compiling libc v0.2.60
Compiling rand v0.4.6
Compiling rand v0.3.23
Compiling add-one v0.1.0 (/Users/charley/project/add/add-one)
Compiling adder v0.1.0 (/Users/charley/project/add/adder)
Finished dev [unoptimized + debuginfo] target(s) in 56.98s
頂層的 Cargo.lock 包含了 add-one
的 rand
依賴的訊息。但即使 rand
被用於工作空間的某處,也不能在其他 crate 中使用它,除非也在他們的 Cargo.toml 中加入 rand
。
測試
為 add_one
crate 中的 add_one::add_one
函數增加一個測試
add-one/src/lib.rs
pub fn add_one(x: i32) -> i32 {
x + 1
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
assert_eq!(3, add_one(2));
}
}
$ cargo test
Compiling add-one v0.1.0 (/Users/charley/project/add/add-one)
Compiling adder v0.1.0 (/Users/charley/project/add/adder)
Finished dev [unoptimized + debuginfo] target(s) in 1.30s
Running target/debug/deps/add_one-cbf892206c67cf71
running 1 test
test tests::it_works ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
Running target/debug/deps/adder-0108381d26b7c5be
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
Doc-tests add-one
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
也可指定測試的 crate
$ cargo test -p add-one
由 crates.io 安裝 binaries
cargo install
用來本地安裝及使用 binary crate
binary crate 是在 crate 有 src/main.rs 或其他可執行程式,不同於本身不能執行的 library。通常 crate 的 README 有該 crate 是 library 或 binary 的資訊。
所有來自 cargo install
的 binary crate 都安裝到 rust 安裝根目錄的 bin folder 中。如果用 rustup.rs
安裝的 rust,且沒有自訂設定,目錄會是 $HOME/.cargo/bin
將該目錄新增到 $PATH
就可以執行程式
ex: ripgrep
用於搜索文件的 grep
的 Rust 實現
$ cargo install ripgrep
Updating registry `https://github.com/rust-lang/crates.io-index`
Downloading ripgrep v0.3.2
--snip--
Compiling ripgrep v0.3.2
Finished release [optimized + debuginfo] target(s) in 97.91 secs
Installing ~/.cargo/bin/rg
擴充 cargo 的自訂指令
如果 $PATH
中有類似 cargo-something
的 binary file,就可以用 cargo something
來執行。
cargo --list
會列出所有自訂指令
沒有留言:
張貼留言