GN 快速入門指南
執行 GN
你可以在命令列裡直接輸入gn
執行。因為在depot_tools
(路徑應該在你的環境變數PATH中已經設定過)工具目錄中有一個相同名字的指令碼。這個指令碼會找到當前目錄中的二進位制檔案並執行它。
構建一個build
使用GYP時,系統會根據相應的配置引數分別生成Debug
和Release
編譯目錄。但GN不一樣,你可以任意配置你的編譯引數和生成目錄。編譯時如果檢測到Ninja檔案需要更新時,也會自動重新生成。
新生成一個編譯目錄:
gn gen out/my_build
傳入編譯引數
設定編譯目錄的編譯引數:
gn args out/my_build
然後,會彈出一個文字編輯器,像下面這樣輸入編譯引數:
is_component_build = true
is_debug = false
檢視所有的引數變數以及他們的預設值:
gn args --list out/my_build
這個命令必須指定編譯目錄,因為不同的目錄有不同的引數值。
Chrome 開發者還可以參考Chrome-specific build configuration的指示獲取更多資訊。
交叉編譯配置(Cross-compiling to a target OS or architecture)
執行gn args out/Default
target_os = "chromeos"
target_os = "android"
target_cpu = "arm"
target_cpu = "x86"
target_cpu = "x64"
更多資訊請參考GNCrossCompiles。
goma 配置
執行gn args out/Default
(用你需要的目錄替換)。並新增:
use_goma = true
goma_dir = "~/foo/bar/goma"
如果你的 goma 安裝在預設路徑(~/goma
),可以忽略goma_dir
引數。
配置 component 模式
執行gn args out/Default
並新增:
is_component_build = true
分步詳解
增加一個編譯檔案(BUILD.gn)
建立檔案tools/gn/tutorial/BUILD.gn
並輸入:
executable("hello_world") {
sources = [
"hello_world.cc",
]
}
在目標目錄中應該存在一個hello_world.cc
的檔案,包含你期望的內容。現在我們僅僅需要告訴編譯器需要處理這個編譯檔案就行了。開啟根目錄(src
)下的BUILD.gn
檔案,將新建立的編譯檔案新增到其中一個根group的依賴項中(這裡的每個group是其它目標的一個集合):
group("root") {
deps = [
...
"//url",
"//tools/gn/tutorial:hello_world",
]
}
你可以看到你的目標檔案標籤的前面有一個”//”符號(表示原始碼的根目錄,也就是src
目錄),後面緊跟具體路徑,再接一個冒號,最後就是你的專案的目標名稱。
測試你新增的工程
在原始碼根目錄中,使用命令列操作:
gn gen out/Default
ninja -C out/Default hello_world
out/Default/hello_world
GN 鼓勵對靜態庫使用相同的名字。編譯其中的某個時,你可以將不帶字首”//”的標籤文字傳給 ninja:
ninja -C out/Default tools/gn/tutorial:hello_world
宣告依賴
現在來構建一個靜態庫,它有一個函式,功能是對任何人說hello
。這些都包含在一個hello.cc
的檔案中。開啟tools/gn/tutorial/BUILD.gn
,將下面的配置靜態庫的文字新增到檔案的最下面:
static_library("hello") {
sources = [
"hello.cc",
]
}
我再新增一個可執行檔案的工程,依賴上面的靜態庫:
executable("say_hello") {
sources = [
"say_hello.cc",
]
deps = [
":hello",
]
}
這個exe
的工程包含一個原始檔並且依賴上面的lib
工程。lib
是通過exe
中的deps
依賴項來引入的。你也可以使用全路徑文字//tools/gn/tutorial:hello
,但是如果你引入的工程是在同一個build檔案中,你可以使用縮寫:hello
。
測試靜態庫
在原始碼根目錄中輸入:
ninja -C out/Default say_hello
out/Default/say_hello
你不需要再次執行 GN 命令了。當BUILD.gn檔案改變的時候 GN會自動重新生成 ninja 檔案。你知道的,這通常發生在 ninja 剛執行時,它會打印出[1/1] Regenerating ninja files
。
預編譯設定(Compiler settings)
我們的 hello lib
工程有一個新功能,就是可以同時對兩個人說 hello。這個功能是通過巨集定義TWO_PEOPLE
來控制的。我們可以在工程中這樣新增:
static_library("hello") {
sources = [
"hello.cc",
]
defines = [
"TWO_PEOPLE",
]
}
將一些設定放到config
中(Putting settings in a config)
然而,使用lib
的工程也需要知道這個預定義,將定義放到lib
工程中,僅僅對這個工程中的檔案生效。如果別的工程包含了hello.h
,他們是看不到這個定義的。如果要看到這個定義,每個引入這個lib
的工程都必須定義TWO_PEOPLE
。
GN 有一個”config”的概念,可以將一些設定放在裡面。現在我們來建立一個”config”並將我們需要的預定義巨集放到裡面:
config("hello_config") {
defines = [
"TWO_PEOPLE",
]
}
如何在目標工程中引入這些設定,你只需要在目標的configs
選項中將需要的配置羅列出來即可:
static_library("hello") {
...
configs += [
":hello_config",
]
}
這個地方你需要使用+=
,而不是=
,因為每個目標工程構建編譯的都有一系列的預設配置。你要做是將新的配置新增到預設的配置中,而不是全部重寫它。如果需要檢視預設的配置,你可以在編譯檔案(BUILD.gn)中使用print
函式或者desc
命令列子命令(下面的例子都會介紹)。
依賴配置項(Dependent configs)
上面介紹的方法可以很好的封裝我們的配置,但是它仍然需要每個使用lib
的工程在他們自己的配置裡去設定。如果每個使用lib
的工程可以自動獲取這些配置,那該有多好。現在來改變以下lib
的配置:
static_library("hello") {
sources = [
"hello.cc",
]
all_dependent_configs = [
":hello_config"
]
}
這會將hello_config
的配置應用到hello
工程本身,以及所有依賴(所有繼承,包含間接依賴)hello
的工程。現在每個依賴我們的lib
的工程都會獲取這些配置。你也可以設定public_configs
來設定只應用到直接依賴的目標專案中(不傳遞)。
現在,如果你編譯並執行的話,你將會看到兩個人的新版本:
> ninja -C out/Default say_hello
ninja: Entering directory 'out/Default'
[1/1] Regenerating ninja files
[4/4] LINK say_hello
> out/Default/say_hello
Hello, Bill and Joy.
新增一個新的編譯引數
你可以通過declare_args
直接宣告你接受的引數並指定它們的預設值。
declare_args() {
enable_teleporter = true
enable_doom_melon = false
}
使用gn help buildargs
來獲取它們工作原理的概述。使用gn help declare_args
獲取宣告引數的細節。
It is an error to declare a given argument more than once in a given scope, so care should be used in scoping and naming arguments.
不知道發生了什麼?(Don‘t know what’s going on?)
你可以執行 GN 的 verbose 模式,會看到很多關於當前發生的資訊。使用-v
啟用。
列印除錯資訊
有一個print
的命令,可以輸出到 stdout:
static_library("hello") {
...
print(configs)
}
這會打印出應用到目標專案的所有配置資訊(包括預設的)。
“desc”命令
你可以執行gn desc <build_dir> <targetname>
獲取指定目標的資訊。
gn desc out/Default //tools/gn/tutorial:say_hello
這會打印出很多我們想要的資訊。你也可以只打印一項。現在來告訴你,如何知道目標工程say_hello
中的TWO_PEOPLE
巨集定義在什麼地方:
> gn desc out/Default //tools/gn/tutorial:say_hello defines --blame
...lots of other stuff omitted...
From //tools/gn/tutorial:hello_config
(Added by //tools/gn/tutorial/BUILD.gn:12)
TWO_PEOPLE
你可以看見TWO_PEOPLE
是通過一個 config 來定義的,你也可以知道是哪行將config應用到目標工程的(在這裡,是all_dependent_configs
那行)。
兩外一個特別有趣的命令:
gn desc out/Default //base:base_i18n deps --tree
參考gn help desc
獲取詳情。
效能(Performance)
You can see what took a long time by running it with the –time command line flag. This will output a summary of timings for various things.
You can also make a trace of how the build files were executed:
gn --tracelog=mylog.trace
and you can load the resulting file in Chrome’s about:tracing page to look at everything.