Fuchsia 建構作業會使用 GN 的新 root_patterns 功能,大幅縮減 GN 和 Ninja 建構圖的大小,進而大幅縮短 gn gen 時間和 Ninja 啟動時間。
不過,這項功能會以令人意外的方式,變更 GN 在剖析 BUILD.gn 檔案時的預設行為。本文將說明相關資訊。
GN 預設行為
基於歷史因素,當 GN 在預設工具鍊的環境中評估 BUILD.gn 檔案時,會例項化檔案中定義的每個目標,即使沒有任何項目實際依附於這些目標。
舉例來說,假設有下列三個 BUILD.gn 檔案,每個檔案都定義了兩個目標,且目標之間有幾個依附元件:
_//BUILD.gn____ _//foo/BUILD.gn__ _//bar/BUILD.gn_
| | | | | |
| A | | D -------------> E |
| | | | | |
| B --------------> C | | F |
|_______________| |_________________| |________________|
GN 剖析這項建構計畫時,會發生下列情況:
GN 會先載入
//BUILD.gn,然後進行評估。由於它使用預設工具鍊,因此會為該檔案中的所有項目建立目標,也就是//:A和//:B。GN 會追蹤剛建立目標的依附元件,因為
//:B依附於//foo:C,所以 GN 會先載入//foo/BUILD.gn並評估。由於仍處於預設工具鍊中,因此也會例項化該檔案中的所有目標,進而建立
//foo:C和//foo:D,即使後者並非//:A或//:B的依附元件也一樣系統會再次追蹤依附元件,並載入
//bar/BUILD.gn、評估該依附元件,然後建立這裡定義的所有目標,因此會產生//bar:E和//bar:F
如果假設 //BUILD.gn 代表圖表的根,這會導致最終建構圖表包含的目標遠多於所需目標。
GN root_patterns
如要變更這項預設行為,請在 .gn 檔案中設定 root_patterns,或使用 --root-pattern=<pattern> 指令列選項 (一次或多次)。
這些模式定義目標標籤模式清單,用於篩選要在預設工具鍊中評估的 BUILD.gn 檔案中,建立哪些非依附元件目標。
舉例來說,使用 gn gen --root-pattern=//:* 和相同的建構計畫會以如下方式變更 GN 的行為:
GN 會先載入
//BUILD.gn並進行評估。由於這是預設工具鍊,因此檔案中建立的任何目標都會符合模式 (//:*實際上是指「//BUILD.gn中的任何目標」),因此會建立//:A和//:B,與先前相同。GN 會追蹤依附元件,然後載入
//foo/BUILD.gn並評估。由於這是先前建立的其中一個目標的直接依附元件,因此 GN 會建立//foo:C。不過,GN 不會建立//foo:D,因為其標籤不符合//:*模式。GN 會在這裡停止,因為它沒有建立
//foo:D,因此沒有理由載入//bar:BUILD.gn
因此 GN 會建立 3 個目標,而不是最終建構圖中的 6 個目標。
實際結果
實際上,使用這項功能可大幅縮減 GN 建構圖的大小,並加快 gn gen 時間。舉例來說,使用 fx set minimal.x64 設定:
Default --root-pattern=//:* Reduction
Target count 183761 48375 -73%
Ninja files size (MiB) 571.7 180.2 -68%
`fx set` peak RAM (GiB) 5.02 2.89 -42%
`gn gen` time (s) 14.9 6.15 -58%
`fx set` time (s) 16.0 6.77 -57%
//:root_targets 目標。
//BUILD.gn 檔案現在定義了名為 root_targets 的頂層目標,可用於將依附元件新增至目標,即使沒有其他項目依附於這些目標,也絕對必須將其納入建構圖。
這在幾種情況下至關重要:
部分特殊
generated_file()目標,其輸出內容會做為其他目標的隱含輸入內容,但無法直接依附。硬式編碼基礎架構工具預期在樹狀結構中一律會建構的幾個目標。
某些建構工具設定預期的目標未正確列在
universe_package_labels中,且僅因同一BUILD.gn檔案中定義的其他必要目標而假設這些目標存在。
請盡量不要新增至這份清單。如果真的需要一律在最終的 Ninja 建構資訊清單中定義某個項目,最好還是從任何其他頂層 //BUILD.gn 目標找出實際的遞移依附元件。