編譯模式 (Compilation Modes)
模式(Mode)是一個具名的編譯時開關,用於控制建置中包含哪些宣告。
- #[mode(name1, name2, ...)] 根據啟用的模式名稱過濾宣告。
- #[test_only] ≡ #[mode(test)]。
- 未標註的宣告始終包含在內。
- 標註的宣告僅在啟用了列表中列出的任何一個名稱時才被包含。
- 啟用任何模式(包括測試模式)意味著建置產物是不可發佈的。
- 模式僅影響編譯時的包含;除了發佈性(publishability)外,它們會在位元組碼層級被消除。
模式基礎 (Mode Basics)
模式透過以下屬性(Attributes)表示:
#[mode(name1, name2, ...)]
#[test_only] // (#[mode(test)] 的簡寫)
啟用任何模式(包括測試模式)編譯的程式碼都是不可發佈的。
本節定義了模式的語法、包含規則、作用域以及工具互動。(如需帶有範例的入門教學,請參閱指南頁面。)
模式標註 (Mode Annotations)
#[mode(...)] 標註可以放置在模組和模組成員(函式、結構體、常數等)上。
#[mode(name1, name2, ...)]
module <addr_opt>::<ident> { ... }
module <addr_opt>::<ident> {
#[mode(name1, name2, ...)]
<decl>
}
注意:#[test_only] 完全等同於 #[mode(test)]。
模式名稱 (Mode Names)
每個名稱都是一個非空的識別碼。模式名稱的比較區分大小寫。
包含模型 (Inclusion model)
令 M 為建置中已啟用模式的集合。令 S(m) 為宣告 m 上列出的模式集合,其中 #[test_only] 貢獻 {test},而未標註的宣告其 S(x) = ∅。若且唯若(if and only if)滿足以下條件之一時,宣告 x 才會包含在編譯單元中:
- S(x) = ∅(未標註)
- S(x) ∩ M ≠ ∅(標註的模式被包含)
也就是說:未標註的宣告始終包含在內;標註的宣告僅在建置中啟用了至少一個其列表中列出的名稱時才被包含,否則將被排除。
模組作用域 (Module scope)
如果一個模組被排除,其所有成員也會隱式地被排除。如果模組被包含,但某個標註的成員其自身的 S(m) 與 M 無交集,則該成員仍可能被排除。
單個屬性中的多個模式 (Multiple modes on one attribute)
#[mode(a, b, c)] 中的列表是析取的(Disjunctive,即邏輯 OR):只要任何列出的名稱匹配,就會包含該項目。
名稱解析與重複 (Name resolution & duplicates)
模式僅是編譯時的過濾器。它們不會引入執行時的條件判斷,且在位元組碼中沒有表示形式。所有驗證都在原始碼中被包含的子集上執行。
當存在重複時,適用標準的名稱解析規則。這意味著在同一次建置中,兩個模式不能啟用具有相同名稱的不同模組或成員。同樣地,帶模式標註的定義不能覆蓋具有相同名稱的未標註宣告。
若要提供模式特定的替代方案,請將它們放在由模式門控(gated)的獨立模組中,或使用不同的名稱並在測試或驅動程式中選擇它們。
使用工具與旗標 (Usage Tooling & flags)
對於建置和測試,move build --mode <name> 會將 <name> 加入 M。透過多次傳遞 --mode 可以啟用多個模式;M 是所有傳遞名稱的聯集。例如,move build --mode test --mode debug。這將啟用所有標註有 #[mode(test)] 或 #[mode(debug)] 的模組和成員。請注意,move test 隱式提供了 --mode test。
發佈性 (Publishability)
任何啟用了至少一個模式(包括測試模式)的建置都會產生「不可發佈」的產物。為了建立可發佈的產物,不能啟用任何模式。