[翻译转载] 快速上手GN
GN Quick Start guide
运行 GN
gn
是一个命令行工具. 对于大型项目, GN 会以特定版本集成在源码中.
- 对于 Chromium 及基于 Chromium 的项目来说, 会通过
depot_tools
脚本集成. 该脚本应在你的 PATH 中, GN 被该脚本代理成代码树中的真正二进制并运行. - 在 Fuchsia 开发环境中,
fx gn ...
会代理正确的 GN 二进制并传递给它参数. - 对于其他项目, 需要查阅项目文档
设定构建
GN 不同于其他构建系统, 你需要设定带有你想要设置的构建文件夹, 这使得你可以同时维护多个不同类型的构建结果.
一旦你设定好构建文件夹, Ninja 文件在开始构建时会按需被自动的重新生成, 因此不需要每次构建都重新运行 GN.
创建构建文件夹的命令为:
gn gen out/my_build
传递构建命令
设置构建文件夹的参数:
gn args out/my_build
该命令会启动一个编辑器. 向文件中输入k-v类型的构建参数
is_component_build=true
is_debug = false
可用的参数取决于你构建的项目(例子中的参数来自 Chromium). 可以通过命令查看可用的参数和它们的默认值
gn args --list out/my_build
注意由于不同构建可能有不同参数, 需要指定构建文件夹
Chrome 开发者可以阅读 Chrome-specific build configuration 来获得更多信息
针对指定操作系统或架构交叉编译
运行 gn args out/Default
(替换成你的编译目录), 然后为常用的交叉编译选项提供如下参数
target_os = "chromeos"
target_os = "android"
target_cpu = "arm"
target_cpu = "x86"
target_cpu = "x64"
更多信息见 GN cross compiles.
简单例子
添加一个构建文件
跳转到 examples/simple_build
. 这是一个最小化 GN 仓库的根目录.
(PS: 该目录在 GN 源码仓库下 )
在该目录下有一个 tutorial
目录. 下有还没加入构建的 tutorial.cc
文件. 在该目录下创建一个新的 BUILD.gn
文件, 来为该文件生成新的可执行 target .
executable("tutorial") {
sources = [
"tutorial.cc"
]
}
现在我们需要加入该 target. 打开父目录(simple_build
)下的BUILD.gn
. GN从这个根文件进行加载, 之后加入该文件的所有依赖, 因此我们需要从该文件依赖新的 target.
你可以将新 target 作为依赖添加到simple_build/BUILD.gn
文件里现存的 target 上, 但通常将可执行 target 作为另一个可执行 target 的依赖是不合理的(它们不能被链接). 因此我们新建一个 “tools”组, 一个“组”表示一系列不被编译或链接的依赖.
group("tools") {
deps = [
# 这里也可以写全名 “://tutorial:tutorial”.
# 更多信息可见 “gn help labels”
"//tutorial",
]
}
测试添加后的效果
在 simple_build
目录运行:
gn gen out
ninja -C out tutorial
out/tutorial
"Hello, world" 应该正确输出在命令行中
注: GN 支持静态库的 target 名不全局唯一. 可以对 ninja 传递带有路径(不带“//”)的标签来构建:
ninja -C out some/path/to/target:my_target
声明依赖
在examples/simple_build/BUILD.gn定义的 target 中, 有一个被静态库定义的函数GetStaticText()
.
static_library("hello_static") {
sources = [
"hello_static.cc",
"hello_static.h",
]
}
共享库也定义了一个函数GetSharedText()
:
shared_library("hello_stared") {
sources = [
"hello_shared.cc",
"hello_shared.h",
]
defines = [ "HELLO_SHARED_IMPLEMENTATION" ]
}
这里展示了怎样在预处理器中为 target 添加 define. 如果需要多于一个的 define 或赋值 define , 参照如下形式:
defines = [
“HELLO_SHARED_IMPLEMENTATION",
"ENABLE_DOOM_MELON=0",
]
现在来看依赖这两个库的可执行文件
executable("hello") {
sources = [
"hello.cc",
]
deps = [
":hello_shared",
":hello_static",
]
}
测试二进制
在simple_build
目录运行:
ninja -C out hello
out/hello
注意你不需要重新运行 GN, 当构建文件变化时, GN 会自动重新构建 ninja 文件. 可以通过 ninja 在执行的开始时,在命令行中的输出 [1/1] Regenerating ninja files
来确认.
将设置放到 config 里
库的用户通常需要 complier flags , defines 和应用它们的 include 目录. “config” 命名的设定集合(没有源文件和依赖), 通过将这些设置放到 “config” 中来达到这个目的.
config("my_lib_config") {
defines = [ "ENABLE_DOOM_MELON" ]
include_dirs = [ "//third_party/something" ]
}
要把 config 加到 configs
列表里, 来使 config 中的设定在 target 中生效.
static_library("hello_shared") {
...
# 注 这里通常需要 "+=", 见下文的 "默认 configs”
configs += [
“:my_lib_config",
]
}
config 放在 public_configs
列表中则可在全部依赖它的 target 中生效.
static_library("hello_shared") {
...
public_configs = [
":my_lib_config",
]
}
public_configs
同样会在当前 target 生效, 因此不需要在两个列表中同时声明.
默认 configs
构建的配置会有一些默认应用到所有 target 的设置. 它们会被设置成 configs 的默认值. 你可以使用 “print” 命令来打印它们(该命令在 debug 中非常使用).
executable("hello") {
print(configs)
}
运行 GN 将打印一些类似的结果
$ gn gen out
["//build:compiler_defaults", "//build:executable_ldconfig"]
Done. Made 5 targets from 5 files in 9ms
target 可以修改这些默认值. 例如, 构建需要通过no_exceptions
config 关闭异常, 但 target 可能需要重新启用它们, 为此需要替换默认的 configs 列表.
executable("hello") {
...
configs -= [ "//build:no_exceptions" ] # Remove global default.
configs += [ "//build:exceptions" ] # Replace with a different one.
}
print 命令也支持字符串差值, 它通过“$“将变量名替换成字符串
print("The configs for the target $target_name are $configs")
添加一个新的构建参数
在 declare_args
函数中可以定义需要的参数和它的默认值.
declare_args() {
enable_teleporter = true
enable_doom_melon = false
}
查看gn help buildargs
来总览它是如何生效的, gn help declare_args
来查看声明它们的细节.
在一个作用域中重复定义参数是不允许的, 因此定义参数前需要考虑它的名字和作用域.
不知道发生了什么?
-v
使 GN 运行在详细模式, 会打印出更多的信息.
desc 命令
可以运行 gn desc <build_dir> <targetname>
来获取指定 target 的详细信息
gn desc out/Default //foo/bar:say_hello
会打印非常详细的信息. 你也可以只打印一部分, 假如你想要知道 say_hello
target 中的 TWO_PEOPLE
define 来源于哪里:
$ gn desc out/Default //foo/bar:say_hello defines --blame
...lots of other stuff omitted...
From //foo/bar:hello_config
(Added by //foo/bar/BUILD.gn:12)
TWO_PEOPLE
另一个有趣的变化:
gn desc out/Default //base:base_i18n deps --tree
更多信息见 gn help desc