- Feature Name: 
min_rust_version - Start Date: 2018-06-28
 - RFC PR: rust-lang/rfcs#2495
 - Rust Issue: rust-lang/rust#65262
 - Translators: [@weihanglo]
 - Commit: The commit link this page based on
 - Updated: 2020-09-07
 
總結
在 Cargo.toml 的 package 區塊加入 rust 欄位,用於指定 crate 的最低支援 Rust 版本(Minimum Supported Rust Version,MSRV)。
[package]
name = "foo"
version = "0.1.0"
rust = "1.30"
動機
當前 crate 無任何正式方法指定 MSRV,導致使用者無法在不建構該 crate 的情況下得知 crate 是否可透過他們的工具鏈(toolchain)建構。這也帶來有關如何在提升 MSRV 時管理 crate 版本的爭論,保守的作法是將之視為破壞性改動,這種作法會阻礙整個生態採納新功能,或使得版本號通膨式提升,進而讓下游的 crate 很難跟上。另一方面,若作法稍微寬鬆些,則導致採用較舊編譯器版本的使用者無法成功編譯它們的 crate。
教學式解說
若你想指定一個特定 MSRV 版本,請在 Cargo.toml 的 [package] 區塊中的 rust 欄位設定指定的 Rust 版本。如果你建構一個 crate 時有任一依賴要求的 MSRV 比你當前工具鏈更高,會導致編譯錯誤,指明該依賴與它的 MSRV。這個行為可以透過 --no-msrv-check 選項來停用。
技術文件式解說
在建構過程(包含 run、test、benchmark、verify 與 publish 子指令),cargo 會以依賴樹(dependency tree)的形式,檢查所有將要建構或檢查的所有 crate 之 MSRV 要求。在依賴樹內但不會被構建的 crate 不會執行此項檢查(例如特定目標平台或可選的 crate)。
rust 欄位應至少遵循下列要求:
- 其值需遵守語意化版號且不能有範圍運算子。注意,「1.50」是合法的值,代表「1.50.0」。
 - 版本不能比當前 stable 工具鏈高(上傳 crate 時 crates.io 會檢查)。
 - 版本不能低於 1.27(此版本將 
package.rust欄位從錯誤改為警告)。 - 版本不能比選用的 edition 釋出的版本低,舉例來說,同時出現 
rust = "1.27"與edition = 2018是非法的。 
未來展望與延伸
對版本解析之影響
rust 欄位之值(手動設定或 cargo 自動選擇)會用於選擇合適的依賴版本。
舉例來說,想像你的 crate 相依 crate foo,一個發佈了從 0.1.0 到 0.1.9 十個版本的 crate,其中 0.1.0 到 0.1.5 版在 crates.io 上 Cargo.toml 的 rust 欄位為「1.30」,其他版本則為「1.40」。現在,你建構一個專案用了例如 Rust 1.33 版,cargo 會選用 foo v0.1.5。foo v0.1.9 只會在你用 Rust 1.40 或更高版本建構專案時選用。倘若你嘗試使用 Rust 1.29 建構專案,cargo 會回報錯誤。
rust 欄位值也會被檢核。在 crate 建構過程,cargo 將檢查所有上游相依是否可以在指定 MSRV 下建構。(例如,檢查給定的 crate 與 Rust 版本限制條件下是否存在解)已除去(yank)的 crate 會略過這個檢查步驟。
期望實作這項功能得以替長久以來對 MSRV 提升是否為破壞性改動的爭論劃下休止符,並讓 crate 作者提升 crate 的 MSRV 不再如此綁手綁腳。(儘管對於已 1.0 的 crate 來說,透過提升修訂號(patch version)來提升 MSRV 次版號,以接納修復嚴重問題的 backport,可能是個有用的慣例)
注意,上述 MSRV 限制與依賴版本解析檢查,可以透過 --no-msrv-check 選項停用。
發佈時檢查 MSRV
cargo publish 將檢查上傳是以 rust 欄位指定的工具鏈版本完成,若工具鏈版本有異,cargo 會拒絕上傳該 crate。此確保機制避免因為未預期的 MSRV 提升導致錯誤的 rust 欄位值。這項檢查可透過既有的 --no-verify 選項停用。
將 rust 欄位設為必填
未來(可能是下一個 edition),我們可以設定新上傳的 crate 的 rust 欄位為必填。既有 crate 的 MSRV 會透過 edition 決定。換句話說 edition = 2018 之 MSRV 必然是 rust = "1.31",而 edition = "2015" 則是 rust = "1.0"。
cargo init 將會使用當前工具鏈使用的版本。
基於 cfg 的 MSRV
部分 crate 會根據不同目標架構平台或啟用的功能而有不同的 MSRV。可透過以下方式有效指定 MSRV 如何依賴這些配置:
[package]
rust = "1.30"
[target.x86_64-pc-windows-gnu.package]
rust = "1.35"
[target.'cfg(feature = "foo")'.package]
rust = "1.33"
在 target 區塊中所有 rust 值應等於或高於在 package 區塊的 rust 值。
若 target 的條件為真,cargo 會取用該區塊的 rust 值。若多個 target 區塊的條件為真,則取用最大值。
Nightly 與 stable 版本
部分 crate 可能偏好在最新 stable 或 nighly 工具鏈,除了指定版本之外,我們可允許宣告 stable 或 nightly 值,讓維護者不需追蹤該 crate 的 MSRV 。
對於某些超前沿的 crate(例如: rocket)常常因為 Nightly 更新就壞,將可指定特定可成功建構的 Nightly 版本。透過下列語法來達成:
- 自動選擇:
nightly此寫法與寫stable的行為一致,將使用等於當前或更高的 nightly 版本。 - 單一版本:
nightly: 2018-01-01(主要寫法) - 列舉:
nightly: 2018-01-01, 2018-01-15 - 類語意化版本條件:
nightly: >=2018-01-01、nightly: >=2018-01-01, <=2018-01-15、nightly: >=2018-01-01, <=2018-01-15, 2018-01-20。(後者會解讀為 「(version >= 2018-01-01 && version <= 2018-01-20) || version == 2018-01-20」) 
這些條件或許很嚴苛,盼使用這功能的 crate 一隻手數得出來。
缺點
- 即使宣告了 MSRV 且檢查過,並無法保持 crate 能夠正確在指定 MSRV 下正確執行,只有合理配置的 CI 能做到此事。
 - 更複雜的依賴版本解析演算法。
 - 使用 
cargo publish配合 MSRVrust = "stable"恐過於保守。 
替代方案
先驅技術
早先的提案:
未解決問題
- 瑣碎的命名問題:
rust或rustc還是min-rust-version - 額外的檢查?
 - 更優質地說明版本解析演算法
 - nightly 版本如何與「基於 cfg 的 MSRV」運作?