运行GN(Generate Ninja)
运行gn
,你只需从命令行运行gn
,对于大型项目,GN是与源码一起的。
- 对于Chromium和基于Chromium的项目,有一个在
depot_tools
中的脚本,它需要加入到你的PATH环境变量中。该脚本将在包含当前目录的源码树中找到二进制文件并运行它。 - 对于Fuchsia树内开发,运行
fx gn ...
,它将找到正确的GN二进制文件,并使用给定的参数运行它。
设置一个构建
与其他一些构建系统不同,在GN中你可以设置你自己的构建目录,和你想要的设置。这让你可以根据需要维护不同的构建,可以根据自己的需要并行维护不同的构建。
一旦你生成了一个构建目录,ninja
文件将被自动生成,如果你在该目录下进行构建时,文件已经过期,ninja
则会自动重新生成,所以你不必重新运行gn
。
建立一个构建目录:
gn gen out/my_build
配置构建参数
在你的构建目录上运行设置构建参数:
gn args out/my_build
这将弹出一个编辑器,在该文件中输入build args,像这样:
is_component_build = true
is_debug = false
可用的变量将取决于你的构建,你可以看到可用参数的列表和它们的默认值。
通过键入:
gn args --list out/my_build
可以看到可用的参数列表和默认值,这个命令必须指定编译目录,因为不同的目录有不同的参数值。
Chrome的开发者也可以阅读Chrome特有的构建配置说明以了解更多信息。
交叉编译至目标操作系统或架构
运行 gn args out/Default
(根据需要替换成你的构建目录),然后为常见的交叉编译选项添加以下一行或多行:
target_os = "chromeos"
target_os = "android"target_cpu = "arm"
target_cpu = "x86"
target_cpu = "x64"
更多信息请参见 GN cross compiles 。
添加BUILD.gn的详细步骤
添加一个构建文件
转到examples/simple_build
目录,这是一个最小的GN仓库的root目录。
在该目录中,有一个tutorial
目录。这里已经有一个tutorial.cc
文件,但没有与构建挂钩。在该目录中为我们的新目标创建一个新的BUILD.gn
文件,用于我们的新目标:
executable("tutorial") {sources = ["tutorial.cc"]
}
现在我们只需要告诉编译器这个新的目标。
打开目录(simple_build
)下的BUILD.gn
文件,GN从加载这个根文件,然后从这里开始加载所有的依赖项,所以我们只需要在这里添加对这个文件中的新目标的引用。
你可以把我们的新目标作为一个依赖关系加入到现有的目标中去,但把一个可执行文件作为依赖关系并没有什么意义。通常情况下,将一个可执行文件作为另一个可执行文件的依赖项是没有意义的(它们不能被链接)。
所以让我们做一个 tools group
组。在GN中,一个group
只是一个依赖关系的集合,没有编译或链接:
group("tools") {deps = [# 这将扩展到"//tutorial:tutorial "这个名字,这是新目标的全名# 新目标,运行 "gn help labels "可以获得更多信息# ‘//’双斜杠代表的是从source-root目录开始的路径,也可以用绝对路径来写,比如'/usr/local/foo:bar'"//tutorial"]
}
执行
gn help labels
可以看到help的详细的解释,关于如何添加子目录的目标到BUILD.gn里面。
测试你的添加
从simple_build
目录下的命令行:
$ gn gen out$ ninja -C out tutorialninja: Entering directory `out'[2/2] LINK tutorial
执行./out/tutorial
你应该看到 Hello from the tutorial.
输出到控制台。
题外话:GN
鼓励静态库的目标名称不是全局唯一的。要建立一个这样的库,你可以把标签和它的路径(但没有前面的//
)给ninja
:
ninja -C out some/path/to/target:my_target
所以前面的tutorial可以是:
$ ninja -C out tutorial:tutorialninja: Entering directory `out'ninja: no work to do.
声明依赖性
让我们看看在下列文件examples/simple_build/BUILD.gn
中定义的目标。这里有一个静态库定义了一个函数,GetStaticText()
:
static_library("hello_static") {sources = [ "hello_static.cc", "hello_static.h", ] }
还有一个共享库,定义了一个函数GetSharedText()
:
shared_library("hello_shared") { sources = [ "hello_shared.cc", "hello_shared.h", ] defines = [ "HELLO_SHARED_IMPLEMENTATION" ]}
这也说明了如何为一个目标设置预处理程序的定义,要设置多个以上的定义或赋值,请使用这种形式:
defines = [ "HELLO_SHARED_IMPLEMENTATION", "ENABLE_DOOM_MELON=0",]
现在我们来看看依赖这两个库的可执行文件:
executable("hello") { sources = [ "hello.cc", ] # 以冒号开头的标签指的是当前BUILD.gn文件中的标签 deps = [ ":hello_shared", ":hello_static", ]}
这个可执行文件包括一个源文件,并依赖于前面的两个库,以冒号开头的标签指的是当前BUILD.gn文件中具有该名称的目标。
测试二进制文件
在simple_build
目录下的命令行中:
ninja -C out helloout/hello
注意,你不需要重新运行GN。当任何构建文件发生变化时,GN会自动重新构建
ninja文件。因为ninja在开始执行时打印出[1/1] Regenerating ninja files
时,你就知道这个发生了。
将设置放在config
中
一个库的用户经常需要用到compile flags
、 defines
、include directories
,要做到这一点,把所有这些设置放到一个 "config "中就可以,这是一个命名的设置集合(但不包括源和依赖关系)。
config("my_lib_config") { defines = [ "ENABLE_DOOM_MELON" ] 。 include_dirs = [ "//third_party/something" ] 。}
要将一个配置的设置应用于目标,请将其添加到configs
列表中。
static_library("Hello_shared") { ... # 注意这里的 "+="通常是必须的,见下面的 "默认配置"。 configs += [ ":my_lib_config", ]}
一个配置可以应用于所有依赖当前配置的目标,只要把它的标签放在public_configs
列表中。
static_library("Hello_shared") { ... public_configs = [ ":my_lib_config", ]}
public_configs
也适用于当前的目标,所以不需要在两个地方都列出一个配置。
默认配置
构建配置将设置一些默认适用于每个target
的设置。
默认情况下,这些通常会被设置为默认的配置列表。你可以用print
命令看到 你可以使用print
命令看到这一点,这对调试很有用:
executable("hello") { print(configs)}
运行GN将打印类似的东西:
$ gn gen out["//build:compiler_defaults", "//build:executable_ldconfig"]
目标可以修改这个列表以改变其默认值。
例如,构建设置可能会通过添加no_exceptions
配置来默认关闭异常,但目标可以通过用不同的配置来重新启用它们:
executable("hello") { ... configs -= [ "//build:no_exceptions" ] # 删除全局默认。 configs += [ "//build:exceptions" ] # 用一个不同的来代替.}
我们上面的打印命令也可以用字符串插值来表达,这是一种将数值转换成字符串的方法。它使用符号"$"来指代一个变量。
print("The configs for the target $target_name are $configs")
执行ninja -C out hello
$ ninja -C out helloninja: Entering directory `out'[0/1] Regenerating ninja filesThe configs for the target hello are ["//build:compiler_defaults", "//build:executable_ldconfig"]ninja: no work to do.
添加一个新的构建参数
你可以通过declare_args
声明你接受哪些参数并指定默认值。
declare_args() { enable_teleporter = true enable_doom_melon = false}
参见gn help buildargs
以了解其工作原理。
参见gn help declare_args
以了解声明参数的具体细节。
在一个给定的范围内多次声明一个参数是一个错误,所以在确定参数的范围和命名时应该谨慎。
不知道发生了什么?
你可以在verbose模式下运行GN,以看到很多详细过程,使用-v
参数就可以:
$ gn gen out -vUsing source root /home/hui/disk4t/codes/gn/examples/simple_buildGot dotfile /home/hui/disk4t/codes/gn/examples/simple_build/.gnUsing build dir //out/Loading //build/BUILDCONFIG.gnLoading //BUILD.gnRunning //BUILD.gn with toolchain //build/toolchain:gccThe configs for the target hello are ["//build:compiler_defaults", "//build:executable_ldconfig"]Defining target //:hello(//build/toolchain:gcc)Defining target //:hello_shared(//build/toolchain:gcc)Defining target //:hello_static(//build/toolchain:gcc)Defining target //:tools(//build/toolchain:gcc)Loading //build/BUILD.gn (referenced from //build/BUILDCONFIG.gn:22)Loading //build/toolchain/BUILD.gn (referenced from //BUILD.gn:5)Loading //tutorial/BUILD.gn (referenced from //BUILD.gn:34)Running //build/BUILD.gn with toolchain //build/toolchain:gccRunning //tutorial/BUILD.gn with toolchain //build/toolchain:gccDefining config //build:compiler_defaults(//build/toolchain:gcc)Defining target //tutorial:tutorial(//build/toolchain:gcc)Defining config //build:executable_ldconfig(//build/toolchain:gcc)Running //build/toolchain/BUILD.gn with toolchain //build/toolchain:gccDefining toolchain //build/toolchain:gccComputing //:hello_shared(//build/toolchain:gcc)Computing //:hello_static(//build/toolchain:gcc)Computing //:hello(//build/toolchain:gcc)Computing //tutorial:tutorial(//build/toolchain:gcc)Computing //:tools(//build/toolchain:gcc)Done. Made 5 targets from 5 files in 5ms
"desc "命令
你可以运行gn desc <build_dir> <targetname>
来获取有关
一个给定的目标。
gn desc out //tutorial:tutorialThe configs for the target hello are ["//build:compiler_defaults", "//build:executable_ldconfig"]Target //tutorial:tutorialtype: executabletoolchain: //build/toolchain:gcc...
获取ldflags
信息
$ gn desc out //tutorial:tutorial ldflagsThe configs for the target hello are ["//build:compiler_defaults", "//build:executable_ldconfig"]-Wl,-rpath=$ORIGIN/-Wl,-rpath-link=
假设你想知道你的TWO_PEOPLE
定义来自哪里:
gn desc out/Default //foo/bar:say_hello defines --blame...lots of other stuff omitted... From //foo/bar:hello_config (Added //foo/bar/BUILD.gn:12) TWO_PEOPLE
另一个特别有趣的变体:
gn desc out/Default //base:base_i18n deps --tree
更多信息见gn help desc
。
附:gn labels
关于标签
所有可以参与依赖关系的图(目标、配置和工具链)都由标签来识别,一个常见的标签看起来像:
//base/test:test_support
这个例子包括一个source-root绝对路径、一个冒号和一个target,这意味着要在 "base/test/BUILD.gn "中寻找名为 "test_support "的目标。 如果有必要,你也可以指定系统的绝对路径。通常情况下,这样的路径会通过构建参数来指定,所以开发者可以指定组件在他们系统中的位置。
/usr/local/foo:bar (Posix)/C:/Program Files/MyLibs:bar (Windows)
工具链
一个规范的标签包括正在使用的工具链的标签。通常情况下,工具链标签隐含地继承自当前的执行环境,但你可以覆盖它以指定跨工具链的依赖关系。
//base/test:test_support(//build/toolchain/win:msvc)
这里 GN 将在文件"//build/toolchain/win "中寻找名为 "msvc "的工具链定义,以知道如何编译这个目标。
相对标签
如果你想引用同一构建文件中的东西,你可以省略路径名称,只用冒号开头。这种格式被推荐用于同文件中的标签引用。
:base
标签可以被指定为相对于当前目录的标签。从风格上看,我们更倾向于对所有非文件本地的引用使用绝对路径,除非一个构建文件需要在不同的环境下运行(比如一个项目既需要独立运行,又需要拉到目录层次中不同位置的其他项目中)。
source/plugin:myplugin.../net:url_request
隐式名称
如果一个名字没有被指定,它将继承目录名称。从风格上看,我们倾向于在可能的情况下省略冒号和名称。
//net -> //net:net//tools/gn -> //tools/gn:gn
为了能让大家更好的学习鸿蒙 (OpenHarmony) 开发技术,这边特意整理了《鸿蒙 (OpenHarmony)开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05
《鸿蒙 (OpenHarmony)开发学习手册》
入门必看:https://qr21.cn/FV7h05
- 应用开发导读(ArkTS)
- ……
HarmonyOS 概念:https://qr21.cn/FV7h05
- 系统定义
- 技术架构
- 技术特性
- 系统安全
如何快速入门?:https://qr21.cn/FV7h05
- 基本概念
- 构建第一个ArkTS应用
- 构建第一个JS应用
- ……
开发基础知识:https://qr21.cn/FV7h05
- 应用基础知识
- 配置文件
- 应用数据管理
- 应用安全管理
- 应用隐私保护
- 三方应用调用管控机制
- 资源分类与访问
- 学习ArkTS语言
- ……
基于ArkTS 开发:https://qr21.cn/FV7h05
1.Ability开发
2.UI开发
3.公共事件与通知
4.窗口管理
5.媒体
6.安全
7.网络与链接
8.电话服务
9.数据管理
10.后台任务(Background Task)管理
11.设备管理
12.设备使用信息统计
13.DFX
14.国际化开发
15.折叠屏系列
16.……