GN
使用gn编译项目的过程:
-
编写.gn文件
模块化各个模块,分别写一个build.gn,添加进主目录的build.gn的依赖中。
gn gen out/Default
ninja -C out/Default base
1. Ninja
ninja一个构建系统,它以文件(通常是源代码和输出可执行文件)的相互依赖性为输入,并快速地构建它们。Ninja通过将编译任务并行组织,大大提高了构建速度。
源于在Chromium浏览器项目中的工作,该项目具有30,000多个源文件,并且其其他构建系统(包括从自定义非递归Makefile构建的一个)在更改一个文件后将需要十秒钟才能开始构建。 而用ninja构建不到一秒钟。
1.1 设计目标
- 即使是非常大的项目,也可以非常快速(即即时)的增量构建。
- 关于如何构建代码的选择很少。对于不同项目,可能有不同的构建策略,ninja简化了这些选择。
- 让依赖正确,在一些特殊情况下Makefiles很难解决的。
- 速度和简单之间,选择速度。
1.2 示例
cflags = -Wall
rule cc
command = gcc $cflags -c $in -o $out
build foo.o: cc foo.c
为字符串生成一个更可读的名字
cflags = -g
使用$符号取值
rule cc
command = gcc $cflags -c $in -o $out
定义一个叫cc的rule,然后这条rule的内容是一个可执行的命令,$in
展开为输入文件(foo.c
),$out
展开为输出文件(foo.o
) for the command.
Build语句声明输入文件和输出文件之间的关系,以build关键词开始,格式是build outputs: rulename inputs
这个规则说明所有的输出文件都是从输入文件产生的。当output不存在或者input改变时,都会重新创建output。上面的例子里面out代表输出列表。
2. GN
GN是一个用来生成ninja构建文件的工具。
2.1 运行参数
生成构建目录
gn gen out/my_build
设置构建参数
gn gen out/my_build --args="..."
可以设置多个target os以及target cpugn args out/Default
(或者使用--args方式)
target_os = "chromeos"
target_os = "android"
target_cpu = "arm"
target_cpu = "x86"
target_cpu = "x64"
查看所有的参数
gn args --list out/Default
2.1 Build文件
示例
static_library(“base”) {
sources = [
“a.cc”,
“b.cc”,
]
}
加上依赖
static_library(“base”) {
sources = [
“a.cc”,
“b.cc”,
]
deps = [
“//fancypants”,
“//foo/bar:baz”,
]
}
设计原则
- 模块化
创建一个反映代码组件和子组件的目录结构,把BUILD文件放在每个目录中。
- 明确模块之间的关系
内置的target类型
-
executable
定义一个可执行target
-
shared_library
在链接器行上为目标指定共享库,该目标在“ deps”中列出了共享库。
-
static_library
创建.a以及.lib文件
-
loadable_module
创建一个目标文件,只能(并且只能)在运行时加载和卸载。
-
source_set:
编译没有中间库的源文件,将其视为静态库,但没有静态库链接规则。是经过编译但未链接的一组源,相反,生成的目标文件是隐式添加到依赖源的所有目标的链接器中。
-
group
把一些依赖合并起来并命名
copy
action, action_foreach
bundle_data, create_bundle: Mac & iOS
另外,我们也可以创建自定义类型。
标签说明
- 完整标签
//chrome/browser:version
- 隐式标签
//base, //base::base的缩写
- 当前目录
:bar,表示当前目录下的bar文件
依赖放到一个group中
gorup是没有被编译或者依赖的集合。
group("tools") {
deps = [
# This will expand to the name "//tutorial:tutorial" which is the full name
# of our new target. Run "gn help labels" for more.
"//tutorial",
]
}
条件语句
component(“base”) {
sources = [
“a.cc”,
“b.cc”,
]
if (is_win || is_linux) {
sources += [ “win_helper.cc” ]
} else {
sources -= [ “a.cc” ]
}
}
Config
Config持有flag, defines, include directories这样一些东西,但不包含源文件和依赖。
添加移除配置
executable(“doom_melon”) {
configs -= [
"//build/config/compiler:chromium_code",
]
configs += [
"//build/config/compiler:no_chromium_code",
]
}
把配置放到一个group中
config(“myconfig”) {
defines = [ “EVIL_BIT=1” ]
}
executable(“doom_melon”) {
...
configs += [ “:myconfig” ]
}
test(“doom_melon_tests”) {
...
configs += [ “:myconfig” ]
}
动态加载一些外部的数据文件
shared_library(“icu”) {
# This target is loaded @ runtime.
data_deps = [
“:icu_data_tables”,
]
}
权限控制
- deps vs public_deps
控制依赖的可见性
- visibility
设置当前文件可以被其他文件依赖
- assert_no_deps
依赖项都不应该链接
- testonly
不链接到production代码中