GN使用

原文:http://blog.csdn.net/yujiawang/article/details/72627138


GN語法和操作

1.介紹

本文描述了許多GN的語法細節和行爲。

1.1使用內置的幫助!

GN具有廣泛的內置幫助系統,爲每個函數和內置變量提供參考。 這個頁面更高級。

    GN help
  • 1
  • 1

您還可以閱讀2016年3月的GN介紹的幻燈片。演講者備註包含完整內容。

1.2設計理念

  • 編寫構建文件不應該有太多的創造性的工作。理想情況下,給定相同的要求,兩個人應該生成相同的構建文件。 
    除非確實需要,否則不應有靈活性。因爲許多事情應該儘可能作爲致命錯誤。
  • 定義應該更像代碼而不是規則。我不想寫或調試Prolog。但是我們團隊中的每個人都可以編寫和調試C ++和Python。
  • 應該考慮構建語言應該如何工作。它沒必要去容易甚至是可能表達抽象事物。 
    我們應該通過改變源碼或工具來使構建更加簡單,而不是使構建加以複雜來滿足外部需求(在合理的範圍內)。
  • 像Blaze,它什麼時候是有意義的(見下文“與Blaze的區別和相似之處”)。

2.語法

GN使用了一個非常簡單的動態類型語言。的類型是: 
* 布爾(true,false)。 
* 64位有符號整數。 
* 字符串。 
* 列表(任何其它類型)。 
* 作用域(有點像字典,只是內置的東西)。 
有一些內置的變量,其值取決於當前的環境。參見gn help更多。 
GN中有許多故意的遺漏。例如沒有用戶定義的函數調用(模板是最接近的了)。 根據上述設計理念,如果你需要這種東西,已經不符合其設計理念了。 
變量sources有一個特殊的規則:當分配給它時,排除模式的列表會應用於它。 這是爲了自動過濾掉一些類型的文件。 有關更多信息,請參閱gn help set_sources_assignment_filter和gn help label_pattern。 
書呆子似的GN的完整語法在gn help grammar中提供。

2.1字符串

