Rust實現(xiàn)按需環(huán)境控制,Cargo.toml中的特性配置說明,跨平臺,可代替環(huán)境變量
Cargo的配置術(shù)語:特性 features
Cargo 的Cargo.toml 文件的語法 "特性" features提供了一種表達 條件編譯[1] 和 可選依賴項 的機制。包在 Cargo.toml 中的 [features] 表中定義了一組具有名稱的特征,每個特征可以被啟用或禁用。在構(gòu)建包時,可以通過命令行參數(shù)(如 --features)來啟用包中的特征。對于依賴項,可以在 Cargo.toml 中的依賴項聲明中啟用特征。
Cargo.toml 文件的 [features] 設(shè)置
特性是在 Cargo.toml 中的 [features] 表中定義的。每個特性都定義了一個數(shù)組,其中包含其他特征或可選依賴項,它們被該特性啟用。以下示例展示了如何使用特性來實現(xiàn)一個支持不同圖像格式的 2D 圖像處理庫。
[features]
# 定義了一個名為webp的 特性,它內(nèi)部暫不定義任何配置項。
webp = []
這個特性啟用后,可以在編譯時通過 cfg 表達式 (即 cfg-macro 語法)選擇性地包含支持該特性的代碼。例如,在包的 lib.rs 中可以:
// 這個條件編譯,包含了一個模塊,實現(xiàn) WEBP 支持。
// 代碼中可根據(jù)是否啟用了 "webp" 特性來選擇是否包含 WEBP 支持。若支持,則`pub mod webp`有效。
#[cfg(feature = "webp")]
pub mod webp;
cargo 通過使用rustc [--cfg flag] 來幫助代碼判斷某個特性是否支持;代碼中通過[cfg attribute] 或 [cfg macro]實現(xiàn)在符合特性的時候執(zhí)行代碼段。
特性可以列出其他特性來啟用。例如,ICO 圖像格式可以包含 BMP 和 PNG 圖像,所以當它被啟用時,它應(yīng)該確保其他特性也被啟用。
[features]
bmp = []
png = []
ico = ["bmp", "png"]
webp = []
Cargo 使用 rustc 的 cfg-expressions 來設(shè)置包中的特性。代碼可以使用 cfg-macro 來測試特性是否可用,以執(zhí)行緊跟的相關(guān)代碼(僅在特性啟用的情況下編譯和運行的代碼)。
例如,ICO 圖像格式可以包含 BMP 和 PNG 圖像,因此當它被啟用時,它應(yīng)該確保其他特性也被啟用。
特性名稱允許包含來自 https://unicode.org/reports/tr31/ 的字符(包括大多數(shù)字母),此外還允許從 _ 或數(shù)字 0 到 9 開始,并在第一個字符之后可能包含 -、+ 或 .。
default 特性是自帶的
默認情況下,所有特性都處于禁用狀態(tài),除非明確啟用。可以通過指定 default 特性來更改此行為:
[features]
default = ["ico", "webp"]
bmp = []
png = []
ico = ["bmp", "png"]
webp = []
當包被構(gòu)建時,default 特性被啟用,從而啟用了列出的特性。這種行為可以通過:
- --no-default-features 命令行選項禁用包的默認特性。
- default-features = false 選項可以在 Cargo.toml的 依賴聲明 (dependency-features) 中指定。
注意:選擇默認特性集時要小心。默認特性集是方便用戶不用費心選擇哪些特性被啟用,但也有缺點。依賴項會自動啟用默認特性,除非 default-features = false 被指定。這在希望 默認特性不被啟用時可能要額外告訴編譯器,尤其是在依賴圖中有多個依賴項時尤其如此。每個包必須確保default-features = false 被指定,以避免啟用它們。
另一個問題是在從默認特性集中移除特性時,這可能會破壞 SemVer 兼容性,因此你必須確保 你不會移除這些特性。
可選依賴
依賴的特性可被標記為可選的(optional),這表示它們不會被默認編譯。例如,讓我們假設(shè)我們的 2D 圖像處理庫使用一個外部包來處理 GIF 圖像。這可以用以下方式表達:
[dependencies]
gif = { version = "0.11.1", optional = true }
可選特性會隱式定義為與依賴同名的特性。這意味著代碼中可以使用相同的 cfg(feature = "gif") 語法,并且依賴可以像特性一樣啟用,例如 --features gif。
注意:[feature]表中的特性不能與依賴同一名稱。在rust的 nightly渠道上才有,可以在nightly版的rust中啟用 [namespaced 特性],注意這個是rust試驗階段的功能。
額外的特性可以啟用可選依賴,只要在特性列表中包含可選依賴的名字。例如,假設(shè)為了支持AVIF圖像格式,我們的庫需要兩個其他的依賴:
[dependencies]
ravif = { version = "0.6.3", optional = true }
rgb = { version = "0.8.25", optional = true }
[features]
avif = ["ravif", "rgb"]
本例中,avif特性會啟用兩個指定的依賴。
注意:另外的一種可選依賴的方法是使用 [platform-specific dependencies],這個是條件依賴,根據(jù)目標平臺。
特定于平臺的依賴項采用相同的格式,但在target下列出。像正常 Rust 一樣的#[cfg]語法,將用于定義這些部分:
[target.'cfg(windows)'.dependencies]
winhttp = "0.4.0"
[target.'cfg(unix)'.dependencies]
openssl = "1.0.1"
[target.'cfg(target_arch = "x86")'.dependencies]
native = { path = "native/i686" }
[target.'cfg(target_arch = "x86_64")'.dependencies]
native = { path = "native/x86_64" }
與 Rust 一樣,這里的語法支持not,any,和all運算符組合各種 cfg 名稱/值對。請注意cfg語法僅在 Cargo 0.9.0(Rust 1.8.0)之后可用.
除了#[cfg]語法,Cargo 還支持列出依賴關(guān)系適用的完整目標:
[target.x86_64-pc-windows-gnu.dependencies]
winhttp = "0.4.0"
[target.i686-unknown-linux-gnu.dependencies]
openssl = "1.0.1"
如果您使用的是自定義目標規(guī)范,請引用完整路徑和文件名:
[target."x86_64/windows.json".dependencies]
winhttp = "0.4.0"
[target."i686/linux.json".dependencies]
openssl = "1.0.1"
native = { path = "native/i686" }
[target."x86_64/linux.json".dependencies]
openssl = "1.0.1"
native = { path = "native/x86_64" }
依賴的特性
可在依賴聲明中啟用依賴的特性。features鍵指示要啟用的特性:
[dependencies]
# cargo.toml的依賴聲明中啟用 serde包的 `derive` 特性.
serde = { version = "1.0.118", features = ["derive"] }
default默認特性 可以用default-features = false聲明實現(xiàn)禁用,完整的示例如下:
[dependencies]
flate2 = { version = "1.0.3", default-features = false, features = ["zlib"] }
注意:這可能無法確保默認特性被禁用。如果另一個依賴項依賴了flate2且它未聲明default-features = false,則flate2的默認特性將被啟用。
依賴包的特性也可以在[features]表中啟用,語法為"package-name/feature-name"。例如:
[dependencies]
jpeg-decoder = { version = "0.1.20", default-features = false }
[features]
# 通過啟用jpeg-decoder的`rayon`特性,打開并行處理支持
parallel = ["jpeg-decoder/rayon"]
注意:"package-name/feature-name"語法也會啟用package-name,即使它是一個可選依賴項。
通過cargo的命令行參數(shù)控制
cargo build 命令支持控制是否啟用指定的feature,有3個相關(guān)參數(shù):
-F, --features <FEATURES> Space or comma separated list of features to activate
--all-features Activate all available features
--no-default-features Do not activate the `default` feature
通過命令行控制特性的啟用:
- --features FEATURES: 參數(shù)啟用所指定FEATURES特性是否啟用。多個特性可以用逗號或空格分隔。如果使用空格,請確保在運行Cargo從shell(例如--features "foo bar")。如果在一個[工作區(qū)]中構(gòu)建多個包,則可以使用package-name/feature-name語法來指定 特定工作區(qū)成員的特性。
- --all-features參數(shù),啟用指定的包的所有特性。
- --no-default-features參數(shù),指定不啟用指定包的default特性。
參考資料
[1]條件編譯: https://doc.rust-lang.org/cargo/reference/features.html#conditional-compilation