webrtc的GN构建系统
实时音视频划水大师
5 人赞同了该文章
目录
收起
GN是什么
安装方法
建立一个GN工程
GN的命令行使用
GN的语法介绍
生成目标
编译宏定义
依赖关系
分组
配置项
public配置
依赖查找
条件分支
编译器相关配置
其他
总结
最近想单独剥离webrtc的单个模块,因此就对webrtc的编译工程感兴趣,越挖掘深入就觉得gn的确是解决了大多数人的痛点,比相较于其他的工具如cmake更简单。它在的大型工程的依赖问题中解决的非常好,而且语法简洁。
先列出一些资源,给想看第一手资料的小伙伴自己学习:
- Ninja介绍:The Ninja build system
- GN源码入口:GN source
- GN快速入门:GN Quick Start guide
- GN参考手册:GN Reference
- 官方的PPT介绍:Using GN build - Google 幻灯片
- GN语言参考:GN Language and Operation
GN是什么
GN是一个用来产生ninja编译工程的工具,其定位与cmake类似(cmake也可以通过cmake -GNinja
生成ninja的工程)。它是由google开发,目前已经用于chromium(包含webrtc)、fuchsia以及相关的工程。
安装方法
可以直接从官方下载二进制包: Linux, macOS ,Windows,也可以从源码构建:
git clone https://gn.googlesource.com/gn
cd gn
# --allow-warning if you want to build with warnings.
# windows平台编译可能有warning问题导致编不过,可以通过上面的命令开启
python build/gen.py
# windows上需要能够找到cl.exe、link.exe等文件
# 默认使用x64编译
ninja -C out
# To run tests:
out/gn_unittests
建立一个GN工程
.gn
:位于源码根目录下,这是gn搜索的根目录,一般我们需要在该目录下指定编译配置buildconfig
。关于.gn
文件查看gn help dotfile
帮助BUILD.gn
:编译的脚本- buildconfig:包含了配置以及工具链等。
[!NOTE] 在chrome里,build目录( chromium/src/build)包含了GN的核心模版和配置以及一些python脚本,可以帮助我们更快地配置工程。一般来说,build是独立的不依赖其他工程,webrtc的构建也是依赖这个build目录。我们可以利用这里提供的工具链(支持使用内置的工具链或者用户指定的)。
对于buildconfig, gn的examples里面也提供了一个例子,也可使用它的例子。不过它只提供了gcc的工具链定义。
下面介绍如何借助于chrome的build来生成工程与编译(主要是自己不像重新折腾编译工具链):
mkdir gn_example
cd gn_examples
# 创建gn基本的结构
git clone https://chromium.googlesource.com/chromium/src/build build
touch .gn
touch BUILD.gn
# 使用chrome的build,需要这个override默认配置
mkdir build_overrides
touch build.gni
touch main.cc
代码如下:
# 使用我们自己的工具链
set DEPOT_TOOLS_WIN_TOOLCHAIN=0
# 指定vs2022以及windows sdk目录
set vs2022_install=D:\Program Files\Microsoft Visual Studio\2022\Community
set WINDOWSSDKDIR=D:\Windows Kits\10
# 需要在msvc的命令行下运行,否则找不到cl.exe等
# 默认是使用clang,这里我们禁用,windows使用msvc
# 使用gn gen 目标目录来生成工程到目标目录,可以指定参数
..\gn\out\gn.exe gen out --args="is_clang=false"
# 编译
ninja -C out
# 运行
out\gn_example.exe
GN的命令行使用
GN的帮助非常详细,可以使用gn --help
查看,gn主要有几个命令:
analyze: Analyze which targets are affected by a list of files.
args: Display or configure arguments declared by the build.
check: Check header dependencies.
clean: Cleans the output directory.
clean_stale: Cleans the stale output files from the output directory.
desc: Show lots of insightful information about a target or config.
format: Format .gn files.
gen: Generate ninja files.
help: Does what you think.
ls: List matching targets.
meta: List target metadata collection results.
outputs: Which files a source/target make.
path: Find paths between two targets.
refs: Find stuff referencing a target or file.
常用的有:
# 生成工程到out目录,并指定参数
gn gen out --args="is_clang=false,is_debug=false,target_cpu="x86\""
查看编辑编译参数:
# 以下命令会自动打开编辑器,可以修改上面指定的参数
gn args out
查看工程介绍:
# 查看out目录中:gn_example的信息
gn desc out :gn_example
检查头文件依赖:
gn check out :gn_example
以上的命令使用还有很多参数可以设置,需要根据自己的需求慢慢摸索。建议多使用--help
来学习。
GN的语法介绍
以下就重点介绍下,gn中场景的语法和使用,这些主要位于BUILD.gn文件。
生成目标
gn的生成目标一般主要有3个,可执行程序、静态库、动态库,分别使用executable
、static_library
、shared_library
来创建,如下:
使用executable创建二进制程序,程序名为tutorial,源码tutorial.cc
:
executable("tutorial") {
sources = [
"tutorial.cc",
]
}
创建静态库:
static_library("hello_static") {
sources = [
"hello_static.cc",
"hello_static.h",
]
}
创建动态库:
shared_library("hello_shared") {
sources = [
"hello_shared.cc",
"hello_shared.h",
]
defines = [ "HELLO_SHARED_IMPLEMENTATION" ]
}
编译宏定义
可以给编译器指定一些定义:
defines = [
"HELLO_SHARED_IMPLEMENTATION",
"ENABLE_DOOM_MELON=0",
]
依赖关系
创建一个hello二进制,依赖动态库hello_shared和静态库hello_static,gn的依赖关系通过deps数组指定:
executable("hello") {
sources = [
"hello.cc",
]
deps = [
":hello_shared",
":hello_static",
]
}
分组
可以对编译产物、配置等分组,这个分组只是形式上的,不会影响编译:
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",
]
}
配置项
可以创建一个配置如下,配置中包含了定义以及头文件包含目录,当前文件中其他地方可以通过":my_lib_config"
来引用配置:
config("my_lib_config") {
defines = [ "ENABLE_DOOM_MELON" ]
include_dirs = [ "//third_party/something" ]
}
如下引用:
static_library("hello_shared") {
configs += [
":my_lib_config",
]
}
配置可以动态更新,比如这里移出了一个配置,增加了一个配置,这里的配置语法非常清晰:
executable("hello") {
...
configs -= [ "//build:no_exceptions" ] # Remove global default.
configs += [ "//build:exceptions" ] # Replace with a different one.
}
public配置
public_config表示,如果有其他库依赖本库,都会应用这个配置:
static_library("hello_shared") {
...
public_configs = [
":my_lib_config",
]
}
依赖查找
我们的编译目标可以依赖其他的目标,比如一个可执行文件可以依赖一个静态库或者动态库。目标格式一般是路径:目标
,如//chrome/browser:version
表示依赖chrome/browser这里的version。
路径可以使用完整路径,如//chrome/browser:version
(根目录包含.gn),如果在当前文件中,则可以使用:foo
,表示依赖当前文件的foo目标。如果一个文件中只有一个目标,也可以省略目标,如//base
是//base:base
的简写。
- group:可以将一系列target分组
- copy
- action
- action_foreach
- bundle_deta、create_bundle:仅mac和ios
条件分支
component(“base”) {
sources = [
“a.cc”,
“b.cc”,
]
if (is_win || is_linux) {
sources += [ “win_helper.cc” ]
} else {
sources -= [ “a.cc” ]
}
}
编译器相关配置
可以指定clfags、宏定义、头文件包含目录等:
executable(“doom_melon”) {
sources = [ “doom_melon.cc” ]
cflags = [ “-Wall” ]
defines = [ “EVIL_BIT=1” ]
include_dirs = [ “.” ]
}
其他
gn也支持模版,可以定义一个新的target类型:
template("wtf") {
}
wtf("xxxx") {
}
action可以用来运行脚本:
action("myaction") {
script = "myscript.py"
inputs = [ "input.txt" ]
outputs = [ ]
}
总结
以上就是对gn的入门介绍。可以帮助大家快速了解gn,并完成一个gn的工程构建。如果需要深入了解gn,当然还是推荐大家多使用帮助或者看下官方文档