總覽
在 GN 中,工具鍊可讓您以多種方式建立目標。為了瞭解
以及對 GN 程式碼偵錯,您必須瞭解自己使用的工具鍊。由於 GN 代碼
可以是 current_toolchain
上的條件式,也就是執行一項操作
工具鍊 A 可能會在工具鍊 B 中執行完全不同的工作;且
該工具可能完全存在於工具鍊 C 中。
本文件將詳細說明使用工具鍊解決常見問題的最佳做法
GN 代碼 (.gn
和 .gni
檔案) 發生問題。這些最佳做法
以及 Fuchsia 建構系統的最佳做法
政策。
詳情請參閱 GN 工具鍊和 Fuchsia Build。
工具鍊的運作方式,或執行 fx gn help toolchain
查看 GN 的內建
說明文件。
目標
本文件中採用的最佳做法是 目標:
- 一致性:偏好其中一種方法。
- 清楚性。使用斷言清楚傳達意圖。
- 效能:避免建構時執行不必要的工作。
最佳做法
在預期的工具鍊中斷言
如果檔案只會用於單一工具鍊或特定工具鍊中, 把斷言放在頂部
建議使用:斷言is_host
只會建構主機執行檔的 BUILD.gn
檔案。
assert(is_host)
# ...
建議:在僅在預設工具鍊中合理使用的範本中宣告 current_toolchain ==
default_toolchain
。
template("foo") {
assert(current_toolchain == default_toolchain,
"The foo template can only be used in the default toolchain")
}
將目標納入條件式
如果您無法在預期內提出聲明 工具鍊,因為檔案需要使用 將目標包裝在條件區塊中,以避免不必要的 。如此一來,您就能更輕鬆瞭解在何處使用哪些目標 這也能協助減少 GN 產生時間
建議:包裝 is_host
中的目標
和 is_fuchsia
檢查
# example/BUILD.gn
executable("built_everywhere") {
# ...
}
if (is_host) {
executable("only_on_host") {
# ...
}
}
if (is_fuchsia) {
executable("only_on_fuchsia") {
# ...
}
}
不建議的做法:定義所有指定目標 無條件使用
# example/BUILD.gn
executable("built_everywhere") {
# ...
}
executable("only_on_host") {
# ...
}
executable("only_on_fuchsia") {
# ...
}
這種做法會增加目標數量,並減緩 GN 和 ninja 的速度。
舉例來說,當 GN 在example:only_on_fuchsia
預設工具鍊,它會評估預設工具鍊中的所有 example/BUILD.gn
工具鍊,包括 only_on_host
目標。因為這層串聯防護機制
導致錯誤的可能性
到數萬個不適用的目標。
使用 is_*
變數檢查工具鍊
聲明或撰寫
目前工具鍊上的 conditional,請使用其中一個
is_*
變數
BUILDCONFIG.gn (如果滿足您的需求):
is_android = false
is_chromeos = false
is_fuchsia = false
is_fuchsia_host = false
is_host = false
is_ios = false
is_linux = false
is_mac = false
is_win = false
is_component_build = false
is_official_build = false
建議採用:使用 is_host
檢查
主機工具鍊。
if (is_host) {
# ...
}
不建議使用:使用 current_toolchain ==
host_toolchain
檢查主機工具鍊。
if (current_toolchain == host_toolchain) {
# ...
}
檢查 current_toolchain == host_toolchain
通常有誤,因為檢查中
是多個主機工具鍊 (當涉及變化版本時)。
除非有理由,否則請勿檢查 current_toolchain
的值。
舉例來說,其中一種有效的用途是檢查 current_toolchain ==
default_toolchain
是否定義跨工具鍊
動作。
偏好更少且早期的工具鍊重新導向
如要進入非預設工具鍊,您必須在某個時間點重新導向至該工具鍊。 請盡可能將這些重新導向推送到建構圖的上。這會產生 還能減少重新導向 宣告預期的工具鍊。
建議使用:重新導向至 host_toolchain
在建構初期執行這項作業
# example/BUILD.gn
group("tests") {
testonly = true
deps = [ "foo:tests($host_toolchain)" ]
}
# examples/foo/BUILD.gn
assert(is_host)
test("foo_unit_tests") {
# ...
}
test("foo_integration_tests") {
# ...
}
group("tests") {
testonly = true
deps = [
":foo_unit_tests",
":foo_integration_tests",
]
}
不建議使用:重新導向至以下網域:
在建構中之後多次執行 host_toolchain
。
# example/BUILD.gn
group("tests") {
testonly = true
deps = [ "foo:tests" ]
}
# examples/foo/BUILD.gn
if (is_host) {
test("foo_unit_tests") {
# ...
}
test("foo_integration_tests") {
# ...
}
}
group("tests") {
testonly = true
deps = [
":foo_unit_tests($host_toolchain)",
":foo_integration_tests($host_toolchain)",
]
}
這個方法不需要重複處理範例/foo/BUILD.gn 兩次, 預設工具鍊,然後再在主機工具鍊中再次執行。
避免自動工具鍊轉送
如果目標僅在特定工具鍊中具有意義,請直接參考 預期的工具鍊。
建議:在預期中斷言 並定義目標一次。
assert(current_toolchain == desired_toolchain)
action(target_name) {
# ...
}
不建議使用:隱藏工具鍊 要求自動重新導向所有其他工具鍊的 GN 群組。
if (current_toolchain == desired_toolchain) {
action(target_name) {
# ...
}
} else {
group(target_name) {
public_deps = [ ":$target_name($desired_toolchain)" ]
}
}
雖然在任何工具鍊中實現目標看起來似乎很方便, 讓你更難瞭解實際情況
將無工具鍊動作放入預設工具鍊
某些操作在工具鍊上的行為都相同,因此會浪費資源
以便在多個工具鍊中重複執行這些指令最常見的例子是
:雖然我們可能會在多個工具鍊中建構結果程式碼,
不必每次都重新產生程式碼如要解決這個問題,請確認
動作只會在 default_toolchain
中定義。
建議做法:在 預設工具鍊。
if (current_toolchain == default_toolchain) {
action("codegen") {
visibility = [ ":*" ]
outputs = [ "$target_gen_dir/main.cc" ]
# ...
}
}
executable("program") {
deps = [ ":codegen($default_toolchain)" ]
sources = get_target_outputs(deps[0])
# ...
}
不建議使用:在 每個工具鍊。
action("codegen") {
visibility = [ ":*" ]
outputs = [ "$target_gen_dir/main.cc" ]
# ...
}
executable("program") {
deps = [ ":codegen" ]
sources = get_target_outputs(deps[0])
# ...
}
使用 :anything
標籤取得輸出目錄
使用「target_gen_dir」呼叫 get_label_info
時或「target_out_dir」,只有
像是標籤的目錄,而不是目標名稱如果沒有
顯示有意義的目標,請使用名為「任何內容」的假目標。
建議:將假目標命名為「anything」。
codegen_dir = get_label_info(":anything($default_toolchain)", "target_gen_dir")
不建議的做法:為假目標命名,而不是「任何內容」。
codegen_dir = get_label_info(":bogus($default_toolchain)", "target_gen_dir")
避免使用特定語言的工具鍊
請勿針對特定程式設計語言建立工具鍊。我們的做法
結果顯示,這真的是不好的想法。舉例來說,我們過去
rust_toolchain
但後來移除了該商家檔案。我們也打算
移除 fidl_toolchain
。