[翻译转载] 快速上手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

posted @ 2021-08-01 19:14  新新人類  阅读(1181)  评论(1编辑  收藏  举报