字符串用雙引號和反斜線使用作爲轉義字符。唯一支持的轉義序列是: 
* \” (字符引用) 
$ (字符美元符號) 
* \ (字符反斜槓) 
反斜槓的任何其他用法被視爲字符反斜槓。 因此,例如在模式中使用的\b不需要轉義,Windows路徑,如“C\foo\bar.h”也不需要轉義。 
通過variablename使a=mypathb=a/foo.cc” # b -> “mypath/foo.cc” 
c = “foo{a}bar.cc”  # c -> “foomypathbar.cc”  
你可以使用“
0xFF”語法編碼8位字符,所以帶有換行符(十六進制0A)的字符串如下:`“look0x0Alike0x0Athis”。

2.2清單

我們是沒有辦法得到列表的長度的。 如果你發現自己想做這樣的事情,那是你在構建中做了太多的工作。 
列表支持附加:

a = [ "first" ]
a += [ "second" ]  # [ "first", "second" ]
a += [ "third", "fourth" ]  # [ "first", "second", "third", "fourth" ]
b = a + [ "fifth" ]  # [ "first", "second", "third", "fourth", "fifth" ]
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

將列表附加到另一個列表將項目附加在第二個列表中,而不是將列表附加爲嵌套成員。 
您可以從列表中刪除項目:

a = [ "first", "second", "third", "first" ]
b = a - [ "first" ]  # [ "second", "third" ]
a -= [ "second" ]  # [ "first", "third", "fourth" ]
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

列表中的 - 運算符搜索匹配項並刪除所有匹配的項。 從另一個列表中減去列表將刪除第二個列表中的每個項目。 
如果沒有找到匹配的項目,將拋出一個錯誤,因此您需要提前知道該項目在那裏,然後再刪除它。 假定沒有辦法測試是否包含,主要用例是設置文件或標誌的主列表,並根據各種條件刪除不適用於當前構建的主列表。

在文體風格上,只喜歡添加到列表,並讓每個源文件或依賴項出現一次。 這與Chrome團隊爲GYP提供的建議(GYP更願意列出所有文件,然後刪除在條件語中不需要的文件)相反。 
列表支持基於零的下標來提取值:

a = [ "first", "second", "third" ]
b = a[1]  # -> "second"
  • 1
  • 2
  • 1
  • 2

[]運算符是隻讀的,不能用於改變列表。 主要用例是當外部腳本返回幾個已知值,並且要提取它們時。 
在某些情況下,當你想要附加到列表時,很容易覆蓋列表。 爲了幫助捕獲這種情況,將非空列表賦給包含非空列表的變量是一個錯誤。如果要解決此限制,請先將空列表賦給目標變量。如下: 
a = [ “one” ] 
a = [ “two” ] # Error: overwriting nonempty list with a nonempty list. 
a = [] # OK 
a = [ “two” ] # OK 
注意,構建腳本執行時並不理解潛在數據的含義。這意味着它並不知道sources是一個文件名的列表。例如,如果你想刪除其中一項,它必須字符串完全匹配,而不是指定一個不帶後綴的名稱,它並不會解析爲相同的文件名。

2.3條件語句

條件表達式看起來像C:

  if (is_linux || (is_win && target_cpu == "x86")) {
    sources -= [ "something.cc" ]
  } else if (...) {
    ...
  } else {
    ...
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

如果目標只應在某些情況下聲明,你就可以使用條件語句,甚至是整個目標。

2.4循環

你可以用foreach遍歷一個列表。 但不鼓勵這樣做。構建做的大多數事情應該都可以表達,而不是循環,如果你發現有必要使用循環,這可能說明你在構建中做了一些無用的工作。

foreach(i, mylist) {
  print(i)  # Note: i is a copy of each element, not a reference to it.
}
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

2.5函數調用

簡單的函數調用看起來像大多數其他的語言: 
print(“hello, world”) 
assert(is_win, “This should only be executed on Windows”) 
這些功能是內置的,用戶不能定義新的功能。 
一些函數接受一個由{}括起來的代碼塊:

static_library("mylibrary") {
  sources = [ "a.cc" ]
}
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

其中大多數定義目標。 用戶可以使用下面討論的模板機制來定義這樣的functions。 
確切地說,這個表達式意味着該塊變成用於函數執行的函數的參數。 大多數塊風格函數執行塊並將結果作爲要讀取的變量的字典。

2.6作用域和執行

文件和函數調用後跟{}塊將引入新作用域。 作用域是嵌套的。 當你讀取變量時,將以相反的順序搜索包含的作用域,直到找到匹配的名稱。 變量寫入始終位於最內層。 
沒有辦法修改除最內層之外的任何封閉作用域。 這意味着,當你定義一個目標,例如,你在塊裏面做的什麼都不會“泄漏”到文件的其餘部分。 
if/else/foreach語句,即使他們使用{},不會引入一個新的作用域,所以更改會影響到語句之外。

3.命名

3.1文件和目錄名

文件和目錄名稱是字符串,並且被解釋爲相對於當前構建文件的目錄。 有三種可能的形式: 
相對名稱:

“foo.cc”
“SRC/foo.cc”
“../src/foo.cc
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

Source-tree絕對名稱:

//net/foo.cc”//base/test/foo.cc”
  • 1
  • 2
  • 1
  • 2
系統絕對名稱(很少,通常用於包含目錄):
"/usr/local/include/"
"/C:/Program Files/Windows Kits/Include"
  • 1
  • 2
  • 1
  • 2

3.2 標識

標識是有着預定義格式的字符串,依賴圖中所有的元素(目標,配置和工具鏈)都由標識唯一識別。通常情況下,標識看去是以下樣子。 
“//base/test:test_support” 
它由三部分組成:source-tree絕對路徑,冒號和名稱。上面這個標識指示到/base/test/BUILD.gn中查找名稱是“test_support”的標識。 
當加載構建文件時,如果在相對於source root給定的路徑不存在時,GN將查找build/secondary中的輔助樹。該樹的鏡像結構主存儲庫是一種從其它存儲庫添加構建文件的方式(那些我們無法簡單地合入BUILD文件) 輔助樹只是備用而不是覆蓋,因此正常位置中的文件始終優先。 
完整的標識還包括處理該標識要使用的工具鏈。工具鏈通常是以繼承的方式被默認指定,當然你也可以顯示指定。 
“//base/test:test_support(//build/toolchain/win:msvc)” 
上面這個標識會去“//build/toolchain/win”文件查到名叫”msvc”的工具鏈定義,那個定義會知道如何處理“test_support”這個標識。 
如果你指向的標識就在此個build文件,你可以省略路徑,而只是從冒號開始。 
“:base” 
你可以以相對於當前目錄的方式指定路徑。標準上說,要引用非本文件中標識時,除了它要在不同上下文運行,我們建議使用絕對路徑。什麼是要在不同上下文運行?舉個列子,一個項目它既要能構造獨立版本,又可能是其它項目的子模塊。 
“source/plugin:myplugin” # Prefer not to do these. 
“../net:url_request” 
書寫時,可以省略標識的第二部分、第三部分,即冒號和名稱,這時名稱默認使用目錄的最後一段。標準上說,在這種情況建議省略第二、三部分。(以下的“=”表示等同) 
“//net” = “//net:net” 
“//tools/gn” = “//tools/gn:gn”

4.構建配置

4.1總體構建流程

在當前目錄查找.gn文件,如果不存在則向上一級目錄查找直到找到一個。將這個目錄設爲”souce root”, 解析該目錄下的gn文件以獲取build confing文件名稱。 
執行build config文件(這是一個默認工具鏈),在chromium中是//build/config/BUILDCONFIG.gn; 
加載root目錄下的BUILD.gn文件; 
根據root目錄下的BUILD.gn內容加載其依賴的其它目錄下的BUILD.gn文件,如果在指定位置找不到一個gn文件,GN將查找 build/secondary 的相應位置; 
當一個目標的依賴都解決了,編譯出.ninja文件保存到out_dir/dir,例如./out/arm/obj/ui/web_dialogs/web_dialogs.ninja; 
當所有的目標都解決了, 編譯出一個根 build.ninja 文件存放在out_dir根目錄下。

4.2構建配置文件

第一個要執行的是構建配置文件,它在指示源碼庫根目錄的“.gn”文件中指定。Chrome源碼樹中該文件是“//build/config/BUILDCONFIG.gn”。整個系統有且只有一個構造配置文件。 
除設置其它build文件執行時的工作域外,該文件還設置參數、變量、默認值,等等。設置在該文件的值對所有build文件可見。 
每個工具鏈會執行一次該文件(見“工具鏈”)。

4.3構建參數

參數可以從命令行(和其他工具鏈,參見下面的“工具鏈”)傳入。 你可以通過declare_args聲明接受哪些參數和指定默認值。 
有關參數是如何工作的,請參閱gn help buildargs。 有關聲明它們的細節,請參閱gn help declare_args。 
在給定作用域內多次聲明給定的參數是一個錯誤。 通常,參數將在導入文件中聲明(在構建的某些子集之間共享它們)或在主構建配置文件中(使它們是全局的)。

4.4默認目標

您可以爲給定的目標類型設置一些默認值。 這通常在構建配置文件中完成,以設置一個默認配置列表,它定義每個目標類型的構建標誌和其他設置信息。 
請參閱gn help set_defaults。 
例如,當您聲明static_library時,將應用靜態庫的目標默認值。 這些值可以由目標覆蓋,修改或保留。

# This call is typically in the build config file (see above).
set_defaults("static_library") {
  configs = [ "//build:rtti_setup", "//build:extra_warnings" ]
}

# This would be in your directory's BUILD.gn file.
static_library("mylib") {
  # At this point configs is set to [ "//build:rtti_setup", "//build:extra_warnings" ]
  # by default but may be modified.
  configs -= "//build:extra_warnings"  # Don't want these warnings.
  configs += ":mylib_config"  # Add some more configs.
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

用於設置目標默認值的其他用例是,當您通過模板定義自己的目標類型並想要指定某些默認值。

5.目標

目標是構造表中的一個節點,通常用於表示某個要產生的可執行或庫文件。目標經常會依賴其它目標,以下是內置的目標類型(參考gn help ): 
action:運行一個腳本來生成一個文件。 
action_foreach:循環運行腳本依次產生文件。 
bundle_data:產生要加入Mac/iOS包的數據。 
create_bundle:產生Mac/iOS包。 
executable:生成一個可執行文件。 
group:包含一個或多個目標的虛擬節點(目標)。 
shared_library:一個.dll或的.so。 
loadable_module:一個只用於運行時的.dll或.so。 
source_set:一個輕量的虛擬靜態庫(通常指向一個真實靜態庫)。 
static_library:一個的.lib或某文件(正常情況下你會想要一個source_set代替)。 
你可以用模板(templates)來擴展可使用的目標。Chrome就定義了以下類型。 
component:基於構造類型,或是源文件集合或是共享庫。 
test:可執行測試。在移動平臺,它用於創建測試原生app。 
app:可執行程序或Mac/iOS應用。 
android_apk:生成一個APK。有許多Android應用,參考//build/config/android/rules.gni。

6. CONFIGS

配置是指定標誌集,包含目錄和定義的命名對象。 它們可以應用於目標並推送到依賴目標。

config("myconfig") {
  includes = [ "src/include" ]
  defines = [ "ENABLE_DOOM_MELON" ]
}
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

將配置應用於目標:

executable("doom_melon") {
  configs = [ ":myconfig" ]
}
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

build config文件通常指定設置默認配置列表的目標默認值。 根據需要,目標可以添加或刪除到此列表。 所以在實踐中,你通常使用configs + =“:myconfig”附加到默認列表。 
有關如何聲明和應用配置的更多信息,請參閱gn help config。 
公共CONFIGS 
目標可以將設置應用於依賴它的目標。 最常見的例子是第三方目標,它需要一些定義或包含目錄來使其頭文件正確include。 希望這些設置適用於第三方庫本身,以及使用該庫的所有目標。 
爲此,我們需要爲要應用的設置編寫config:

config("my_external_library_config") {
  includes = "."
  defines = [ "DISABLE_JANK" ]
}
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

然後將這個配置被添加到public_configs。 它將應用於該目標以及直接依賴該目標的目標。

shared_library("my_external_library") {
  ...
  # Targets that depend on this get this config applied.
  public_configs = [ ":my_external_library_config" ]
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

依賴目標可以通過將你的目標作爲“公共”依賴來將該依賴樹轉發到另一個級別。

static_library("intermediate_library") {
  ...
  # Targets that depend on this one also get the configs from "my external library".
  public_deps = [ ":my_external_library" ]
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

目標可以將配置轉發到所有依賴項,直到達到鏈接邊界,將其設置爲all_dependent_config。 但建議不要這樣做,因爲它可以噴塗標誌和定義超過必要的更多的構建。 相反,使用public_deps控制哪些標誌適用於哪裏。 
在Chrome中,更喜歡使用構建標誌頭系統(build/buildflag_header.gni)來防止編譯器定義導致的大多數編譯錯誤。

7.工具鏈

Toolchains 是一組構建命令來運行不同類型的輸入文件和鏈接的任務。 
可以設置有多個 Toolchains 的 build。 不過最簡單的方法是每個 toolchains 分開 build同時在他們之間加上依賴關係。 這意味着,例如,32 位 Windows 建立可能取決於一個 64 位助手的 target。 他們每個可以依賴“//base:base”將 32 位基礎背景下的 32 位工具鏈,和 64 位背景下的 64 位工具鏈。 
當 target 指定依賴於另一個 target,當前的 toolchains 是繼承的,除非它是明確覆蓋(請參見上面的“Labels”)。

7.1工具鏈和構建配置

當你有一個簡單的版本只有一個 toolchain,build config 文件是在構建之初只加載一次。它必須調用 set_default_toolchain 告訴 GN toolchain 定義的 label 標籤。 此 toolchain 定義了需要用的編譯器和連接器的命令。 toolchain 定義的 toolchain_args 被忽略。當 target 對使用不同的 toolchain target 的依賴, GN 將使用輔助工具鏈來解決目標開始構建。 GN 將加載與工具鏈定義中指定的參數生成配置文件。 由於工具鏈已經知道, 調用 set_default_toolchain 將被忽略。所以 oolchain configuration 結構是雙向的。 在默認的 toolchain(即主要的構建 target)的配置從構建配置文件的工具鏈流向: 構建配置文件着眼於構建(操作系統類型, CPU 架構等)的狀態, 並決定使用哪些 toolchain(通過 set_default_toolchin)。 在二次 toolchain,配置從 toolchain 流向構建配置文件:在 toolchain 定義 toolchain_args 指定的參數重新調用構建。

7.2工具鏈例子

假設默認的構建是一個 64 位版本。 無論這是根據當前系統默認的 CPU 架構, 或者用戶在命令行上傳遞 target_cpu=“64”。 build config file 應該像這樣設置默認的工具鏈:

# Set default toolchain only has an effect when run in the context of
# the default toolchain. Pick the right one according to the current CPU
# architecture.
if (target_cpu == "x64") {
  set_default_toolchain("//toolchains:64")
} else if (target_cpu == "x86") {
  set_default_toolchain("//toolchains:32")
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

如果一個 64 位的 target 要依靠一個 32 位二進制數, 它會使用 data_deps 指定的依賴關係(data_deps 依賴庫在運行時才需要鏈接時不需要, 因爲你不能直接鏈接 32 位和 64位的庫)。

executable("my_program") {
  ...
  if (target_cpu == "x64") {
    # The 64-bit build needs this 32-bit helper.
    data_deps = [ ":helper(//toolchains:32)" ]
  }
}

if (target_cpu == "x86") {
  # Our helper library is only compiled in 32-bits.
  shared_library("helper") {
    ...
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

上述(引用的工具鏈文件toolchains/BUILD.gn)將定義兩個工具鏈:

toolchain("32") {
  tool("cc") {
    ...
  }
  ... more tools ...

  # Arguments to the build when re-invoking as a secondary toolchain.
  toolchain_args = {
    current_cpu = "x86"
  }
}

toolchain("64") {
  tool("cc") {
    ...
  }
  ... more tools ...

  # Arguments to the build when re-invoking as a secondary toolchain.
  toolchain_args = {
    current_cpu = "x64"
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

工具鏈args明確指定CPU體系結構,因此如果目標依賴於使用該工具鏈的東西,那麼在重新調用該生成時,將設置該cpu體系結構。 這些參數被忽略爲默認工具鏈,因爲當他們知道的時候,構建配置已經運行。 通常,工具鏈args和用於設置默認工具鏈的條件應該一致。 
有關多版本設置的好處是, 你可以寫你的目標條件語句來引用當前 toolchain 的狀態。構建文件將根據每個 toolchain 不同的狀態重新運行。 對於上面的例子 my_program, 你可以看到它查詢 CPU 架構, 加入了只依賴該程序的 64 位版本。 32 位版本便不會得到這種依賴性。

7.3聲明工具鏈

工具鏈均使用 toolchain 的命令聲明, 它的命令用於每個編譯和鏈接操作。 該toolchain 在執行時還指定一組參數傳遞到 build config 文件。 這使您可以配置信息傳遞給備用 toolchain。

8.模板

模板是 GN 重複使用代碼的主要方式。 通常, 模板會擴展到一個或多個其他目標類型。

# Declares a script that compiles IDL files to source, and then compiles those
# source files.
template("idl") {
  # Always base helper targets on target_name so they're unique. Target name
  # will be the string passed as the name when the template is invoked.
  idl_target_name = "${target_name}_generate"
  action_foreach(idl_target_name) {
    ...
  }

  # Your template should always define a target with the name target_name.
  # When other targets depend on your template invocation, this will be the
  # destination of that dependency.
  source_set(target_name) {
    ...
    deps = [ ":$idl_target_name" ]  # Require the sources to be compiled.
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

通常情況下你的模板定義在一個.gni 文件中, 用戶 import 該文件看到模板的定義:

import("//tools/idl_compiler.gni")

idl("my_interfaces") {
  sources = [ "a.idl", "b.idl" ]
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

聲明模板會在當時在範圍內的變量周圍創建一個閉包。 當調用模板時,魔術變量調用器用於從調用作用域讀取變量。 模板通常將其感興趣的值複製到其自己的範圍中:

template("idl") {
  source_set(target_name) {
    sources = invoker.sources
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

模板執行時的當前目錄將是調用構建文件的目錄,而不是模板源文件。 這是從模板調用器傳遞的文件將是正確的(這通常說明大多數文件處理模板)。 但是,如果模板本身有文件(也許它生成一個運行腳本的動作),你將需要使用絕對路徑(“// foo / …”)來引用這些文件, 當前目錄在調用期間將不可預測。 有關更多信息和更完整的示例,請參閱gn幫助模板。

9.其他功能

9.1 Imports

您可以 import .gni 文件到當前文件中。 這不是 C++中的 include。 Import 的文件將獨立執行並將執行的結果複製到當前文件中(C ++執行的時候, 當遇到 include 指令時纔會在當前環境中 include 文件)。 Import 允許導入的結果被緩存, 並且還防止了一些“creative”的用途包括像嵌套 include 文件。通常一個.gni 文件將定義 build 的參數和模板。 命令 gn help import 查看更多信息。.gni 文件可以定義像_this 名字前使用一個下劃線的臨時變量, 從而它不會被傳出文件外。。

9.2 路徑處理

通常你想使一個文件名或文件列表名相對於不同的目錄。 這在運行 scripts 時特別常見的, 當構建輸出目錄爲當前目錄執行的時候, 構建文件通常是指相對於包含他們的目錄的文件。您可以使用 rebase_path 轉化目錄。命令 gn help rebase_path 查看纖細信息。

9.3 模式

Patterns 被用來在一個部分表示一個或多個標籤。

命令: gn help set_sources_assignment_filter 
       gn help label_pattern 查看更多信息。
  • 1
  • 2
  • 1
  • 2

9.4 執行腳本

有兩種方式來執行腳本。 GN中的所有外部腳本都在Python中。第一種方式是構建步驟。這樣的腳本將需要一些輸入並生成一些輸出作爲構建的一部分。調用腳本的目標使用“action”目標類型聲明(請參閱gn help action)。 
在構建文件執行期間,執行腳本的第二種方式是同步的。在某些情況下,這是必要的,以確定要編譯的文件集,或者獲取構建文件可能依賴的某些系統配置。構建文件可以讀取腳本的stdout並以不同的方式對其執行操作。 
同步腳本執行由exec_script函數完成(有關詳細信息和示例,請參閱gn help exec_script)。因爲同步執行腳本需要暫停當前的buildfile執行,直到Python進程完成執行,所以依賴外部腳本很慢,應該最小化。 
爲了防止濫用,允許調用exec_script的文件可以在toplevel .gn文件中列入白名單。 Chrome會執行此操作,需要對此類添加進行其他代碼審覈。請參閱gn help dotfile。 
您可以同步讀取和寫入在同步運行腳本時不鼓勵但偶爾需要的文件。典型的用例是傳遞比當前平臺的命令行限制更長的文件名列表。有關如何讀取和寫入文件,請參閱gn help read_file和gn help write_file。如果可能,應避免這些功能。 
超過命令行長度限制的操作可以使用響應文件來解決此限制,而不同步寫入文件。請參閱gn help response_file_contents。

10.與Blaze的區別和相似之處

Blaze是Google的內部構建系統,現在作爲Bazel公開發布。它啓發了許多其他系統,如Pants和buck。 
在Google的同類環境中,對條件的需求非常低,他們可以通過一些hacks(abi_deps)來實現。 Chrome在所有地方使用條件,需要添加這些是文件看起來不同的主要原因。 
GN還添加了“configs”的概念來管理一些棘手的依賴和配置問題,這些問題同樣不會出現在服務器上。 Blaze有一個“配置”的概念,它像GN工具鏈,但內置到工具本身。工具鏈在GN中的工作方式是嘗試將這個概念以乾淨的方式分離到構建文件中的結果。 
GN保持一些GYP概念像“所有依賴”設置,在Blaze中工作方式有點不同。這部分地使得從現有GYP代碼的轉換更容易,並且GYP構造通常提供更細粒度的控制(其取決於情況是好還是壞)。 
GN也使用像“sources”而不是“srcs”的GYP名稱,因爲縮寫這似乎不必要地模糊,雖然它使用Blaze的“deps”,因爲“dependencies”很難鍵入。 Chromium還在一個目標中編譯多種語言,因此指定了目標名稱前綴的語言類型(例如從cc_library)。

https://chromium.googlesource.com/chromium/src/+/master/tools/gn/docs/language.md


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章