1. 程式人生 > >GN 快速入門指南

GN 快速入門指南

GN Quick Start guide

執行 GN

你可以在命令列裡直接輸入gn執行。因為在depot_tools(路徑應該在你的環境變數PATH中已經設定過)工具目錄中有一個相同名字的指令碼。這個指令碼會找到當前目錄中的二進位制檔案並執行它。

構建一個build

使用GYP時,系統會根據相應的配置引數分別生成DebugRelease編譯目錄。但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.