GN 根目標

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 目標找出實際的遞移依附元件。