gn 是一款構建系統,用於編譯大規模代碼生成ninja文件linux
!!! info "優勢"android
* 1.可讀性好
* 2.速度更快
* 3.修改gn 以後 構建ninja文件時候會自動更新
* 4.依賴分明
複製代碼
通過幾天的摸索發現這種構建系統很是有層次性,一般每一個模塊能夠單獨寫一個gn文件,可是通常採用層級結構 文件根目錄下一般有一個BUILD.gn文件,該文件是全部的代碼模塊組裝的集合web
.gni 文件:通常用來添加一些參數的配置,在gn文件中import這些文件或者裏面定義的變量參數值shell
本文描述了許多GN的語法細節和行爲。緩存
1.1 使用內置的幫助! GN具備普遍的內置幫助系統,爲每一個函數和內置變量提供參考。 這個頁面更高級。bash
GN help
複製代碼
您還能夠閱讀2016年3月的GN介紹的幻燈片。演講者備註包含完整內容。服務器
1.2 設計理念閉包
編寫構建文件不該該有太多的創造性的工做。理想狀況下,給定相同的要求,兩我的應該生成相同的構建文件。架構
除非確實須要,不然不該有靈活性。由於許多事情應該儘量做爲致命錯誤。app
定義應該更像代碼而不是規則。我不想寫或調試Prolog。可是咱們團隊中的每一個人均可以編寫和調試C ++和Python。 應該考慮構建語言應該如何工做。它不必去容易甚至是可能表達抽象事物。
咱們應該經過改變源碼或工具來使構建更加簡單,而不是使構建加以複雜來知足外部需求(在合理的範圍內)。 像Blaze,它何時是有意義的(見下文「與Blaze的區別和類似之處」)。
重要參數講解
group :一個擁有命名的目標集合,這個集合包含不少的依賴模塊 可配置項:
1.依賴的模塊 data_deps,deps,public_deps
配置參數 :all_dependent_configs,public_configs
根目錄的gn文件就是一個個的group組成,根據不一樣的條件添加或者減小模塊依賴,全部在根目錄的子目錄中建立的模塊想發揮做用須要在這個文件中進行添加依賴
config :定義一個配置對象 通俗的解釋,config就是構造一個模板,這個模板有各類各樣的屬性
source_set :須要被編譯的資源的一個集合,被編譯可是不產生任何的庫
static_library :生成靜態庫目標
target : 指定目標的類型並生成該目標
template: 定義一個函數名字,這個名字相似於一個函數
component : 定義一個組件至關於使用gn的component模板替代了靜態庫、動態庫或者sourceset,當容許使用這個(編譯參數 is_component_build 爲true的時候),模板會生成一個動態庫,不容許的話會生成一個動態庫,這個很複雜,詳情鍵component官方詳解
define :定義字符串,被傳遞給編譯器,功能相似於# defines
include_dirs :添加額外路徑文件
inputs : 添加當前編譯目標在編譯的時候須要的target
ldflags :傳遞給連接器的標誌 ,如今大部分能夠用libs和lib_dirs替代使用
lib_dirs :額外的庫路徑列表
GN使用了一個很是簡單的動態類型語言。的類型是:
有一些內置的變量,其值取決於當前的環境。參見gn help更多。 GN中有許多故意的遺漏。例如沒有用戶定義的函數調用(模板是最接近的了)。 根據上述設計理念,若是你須要這種東西,已經不符合其設計理念了。 變量sources有一個特殊的規則:當分配給它時,排除模式的列表會應用於它。 這是爲了自動過濾掉一些類型的文件。 有關更多信息,請參閱gn help set_sources_assignment_filter和gn help label_pattern。 書呆子似的GN的完整語法在gn help grammar中提供。
字符串用雙引號和反斜線使用做爲轉義字符。惟一支持的轉義序列是:
反斜槓的任何其餘用法被視爲字符反斜槓。 所以,例如在模式中使用的\b不須要轉義,Windows路徑,如「C\foo\bar.h」也不須要轉義。 經過支持簡單的變量替換,其中美圓符號後面的字替換爲變量的值。若是沒有非variable−name字符以終止變量名,可使用選擇性地包圍名稱。不支持更復雜的表達式,只支持變量名稱替換。
a=「mypath」b=「a/foo.cc」 # b -> 「mypath/foo.cc」
c = 「foo{a}bar.cc」 # c -> 「foomypathbar.cc」
複製代碼
你可使用「0xFF」語法編碼8位字符,因此帶有換行符(十六進制0A)的字符串以下:`「look0x0Alike0x0Athis」。
咱們是沒有辦法獲得列表的長度的。 若是你發現本身想作這樣的事情,那是你在構建中作了太多的工做。 列表支持附加:
a = [ "first" ]
a += [ "second" ] # [ "first", "second" ]
a += [ "third", "fourth" ] # [ "first", "second", "third", "fourth" ]
b = a + [ "fifth" ] # [ "first", "second", "third", "fourth", "fifth" ]
複製代碼
將列表附加到另外一個列表將項目附加在第二個列表中,而不是將列表附加爲嵌套成員。 您能夠從列表中刪除項目:
a = [ "first", "second", "third", "first" ]
b = a - [ "first" ] # [ "second", "third" ]
a -= [ "second" ] # [ "first", "third", "fourth" ]
複製代碼
列表中的 - 運算符搜索匹配項並刪除全部匹配的項。 從另外一個列表中減去列表將刪除第二個列表中的每一個項目。 若是沒有找到匹配的項目,將拋出一個錯誤,所以您須要提早知道該項目在那裏,而後再刪除它。 假定沒有辦法測試是否包含,主要用例是設置文件或標誌的主列表,並根據各類條件刪除不適用於當前構建的主列表。
在文體風格上,只喜歡添加到列表,並讓每一個源文件或依賴項出現一次。 這與Flutter Engine團隊爲GYP提供的建議(GYP更願意列出全部文件,而後刪除在條件語中不須要的文件)相反。 列表支持基於零的下標來提取值:
a = [ "first", "second", "third" ]
b = a[1] # -> "second"
複製代碼
[]運算符是隻讀的,不能用於改變列表。 主要用例是當外部腳本返回幾個已知值,而且要提取它們時。 在某些狀況下,當你想要附加到列表時,很容易覆蓋列表。 爲了幫助捕獲這種狀況,將非空列表賦給包含非空列表的變量是一個錯誤。若是要解決此限制,請先將空列表賦給目標變量。以下: a = [ 「one」 ] a = [ 「two」 ] # Error: overwriting nonempty list with a nonempty list. a = [] # OK a = [ 「two」 ] # OK 注意,構建腳本執行時並不理解潛在數據的含義。這意味着它並不知道sources是一個文件名的列表。例如,若是你想刪除其中一項,它必須字符串徹底匹配,而不是指定一個不帶後綴的名稱,它並不會解析爲相同的文件名。
條件表達式看起來像C:
if (is_linux || (is_win && target_cpu == "x86")) {
sources -= [ "something.cc" ]
} else if (...) {
...
} else {
...
}
複製代碼
若是目標只應在某些狀況下聲明,你就可使用條件語句,甚至是整個目標。
你能夠用foreach遍歷一個列表。 但不鼓勵這樣作。構建作的大多數事情應該均可以表達,而不是循環,若是你發現有必要使用循環,這可能說明你在構建中作了一些無用的工做。
foreach(i, mylist) {
print(i) # Note: i is a copy of each element, not a reference to it.
}
複製代碼
簡單的函數調用看起來像大多數其餘的語言: print(「hello, world」) assert(is_win, 「This should only be executed on Windows」) 這些功能是內置的,用戶不能定義新的功能。 一些函數接受一個由{}括起來的代碼塊:
static_library("mylibrary") {
sources = [ "a.cc" ]
}
複製代碼
其中大多數定義目標。 用戶可使用下面討論的模板機制來定義這樣的functions。 確切地說,這個表達式意味着該塊變成用於函數執行的函數的參數。 大多數塊風格函數執行塊並將結果做爲要讀取的變量的字典。
文件和函數調用後跟{}塊將引入新做用域。 做用域是嵌套的。 當你讀取變量時,將以相反的順序搜索包含的做用域,直到找到匹配的名稱。 變量寫入始終位於最內層。 沒有辦法修改除最內層以外的任何封閉做用域。 這意味着,當你定義一個目標,例如,你在塊裏面作的什麼都不會「泄漏」到文件的其他部分。 if/else/foreach語句,即便他們使用{},不會引入一個新的做用域,因此更改會影響到語句以外。
文件和目錄名稱是字符串,而且被解釋爲相對於當前構建文件的目錄。 有三種可能的形式: 相對名稱:
「foo.cc」
「SRC/foo.cc」
「../src/foo.cc」
複製代碼
Source-tree絕對名稱:
「//net/foo.cc」
「//base/test/foo.cc」
複製代碼
系統絕對名稱(不多,一般用於包含目錄):
"/usr/local/include/"
"/C:/Program Files/Windows Kits/Include"
複製代碼
標識是有着預約義格式的字符串,依賴圖中全部的元素(目標,配置和工具鏈)都由標識惟一識別。一般狀況下,標識看去是如下樣子。
「//base/test:test_support」 !!! info ""它由三部分組成"
* 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」
書寫時,能夠省略標識的第二部分、第三部分,即冒號和名稱,這時名稱默認使用目錄的最後一段。標準上說,在這種狀況建議省略第2、三部分。(如下的「=」表示等同)
「//net」 = 「//net:net」 「//tools/gn」 = 「//tools/gn:gn」
在當前目錄查找.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根目錄下。
第一個要執行的是構建配置文件,它在指示源碼庫根目錄的「.gn」文件中指定。Flutter Engine源碼樹中該文件是「//build/config/BUILDCONFIG.gn」。整個系統有且只有一個構造配置文件。 除設置其它build文件執行時的工做域外,該文件還設置參數、變量、默認值,等等。設置在該文件的值對全部build文件可見。 每一個工具鏈會執行一次該文件(見「工具鏈」)。
參數能夠從命令行(和其餘工具鏈,參見下面的「工具鏈」)傳入。 你能夠經過declare_args聲明接受哪些參數和指定默認值。 有關參數是如何工做的,請參閱gn help buildargs。 有關聲明它們的細節,請參閱gn help declare_args。 在給定做用域內屢次聲明給定的參數是一個錯誤。 一般,參數將在導入文件中聲明(在構建的某些子集之間共享它們)或在主構建配置文件中(使它們是全局的)。
您能夠爲給定的目標類型設置一些默認值。 這一般在構建配置文件中完成,以設置一個默認配置列表,它定義每一個目標類型的構建標誌和其餘設置信息。 請參閱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.
}
複製代碼
用於設置目標默認值的其餘用例是,當您經過模板定義本身的目標類型並想要指定某些默認值。
目標是構造表中的一個節點,一般用於表示某個要產生的可執行或庫文件。目標常常會依賴其它目標,如下是內置的目標類型(參考gn help ):
!!! info "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)來擴展可以使用的目標。Flutter Engine就定義瞭如下類型。
* component:基於構造類型,或是源文件集合或是共享庫。
* test:可執行測試。在移動平臺,它用於建立測試原生app。
* app:可執行程序或Mac/iOS應用。
* android_apk:生成一個APK。有許多Android應用,參考//build/config/android/rules.gni。
複製代碼
配置是指定標誌集,包含目錄和定義的命名對象。 它們能夠應用於目標並推送到依賴目標。
config("myconfig") {
includes = [ "src/include" ]
defines = [ "ENABLE_DOOM_MELON" ]
}
複製代碼
將配置應用於目標:
executable("doom_melon") {
configs = [ ":myconfig" ]
}
複製代碼
build config文件一般指定設置默認配置列表的目標默認值。 根據須要,目標能夠添加或刪除到此列表。 因此在實踐中,你一般使用configs + =「:myconfig」附加到默認列表。 有關如何聲明和應用配置的更多信息,請參閱gn help config。 公共CONFIGS 目標能夠將設置應用於依賴它的目標。 最多見的例子是第三方目標,它須要一些定義或包含目錄來使其頭文件正確include。 但願這些設置適用於第三方庫自己,以及使用該庫的全部目標。 爲此,咱們須要爲要應用的設置編寫config:
config("my_external_library_config") {
includes = "."
defines = [ "DISABLE_JANK" ]
}
複製代碼
而後將這個配置被添加到public_configs。 它將應用於該目標以及直接依賴該目標的目標。
shared_library("my_external_library") {
...
# Targets that depend on this get this config applied.
public_configs = [ ":my_external_library_config" ]
}
複製代碼
依賴目標能夠經過將你的目標做爲「公共」依賴來將該依賴樹轉發到另外一個級別。
static_library("intermediate_library") {
...
# Targets that depend on this one also get the configs from "my external library".
public_deps = [ ":my_external_library" ]
}
複製代碼
目標能夠將配置轉發到全部依賴項,直到達到連接邊界,將其設置爲all_dependent_config。 但建議不要這樣作,由於它能夠噴塗標誌和定義超過必要的更多的構建。 相反,使用public_deps控制哪些標誌適用於哪裏。 在Flutter Engine中,更喜歡使用構建標誌頭系統(build/buildflag_header.gni)來防止編譯器定義致使的大多數編譯錯誤。
Toolchains 是一組構建命令來運行不一樣類型的輸入文件和連接的任務。 能夠設置有多個 Toolchains 的 build。 不過最簡單的方法是每一個 toolchains 分開 build同時在他們之間加上依賴關係。 這意味着,例如,32 位 Windows 創建可能取決於一個 64 位助手的 target。 他們每一個能夠依賴「//base:base」將 32 位基礎背景下的 32 位工具鏈,和 64 位背景下的 64 位工具鏈。 當 target 指定依賴於另外一個 target,當前的 toolchains 是繼承的,除非它是明確覆蓋(請參見上面的「Labels」)。
當你有一個簡單的版本只有一個 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 指定的參數從新調用構建。
假設默認的構建是一個 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")
}
複製代碼
若是一個 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") {
...
}
}
上述(引用的工具鏈文件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"
}
複製代碼
工具鏈args明確指定CPU體系結構,所以若是目標依賴於使用該工具鏈的東西,那麼在從新調用該生成時,將設置該cpu體系結構。 這些參數被忽略爲默認工具鏈,由於當他們知道的時候,構建配置已經運行。 一般,工具鏈args和用於設置默認工具鏈的條件應該一致。 有關多版本設置的好處是, 你能夠寫你的目標條件語句來引用當前 toolchain 的狀態。構建文件將根據每一個 toolchain 不一樣的狀態從新運行。 對於上面的例子 my_program, 你能夠看到它查詢 CPU 架構, 加入了只依賴該程序的 64 位版本。 32 位版本便不會獲得這種依賴性。
工具鏈均使用 toolchain 的命令聲明, 它的命令用於每一個編譯和連接操做。 該toolchain 在執行時還指定一組參數傳遞到 build config 文件。 這使您能夠配置信息傳遞給備用 toolchain。
模板是 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.
}
}
複製代碼
一般狀況下你的模板定義在一個.gni 文件中, 用戶 import 該文件看到模板的定義:
import("//tools/idl_compiler.gni")
idl("my_interfaces") {
sources = [ "a.idl", "b.idl" ]
}
複製代碼
聲明模板會在當時在範圍內的變量周圍建立一個閉包。 當調用模板時,魔術變量調用器用於從調用做用域讀取變量。 模板一般將其感興趣的值複製到其本身的範圍中:
template("idl") {
source_set(target_name) {
sources = invoker.sources
}
}
複製代碼
模板執行時的當前目錄將是調用構建文件的目錄,而不是模板源文件。 這是從模板調用器傳遞的文件將是正確的(這一般說明大多數文件處理模板)。 可是,若是模板自己有文件(也許它生成一個運行腳本的動做),你將須要使用絕對路徑(「// foo / …」)來引用這些文件, 當前目錄在調用期間將不可預測。 有關更多信息和更完整的示例,請參閱gn幫助模板。
您能夠 import .gni 文件到當前文件中。 這不是 C++中的 include。 Import 的文件將獨立執行並將執行的結果複製到當前文件中(C ++執行的時候, 當遇到 include 指令時纔會在當前環境中 include 文件)。 Import 容許導入的結果被緩存, 而且還防止了一些「creative」的用途包括像嵌套 include 文件。一般一個.gni 文件將定義 build 的參數和模板。 命令 gn help import 查看更多信息。.gni 文件能夠定義像_this 名字前使用一個下劃線的臨時變量, 從而它不會被傳出文件外。。
一般你想使一個文件名或文件列表名相對於不一樣的目錄。 這在運行 scripts 時特別常見的, 當構建輸出目錄爲當前目錄執行的時候, 構建文件一般是指相對於包含他們的目錄的文件。您可使用 rebase_path 轉化目錄。命令 gn help rebase_path 查看纖細信息。
Patterns 被用來在一個部分表示一個或多個標籤。
命令: gn help set_sources_assignment_filter gn help label_pattern 查看更多信息。
有兩種方式來執行腳本。 GN中的全部外部腳本都在Python中。第一種方式是構建步驟。這樣的腳本將須要一些輸入並生成一些輸出做爲構建的一部分。調用腳本的目標使用「action」目標類型聲明(請參閱gn help action)。 在構建文件執行期間,執行腳本的第二種方式是同步的。在某些狀況下,這是必要的,以肯定要編譯的文件集,或者獲取構建文件可能依賴的某些系統配置。構建文件能夠讀取腳本的stdout並以不一樣的方式對其執行操做。 同步腳本執行由exec_script函數完成(有關詳細信息和示例,請參閱gn help exec_script)。由於同步執行腳本須要暫停當前的buildfile執行,直到Python進程完成執行,因此依賴外部腳本很慢,應該最小化。 爲了防止濫用,容許調用exec_script的文件能夠在toplevel .gn文件中列入白名單。 Flutter Engine會執行此操做,須要對此類添加進行其餘代碼審覈。請參閱gn help dotfile。 您能夠同步讀取和寫入在同步運行腳本時不鼓勵但偶爾須要的文件。典型的用例是傳遞比當前平臺的命令行限制更長的文件名列表。有關如何讀取和寫入文件,請參閱gn help read_file和gn help write_file。若是可能,應避免這些功能。 超過命令行長度限制的操做可使用響應文件來解決此限制,而不一樣步寫入文件。請參閱gn help response_file_contents。
Blaze是Google的內部構建系統,如今做爲Bazel公開發布。它啓發了許多其餘系統,如Pants和buck。 在Google的同類環境中,對條件的需求很是低,他們能夠經過一些hacks(abi_deps)來實現。 Flutter Engine在全部地方使用條件,須要添加這些是文件看起來不一樣的主要緣由。 GN還添加了「configs」的概念來管理一些棘手的依賴和配置問題,這些問題一樣不會出如今服務器上。 Blaze有一個「配置」的概念,它像GN工具鏈,但內置到工具自己。工具鏈在GN中的工做方式是嘗試將這個概念以乾淨的方式分離到構建文件中的結果。 GN保持一些GYP概念像「全部依賴」設置,在Blaze中工做方式有點不一樣。這部分地使得從現有GYP代碼的轉換更容易,而且GYP構造一般提供更細粒度的控制(其取決於狀況是好仍是壞)。 GN也使用像「sources」而不是「srcs」的GYP名稱,由於縮寫這彷佛沒必要要地模糊,雖然它使用Blaze的「deps」,由於「dependencies」很難鍵入。 Chromium還在一個目標中編譯多種語言,所以指定了目標名稱前綴的語言類型(例如從cc_library)。
GN構建系統是一個組織源代碼的依賴關係,而且可以配置編譯不一樣產物的參數,GN構建系統使用的是一個順藤摸瓜
的方式從源碼root
目錄的.gn
文件開發,不斷讀取相關關聯的文件,目的是爲下一步的編譯構建好,編譯文件依賴和相關的參數配置,下一步纔是正在的編譯工做,Ninja
工具在構建的時候只會更加GN
生成的配置文件進行源代碼查找編譯,下一篇中咱們見介紹相關的Ninja
腳本文件