本章會討論 Cargo 其他一些更為高級的功能,我們將展示如何:
- 使用發(fā)布配置來自定義構(gòu)建
- 將庫發(fā)布到?crates.io
- 使用工作空間來組織更大的項目
- 從?crates.io?安裝二進(jìn)制文件
- 使用自定義的命令來擴(kuò)展 Cargo
Cargo 的功能不止本章所介紹的,關(guān)于其全部功能的詳盡解釋,請查看?文檔
14.1?采用發(fā)布配置自定義構(gòu)建
在 Rust 中?發(fā)布配置(release profiles)是預(yù)定義的、可定制的帶有不同選項的配置,他們允許程序員更靈活地控制代碼編譯的多種選項。每一個配置都彼此相互獨立。
Cargo 有兩個主要的配置:運行?cargo build
?時采用的?dev
?配置和運行?cargo build --release
?的?release
?配置。dev
?配置被定義為開發(fā)時的好的默認(rèn)配置,release
?配置則有著良好的發(fā)布構(gòu)建的默認(rèn)配置。
這些配置名稱可能很眼熟,因為它們出現(xiàn)在構(gòu)建的輸出中:
$ cargo build
Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
$ cargo build --release
Finished release [optimized] target(s) in 0.0 secs
構(gòu)建輸出中的?dev
?和?release
?表明編譯器在使用不同的配置。
當(dāng)項目的?Cargo.toml?文件中沒有任何?[profile.*]
?部分的時候,Cargo 會對每一個配置都采用默認(rèn)設(shè)置。通過增加任何希望定制的配置對應(yīng)的?[profile.*]
?部分,我們可以選擇覆蓋任意默認(rèn)設(shè)置的子集。例如,如下是?dev
?和?release
?配置的?opt-level
?設(shè)置的默認(rèn)值:
文件名: Cargo.toml
[profile.dev]
opt-level = 0
[profile.release]
opt-level = 3
opt-level
?設(shè)置控制 Rust 會對代碼進(jìn)行何種程度的優(yōu)化。這個配置的值從 0 到 3。越高的優(yōu)化級別需要更多的時間編譯,所以如果你在進(jìn)行開發(fā)并經(jīng)常編譯,可能會希望在犧牲一些代碼性能的情況下編譯得快一些。這就是為什么?dev
?的?opt-level
?默認(rèn)為?0
。當(dāng)你準(zhǔn)備發(fā)布時,花費更多時間在編譯上則更好。只需要在發(fā)布模式編譯一次,而編譯出來的程序則會運行很多次,所以發(fā)布模式用更長的編譯時間換取運行更快的代碼。這正是為什么?release
?配置的?opt-level
?默認(rèn)為?3
。
對于每個配置的設(shè)置和其默認(rèn)值的完整列表,請查看?Cargo 的文檔。
14.2?將crate 發(fā)布到Crates.io
我們曾經(jīng)在項目中使用?crates.io?上的包作為依賴,不過你也可以通過發(fā)布自己的包來向它人分享代碼。crates.io?用來分發(fā)包的源代碼,所以它主要托管開源代碼。
Rust 和 Cargo 有一些幫助它人更方便找到和使用你發(fā)布的包的功能。我們將介紹一些這樣的功能,接著講到如何發(fā)布一個包。
編寫有用的文檔注釋
準(zhǔn)確的包文檔有助于其他用戶理解如何以及何時使用他們,所以花一些時間編寫文檔是值得的。第三章中我們討論了如何使用兩斜杠?//
?注釋 Rust 代碼。Rust 也有特定的用于文檔的注釋類型,通常被稱為?文檔注釋(documentation comments),他們會生成 HTML 文檔。這些 HTML 展示公有 API 文檔注釋的內(nèi)容,他們意在讓對庫感興趣的程序員理解如何?使用?這個 crate,而不是它是如何被?實現(xiàn)?的。
文檔注釋使用三斜杠?///
?而不是兩斜桿以支持 Markdown 注解來格式化文本。文檔注釋就位于需要文檔的項的之前
/// 將給定的數(shù)字加一
///
/// # Examples
///
/// ```
/// let arg = 5;
/// let answer = my_crate::add_one(arg);
///
/// assert_eq!(6, answer);
/// ```
pub fn add_one(x: i32) -> i32 {
x + 1
}
這里,我們提供了一個?add_one
?函數(shù)工作的描述,接著開始了一個標(biāo)題為?Examples
?的部分,和展示如何使用?add_one
?函數(shù)的代碼??梢赃\行?cargo doc
?來生成這個文檔注釋的 HTML 文檔。這個命令運行由 Rust 分發(fā)的工具?rustdoc
?并將生成的 HTML 文檔放入?target/doc?目錄。
?為了方便起見,運行?cargo doc --open
?會構(gòu)建當(dāng)前 crate 文檔(同時還有所有 crate 依賴的文檔)的 HTML 并在瀏覽器中打開。導(dǎo)航到?add_one
?函數(shù)將會發(fā)現(xiàn)文檔注釋的文本是如何渲染的,
輸入命令后,瀏覽器自動打開。
常用(文檔注釋)部分
其他一些 crate 作者經(jīng)常在文檔注釋中使用的部分有:
-
Panics:這個函數(shù)可能會?
panic!
?的場景。并不希望程序崩潰的函數(shù)調(diào)用者應(yīng)該確保他們不會在這些情況下調(diào)用此函數(shù)。 -
Errors:如果這個函數(shù)返回?
Result
,此部分描述可能會出現(xiàn)何種錯誤以及什么情況會造成這些錯誤,這有助于調(diào)用者編寫代碼來采用不同的方式處理不同的錯誤。 -
Safety:如果這個函數(shù)使用?
unsafe
?代碼(這會在第十九章討論),這一部分應(yīng)該會涉及到期望函數(shù)調(diào)用者支持的確保?unsafe
?塊中代碼正常工作的不變條件(invariants)。
文檔注釋作為測試
在文檔注釋中增加示例代碼塊是一個清楚的表明如何使用庫的方法,這么做還有一個額外的好處:cargo test
?也會像測試那樣運行文檔中的示例代碼!沒有什么比有例子的文檔更好的了!也沒有什么比不能正常工作的例子更糟的了,因為代碼在編寫文檔時已經(jīng)改變。
注釋包含項的結(jié)構(gòu)
還有另一種風(fēng)格的文檔注釋,//!
,這為包含注釋的項,而不是注釋之后的項增加文檔。這通常用于 crate 根文件(通常是?src/lib.rs)或模塊的根文件為 crate 或模塊整體提供文檔。
作為一個例子,如果我們希望增加描述包含?add_one
?函數(shù)的?my_crate
?crate 目的的文檔,可以在?src/lib.rs?開頭增加以?//!
?開頭的注釋
//! # My Crate
//!
//! `my_crate` 是一個使得特定計算更方便的
//! 工具集合
/// 將給定的數(shù)字加一。
// --snip--
注意?//!
?的最后一行之后沒有任何代碼。因為他們以?//!
?開頭而不是?///
,這是屬于包含此注釋的項而不是注釋之后項的文檔。在這個情況中,包含這個注釋的項是?src/lib.rs?文件,也就是 crate 根文件。這些注釋描述了整個 crate。
使用pub use 導(dǎo)出合適的公有API
公有 API 的結(jié)構(gòu)是你發(fā)布 crate 時主要需要考慮的。crate 用戶沒有你那么熟悉其結(jié)構(gòu),并且如果模塊層級過大他們可能會難以找到所需的部分。
好消息是,即使文件結(jié)構(gòu)對于用戶來說?不是?很方便,你也無需重新安排內(nèi)部組織:你可以選擇使用?pub use
?重導(dǎo)出(re-export)項來使公有結(jié)構(gòu)不同于私有結(jié)構(gòu)。重導(dǎo)出獲取位于一個位置的公有項并將其公開到另一個位置,好像它就定義在這個新位置一樣。
例如,假設(shè)我們創(chuàng)建了一個描述美術(shù)信息的庫?art
。這個庫中包含了一個有兩個枚舉?PrimaryColor
?和?SecondaryColor
?的模塊?kinds
,以及一個包含函數(shù)?mix
?的模塊?utils(lib.rs)
//! # Art
//!
//! 一個描述美術(shù)信息的庫。
pub mod kinds {
/// 采用 RGB 色彩模式的主要顏色。
pub enum PrimaryColor {
Red,
Yellow,
Blue,
}
/// 采用 RGB 色彩模式的次要顏色。
pub enum SecondaryColor {
Orange,
Green,
Purple,
}
}
pub mod utils {
use crate::kinds::*;
/// 等量的混合兩個主要顏色
/// 來創(chuàng)建一個次要顏色。
pub fn mix(c1: PrimaryColor, c2: PrimaryColor) -> SecondaryColor {
// --snip--
SecondaryColor::Orange
}
}
fn main() {}
cargo doc
?所生成的 crate 文檔
?注意?PrimaryColor
?和?SecondaryColor
?類型、以及?mix
?函數(shù)都沒有在首頁中列出。我們必須點擊?kinds
?或?utils
?才能看到他們。
另一個依賴這個庫的 crate 需要?use
?語句來導(dǎo)入?art
?中的項,這包含指定其當(dāng)前定義的模塊結(jié)構(gòu)。示例展示了一個使用?art
?crate 中?PrimaryColor
?和?mix
?項的 crate 的例子:(main.rs)
use art::kinds::PrimaryColor;
use art::utils::mix;
fn main() {
let red = PrimaryColor::Red;
let yellow = PrimaryColor::Yellow;
mix(red, yellow);
}
示例中使用?art
?crate 代碼的作者不得不搞清楚?PrimaryColor
?位于?kinds
?模塊而?mix
?位于?utils
?模塊。art
?crate 的模塊結(jié)構(gòu)相比使用它的開發(fā)者來說對編寫它的開發(fā)者更有意義。其內(nèi)部的?kinds
?模塊和?utils
?模塊的組織結(jié)構(gòu)并沒有對嘗試?yán)斫馊绾问褂盟娜颂峁┤魏斡袃r值的信息。art
?crate 的模塊結(jié)構(gòu)因不得不搞清楚所需的內(nèi)容在何處和必須在?use
?語句中指定模塊名稱而顯得混亂和不便。
為了從公有 API 中去掉 crate 的內(nèi)部組織,我們可以增加?pub use
?語句來重導(dǎo)出項到頂層結(jié)構(gòu)(lib.rs)
//! # Art
//!
//! 一個描述美術(shù)信息的庫。
pub use self::kinds::PrimaryColor;
pub use self::kinds::SecondaryColor;
pub use self::utils::mix;
pub mod kinds {
// --snip--
}
pub mod utils {
// --snip--
}
創(chuàng)建Crates.io賬號
在你可以發(fā)布任何 crate 之前,需要在?crates.io?上注冊賬號并獲取一個 API token。為此,訪問位于?crates.io?的首頁并使用 GitHub 賬號登陸。(目前 GitHub 賬號是必須的,不過將來該網(wǎng)站可能會支持其他創(chuàng)建賬號的方法)一旦登陸之后,查看位于?https://crates.io/me/?的賬戶設(shè)置頁面并獲取 API token。
發(fā)布新crate 之前
發(fā)布到Crates.io
使用cargo yank 從 Crates.io 撤回版本
14.3?Cargo工作空間
隨著項目開發(fā)的深入,庫 crate 持續(xù)增大,而你希望將其進(jìn)一步拆分成多個庫 crate。對于這種情況,Cargo 提供了一個叫?工作空間(workspaces)的功能,它可以幫助我們管理多個相關(guān)的協(xié)同開發(fā)的包。
創(chuàng)建工作空間
工作空間?是一系列共享同樣的?Cargo.lock?和輸出目錄的包。讓我們使用工作空間創(chuàng)建一個項目 —— 這里采用常見的代碼以便可以關(guān)注工作空間的結(jié)構(gòu)。有多種組織工作空間的方式;我們將展示一個常用方法。我們的工作空間有一個二進(jìn)制項目和兩個庫。二進(jìn)制項目會提供主要功能,并會依賴另兩個庫。一個庫會提供?add_one
?方法而第二個會提供?add_two
?方法。這三個 crate 將會是相同工作空間的一部分。讓我們以新建工作空間目錄開始:
$ mkdir add
$ cd add
接著在 add* 目錄中,創(chuàng)建?Cargo.toml?文件。這個?Cargo.toml?文件配置了整個工作空間。它不會包含?[package]
?或其他我們在?Cargo.toml?中見過的元信息。相反,它以?[workspace]
?部分作為開始,并通過指定?adder?的路徑來為工作空間增加成員,如下會加入二進(jìn)制 crate:
[workspace]
members = [
"adder",
]
接下來,在?add?目錄運行?cargo new
?新建?adder
?二進(jìn)制 crate:
$ cargo new adder
Created binary (application) `adder` project
到此為止,可以運行?cargo build
?來構(gòu)建工作空間。add?目錄中的文件應(yīng)該看起來像這樣:
工作空間在頂級目錄有一個?target?目錄;adder
?并沒有自己的?target?目錄。即使進(jìn)入?adder?目錄運行?cargo build
,構(gòu)建結(jié)果也位于?add/target?而不是?add/adder/target。工作空間中的 crate 之間相互依賴。如果每個 crate 有其自己的?target?目錄,為了在自己的?target?目錄中生成構(gòu)建結(jié)果,工作空間中的每一個 crate 都不得不相互重新編譯其他 crate。通過共享一個?target?目錄,工作空間可以避免其他 crate 多余的重復(fù)構(gòu)建。
在工作空間中創(chuàng)建第二個crate
接下來,讓我們在工作空間中指定另一個成員 crate。這個 crate 位于?add-one?目錄中,所以修改頂級?Cargo.toml?為也包含?add-one?路徑:
[workspace]
members = [
"adder",
"add-one",
]
接著新生成一個叫做?add-one
?的庫:
$ cargo new add-one --lib
Created library `add-one` project
現(xiàn)在?add?目錄應(yīng)該有如下目錄和文件:
在?add-one/src/lib.rs?文件中,增加一個?add_one
?函數(shù):
文件名: add-one/src/lib.rs
pub fn add_one(x: i32) -> i32 {
x + 1
}
現(xiàn)在工作空間中有了一個庫 crate,讓?adder
?依賴庫 crate?add-one
。首先需要在?adder/Cargo.toml?文件中增加?add-one
?作為路徑依賴:
文件名: adder/Cargo.toml
[dependencies]
add-one = { path = "../add-one" }
cargo并不假定工作空間中的Crates會相互依賴,所以需要明確表明工作空間中 crate 的依賴關(guān)系。
接下來,在?adder
?crate 中使用?add-one
?crate 的函數(shù)?add_one
。打開?adder/src/main.rs?在頂部增加一行?use
?將新?add-one
?庫 crate 引入作用域。接著修改?main
?函數(shù)來調(diào)用?add_one
?函數(shù)
文件名: adder/src/main.rs
use add_one;
fn main() {
let num = 10;
println!("Hello, world! {} plus one is {}!", num, add_one::add_one(num));
}
在?add?目錄中運行?cargo build
?來構(gòu)建工作空間!
為了在頂層?add?目錄運行二進(jìn)制 crate,需要通過?-p
?參數(shù)和包名稱來運行?cargo run
?指定工作空間中我們希望使用的包:
在工作空間中依賴外部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.5.5"
現(xiàn)在就可以在?add-one/src/lib.rs?中增加?use rand;
?了,接著在?add?目錄運行?cargo build
?構(gòu)建整個工作空間就會引入并編譯?rand
?crate:
現(xiàn)在頂級的?Cargo.lock?包含了?add-one
?的?rand
?依賴的信息。然而,即使?rand
?被用于工作空間的某處,也不能在其他 crate 中使用它,除非也在他們的?Cargo.toml?中加入?rand
。
為工作空間增加測試
作為另一個提升,讓我們?yōu)?add_one
?crate 中的?add_one::add_one
?函數(shù)增加一個測試:
文件名: 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));
}
}
在頂級?add?目錄運行?cargo test
:
?輸出的第一部分顯示?add-one
?crate 的?it_works
?測試通過了。下一個部分顯示?adder
?crate 中找到了 0 個測試,最后一部分顯示?add-one
?crate 中有 0 個文檔測試。在像這樣的工作空間結(jié)構(gòu)中運行?cargo test
?會運行工作空間中所有 crate 的測試。
也可以選擇運行工作空間中特定 crate 的測試,通過在根目錄使用?-p
?參數(shù)并指定希望測試的 crate 名稱:
?輸出顯示了?cargo test
?只運行了?add-one
?crate 的測試而沒有運行?adder
?crate 的測試。
如果你選擇向?crates.io發(fā)布工作空間中的 crate,每一個工作空間中的 crate 需要單獨發(fā)布。cargo publish
?命令并沒有?--all
?或者?-p
?參數(shù),所以必須進(jìn)入每一個 crate 的目錄并運行?cargo publish
?來發(fā)布工作空間中的每一個 crate
14.4?使用cargo install 從Crates.io安裝二進(jìn)制文件
cargo install
?命令用于在本地安裝和使用二進(jìn)制 crate。它并不打算替換系統(tǒng)中的包;它意在作為一個方便 Rust 開發(fā)者們安裝其他人已經(jīng)在?crates.io?上共享的工具的手段。只有擁有二進(jìn)制目標(biāo)文件的包能夠被安裝。二進(jìn)制目標(biāo)?文件是在 crate 有?src/main.rs?或者其他指定為二進(jìn)制文件時所創(chuàng)建的可執(zhí)行程序,這不同于自身不能執(zhí)行但適合包含在其他程序中的庫目標(biāo)文件。通常 crate 的?README?文件中有該 crate 是庫、二進(jìn)制目標(biāo)還是兩者都是的信息。
所有來自?cargo install
?的二進(jìn)制文件都安裝到 Rust 安裝根目錄的?bin?文件夾中。如果你使用?rustup.rs?安裝的 Rust 且沒有自定義任何配置,這將是?$HOME/.cargo/bin
。確保將這個目錄添加到?$PATH
?環(huán)境變量中就能夠運行通過?cargo install
?安裝的程序了。
如果想要安裝?ripgrep
,可以運行如下:
$ 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
最后一行輸出展示了安裝的二進(jìn)制文件的位置和名稱,在這里?ripgrep
?被命名為?rg
。只要你像上面提到的那樣將安裝目錄加入?$PATH
,就可以運行?rg --help
?并開始使用一個更快更 Rust 的工具來搜索文件了!文章來源:http://www.zghlxwxcb.cn/news/detail-654105.html
14.5?Cargo自定義擴(kuò)展命令
Cargo 的設(shè)計使得開發(fā)者可以通過新的子命令來對 Cargo 進(jìn)行擴(kuò)展,而無需修改 Cargo 本身。如果?$PATH
?中有類似?cargo-something
?的二進(jìn)制文件,就可以通過?cargo something
?來像 Cargo 子命令一樣運行它。像這樣的自定義命令也可以運行?cargo --list
?來展示出來。能夠通過?cargo install
?向 Cargo 安裝擴(kuò)展并可以如內(nèi)建 Cargo 工具那樣運行他們是 Cargo 設(shè)計上的一個非常方便的優(yōu)點!
參考:更多關(guān)于 Cargo 和 Crates.io 的內(nèi)容 - Rust 程序設(shè)計語言 簡體中文版 (bootcss.com)文章來源地址http://www.zghlxwxcb.cn/news/detail-654105.html
到了這里,關(guān)于【Rust】Rust學(xué)習(xí) 第十四章進(jìn)一步認(rèn)識 Cargo 和 Crates.io的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!