google gn 构建工具系统命令详解 (guozongling)
gn analyze <out_dir> <input_path> <output_path>
gn analyze <out_dir> <input_path> <output_path>
分析文件列表影响哪些目标。
这个命令有三个参数:
<out_dir>是构建目录的路径。
<input_path>是一个文件的路径,该文件包含一个带有三个字段的JSON对象:
- "files": 要检查的文件名列表
- "test_targets": 运行我们希望运行的测试所需的目标标签列表。
- "additional_compile_targets": 我们希望重构的目标标签列表,这个不是测试必须的。这个字段和“test_targets”之间的重要区别在于,如果additional_compile_targets列表中的一个项引用了一个组,那么如果该组的任何依赖项过期了,则会返回,但是组本身不需要返回。如果依赖项本身是组,则重复相同的筛选。此筛选可用于避免重新构建不受输入文件影响的组的依赖项。列表还可能包含字符串“all”,用于引用一个伪组,该伪组包含构建图中的每个根目标。
这种过滤行为也称为“修剪”编译目标列表。
如果<input_path> 是 "-",就从标准输入(stdin)读取。
<out_path> 是指命令的结果写在哪里。结果是一个JSON文件,包含一个或多个下面的字段:
- "compile_targets": 这个列表衍生自受输入文件影响的<compile_targets>。由于上面所描述的对编译目标的过滤方式,这个列表可能会包含没在输入列表中出现的目标。
- "test_targets": 这个列表来自受输入文件影响的<test_targets>,这个列表将是输入列表的一个适当子集。
- "invalid_targets": 输入中不存在于构建图中的任何名称的列表。如果这个列表是非空的,“error”字段也将被设置为“Invalid targets”。
- "status": 这个字符串包含下面三个值中的一个:
- "Found dependency"
- "No dependency"
- "Found dependency (all)"
第一种情况:<compile_targets>和<test_targets>返回的目标列表会被[ninja]进行编译构建。
第二种情况:没有受影响的东西,无需构建。
第三种情况:[gn]不能决定正确的行为方式,安全起见,会将输入当作输出返回。
- "error": 代表有错误,会包含描述错误的信息。错误情况可能是输入文件的格式不正确,或者包含有无效的目标。
如果<out_path>是"-",会输出到标准输出(stdout)。
命令将返回【1】如果不能读取输入文件或者写输出文件,或者有一些构建的错误,否则就返回【0】。
尤其是,即使<error> 不为空并且发生了非致命性错误,这时也返回【0】。换句话说,它总是尽量的去向输出的JSON文件中输出一些信息,而不是返回错误码。
gn args: (command-line tool)
显示或者配置由构建声明的参数
gn args <out_dir> [--list] [--short] [--args] [--overrides-only]
可以用"gn help buildargs"查看更多的概述关于构建的参数如何起作用
用法:
gn args <out_dir>
在编辑器中打开给定的构建目录,会在<out_dir>路径下面打开参数文件,如果<out_dir>不存在,则会创建该目录并且打开一个空的参数文件,你可以写入一些参数信息,例如:
enable_doom_melon=false
os="android"
gn 会在环境变量中顺序查找指定的编辑器,顺序为 GN_EDITOR, VISUAL, EDITOR,你可以指定这三个变量的值,将值指定为你自己的编辑器。
注意: 你可以在<out_dir>路径下面为构建系统手动编辑"args.gn"中的参数,然后运行命令"gn gen <out_dir>"。
gn args <out_dir> --list[=<exact_arg>] [--short] [--overrides-only] [--json]
列出当前配置中可用的所有构建参数,或者,如果为列表标志指定了exact_arg,则只指定一个构建参数。
如果 --short 被指定,则只有名字和当前的值会被打印出来。
如果 --overdides-only被指定,则只有那些被重写过的参数的名字和当前值才会被打印。
如果 --json 被指定,则会以JSON的格式来打印输出的信息。
Examples
gn args out/Debug
用args命令在out/Debug路径下面打开一个默认的参数文件args.gn(一般默认是这个文件名字)。
gn args out/Debug --list
没有 --short 的时候,此时会以文字注释的形式输出参数的当前值,以及默认值。你可以知道默认值是什么,当前值是什么。
gn args out/Debug --list --short
打印带有默认值的参数。(注意,打印的不是参数的默认值,而是当前值,只不过这参数不被重写的时候也有个系统的默认值,所以这样的参数就是带有默认值的参数。比如你在args.gn中自己定义了一个新的变量"enable_my_script=true",那这个新的变量是不打印的。)
gn args out/Debug --list --short --overrides-only
只打印被重写过的参数。
比如host_os = "linux"是默认值,你改成了host_os = "windows",那么就会值显示 host_os = "windows"这一个,因为host_os已经被重写了。
gn args out/Debug --list=target_cpu
没有 --short ,此时会打印target_cpu的当前值,以及默认值。(如果参数未被重写,那就只有默认值,也就只打印默认值)
gn args --list --args="os=\"android\" enable_doom_melon=true"
打印带有默认值的参数。(查看 gn args out/Debug --list --short 部分,括弧中有解释)。
另外,--args后面的值会直接写入文件(args.gn)中,原来文件中的内容会清空。(因此可能会影响其它参数的值)
gn check <out_dir> [<label_pattern>] [--force] [--check-generated]
这个命令和 "gn gen --check"功能是一样的,但这个命令(gn check)无法写出构建文件(类似于BUILD.gn的文件)。
这个命令的功能是检查类C(C/C++/objc/objc++/等等,也就是基于C语言的代码文件,因为要检查#include包含进来的文件)文件中用 #include 引入进来的文件是否合法有效。
<label_pattern>是一个匹配模式,如果设置了,那么只有和这个模式匹配的目标(target)才会被检查。
--check-generated
有些文件是在编译过程中由构建系统生成的,比如Google用一些 .idl后缀的文件生成 .h和.cc文件。
这些文件由于一开始就不存在,所以通常是不会检查的。
但如果设置了这个选项,那些已经被生成过的文件就会被检查。
--check-system
检查系统风格的文件,也就是除了检查双引号("")引入的文件之外,连尖括号(<>)引入的文件也会被检查。
--default-toolchain
只检查使用默认工具链的目标。
"//src:*" 这种通配符匹配会将src目录下面的所有目标都匹配,但如果加了 --default-toolchain 选项,那些指定了与默认工具链不同的目标就不会被匹配到,也就不会被检查。在GN构建系统中,每个目标(target)都可以被指定不同的工具链编译,指定工具链的方式就是在目标的后面添加 "([工具链路径])"。
比如, 我构建 "//src/foo:foo"这个目标的时候,想指定"//toolchain:win32_toolchain"工具链编译它,那么写法就是:
"//src/foo:foo(//toolchain:win32_toolchain)"
--force
忽略目标中的"check_includes = false"设置,对所有需要检查的目标进行检查。
什么会被检查?
.gn 文件可以用"check_targets"指定一个要检查的列表,也可以用"no_check_targets"指定一个不被检查的列表。而如果从命令行指定,那"check_targets"和"no_check_targets"就都不会生效。
如果目标设置"check_includes = false",而"gn check"没有使用"--force",这个目标就不会被检查。(看上面说明,--force)
被检查的目标:
GN会打开目标中的类C源文件,查看#include引入了哪些文件。
检查双引号("")引入的文件,除非指定了 --check_system,不然不会检查尖括号(<>)引入的系统文件。
如果 #include 行有 "nogncheck"注释,那就不会检查这个文件。比如 #include "mytest/testgn.h" // nogncheck
GN 会根据目标中"include_dirs"指定的路径搜寻文件,还有当前目录。
GN不会进行预处理,因此它无法理解那些根据条件判断引入的文件(可能会都检查,可以用"nogncheck"注释)。比如:
#if defined(TEST_GN)
#include "mytest/testgn.h"
#endif
只有匹配到已知文件的 #include才会被检查,未知路径的就会被忽略。
包含文件是否有效:
被引入文件必须存在于当前目标,或者当前目标所公共依赖的目标中。
多个目标引入同一个文件,只需要有一个目标验证被引入文件是有效的即可。
如果一个目标中只有"sources",则这个目标中所有的东西都默认是 public 的,那么其它有效公开依赖的这个目标的目标都可以引入这个目标中的文件。(只有public的东西才可以被继承下去,查看 public 的详细说明)
如果一个目标有 public,那这个目标中其它的东西都默认为private,包括sources也是私有的,不管依赖关系如何,只有 public 指定的文件可以被其它目标所引入。
<action>输出的东西是被当作public处理的,所以可以被继承。
问题修复的建议:
如果你有第三方的项目,而且很难修复或者不需要检查引入文件,那你可以用"check_includes = false"来避开检查。
如果你有条件判断处理,如上面所说的 #if defined(), 你要确保构建系统和预处理时的判断条件一致,还要用 "nogncheck"来注释。
如果你有毫不相交的目标(targets),你可以用"allow_circular_includes_from"标注。理想情况下,每个依赖项都应该具有相同的依赖项,因此从这些依赖项继承的配置是一致的。
如果你有独立的头文件需要在几个目标之间共用,那你可以把这些头文件放入 <source_set>。 可以用 public或者只用<sources>。这样这个source set都可以被引用依赖了。
例子:
gn check out/Debug
检查所有的文件。
gn check out/Default //foo:bar
只检查在 //foo:bar 目标中的文件。
gn check out/Default "//foo/*
只检查 //foo 目录下所有目标的文件。
gn clean <out_dir>...
删除所有输出目录下的除了args.gn的文件。为再次编译创造干净的环境。这个路径与 gn gen <out_dir>对应。
gn desc <out_dir> <label or pattern> [<what to show>] [--blame] [--format=json]
显示所给目标或配置的信息。
<label or pattern>可以是一个目标标签,配置标签,或者一个匹配模式标签。只有匹配成功的才会显示。
<what to show> 包括如下(如果不指定,默认显示):
all_dependent_configs
allow_circular_includes_from
arflags [--blame] args
cflags [--blame]
cflags_c [--blame]
cflags_cc [--blame]
check_includes
configs [--tree] (see below)
data_keys
defines [--blame]
depfile
deps [--all] [--tree] (see below)
framework_dirs
frameworks
include_dirs [--blame]
inputs ldflags [--blame]
lib_dirs libs
metadata
output_conversion
outputs
public_configs
public
rebase
script
sources
testonly
visibility
walk_keys
weak_frameworks
runtime_deps
[--format=json] 以JSON的格式输出。
gn help <anything>
可以用这个命令查看gn任意命令或者标签的用法。只要你想使用的任何标签或者函数都可以查看。
比如: gn help all_dependent_configs
gn help --markdown all 输出所有gn的用法。
一些次要的命令不作解释了。
gn outputs <out_dir> <list of target or file names...>
列出所给目标或文件的输出文件。
例子:
gn outputs out/debug some/directory:some_target
列出目标"some/directory:some_target"的输出。
gn outputs out/debug src/project/my_file.cc | xargs ninja -C out/debug
只编译这个文件,每个工具链都会编译。(如上面所说,每个target可以用不同的工具链编译)
git diff --name-only | xargs gn outputs out/x64 | xargs ninja -C out/x64
编译所有改动过的文件。这个前提是用git管理的代码,因为git diff是GIT命令。
gn path <out_dir> <target_one> <target_two>
找出两个目标直接的依赖路径。
--all
找到所有路径,而不是只找第一个。公共路径先被打印,并按照路径长度的顺序打印。然后是非公共路径的打印,也是按照路径长度的顺序。
--public
只找公共路径。不能和--with-data使用。
--with-data
找data deps。不能和--public使用。
(不知道一起使用会怎么样,没试过,~_~)
目标声明 (Target declarations)
action:
可以让你执行一次脚本生成一个或多个输出文件。 如果你想要每个文件都执行一次脚本就使用 action_foreach。
在<action>中"sources"和"inputs"效果一样。如果你想把"sources"传递给脚本,你需要在"args"中包含它。
由于没有对路径进行处理,GN不知道哪些参数是路径,哪些参数不是路径,所以需要用rebase_path()函数对路径进行处理,这个函数可以将路径转换成相对于root_build_dir(当前命令执行的路径)的路径。
如果命令行的参数太长,你可以用响应文件(response file)来传递参数给你的脚本。(查看 gn help response_file_contents的用法)
参数太长的话,系统会把这些参数卸载一个不限大小的临时文件中,而在脚本中使用"{{response_file_contents}}"来替代那个临时文件。因此,你可以用"{{response_file_contents}}"来传参。
推荐你把要传给脚本的输入放在"sources"变量中,而需要运行你这个脚本的其它python文件放在"inputs"变量中。
因为<deps>和<public_deps>总是在<action>执行之前就完成,所以<action>可以依赖前面步骤所输出的东西作为依赖。
GN可以为所有<action>命令设置ninja的"restat"的标志,将其设置为"restat = 1",那么ninja就会在<action>执行完成后检查输出(文件或别的什么)的时间戳,如果这个时间戳不变,那就意味着不需要重新构建相关的东西,这样也减少了不必要的构建。
<outputs> 可以指定脚本输出的名字。
例子:
action("run_this_guy_once") { script = "doprocessing.py" sources = [ "my_configuration.txt" ] outputs = [ "$target_gen_dir/insightful_output.txt" ] # Our script imports this Python file so we want to rebuild if it changes. inputs = [ "helper_library.py" ] # Note that we have to manually pass the sources to our script if the # script needs them as inputs. args = [ "--out", rebase_path(target_gen_dir, root_build_dir) ] + rebase_path(sources, root_build_dir) }
action_foreach:
遍历<sources>中的文件,每个文件都会执行一次脚本。
如果你有额外的数据需要传给脚本,比如一个共享配置或者一个python脚本,你应该把它放入<inputs>变量。
{{source_name_part}} 是输入文件的名字,比如 "foo.idl"的名字就是"foo"
两个大括号 "{{ }}" 表示的是占位符,可以了解一下GN中的占位符用法,有哪些占位符可以使用。
例子:
# Runs the script over each IDL file. The IDL script will generate both a .cc # and a .h file for each input. action_foreach("my_idl") { script = "idl_processor.py" sources = [ "foo.idl", "bar.idl" ] # Our script reads this file each time, so we need to list it as a # dependency so we can rebuild if it changes. inputs = [ "my_configuration.txt" ] # Transformation from source file name to output file names. outputs = [ "$target_gen_dir/{{source_name_part}}.h", "$target_gen_dir/{{source_name_part}}.cc" ] # Note that since "args" is opaque to GN, if you specify paths here, you # will need to convert it to be relative to the build directory using # rebase_path(). args = [ "{{source}}", "-o", rebase_path(relative_target_gen_dir, root_build_dir) + "/{{source_name_part}}.h" ] }
copy:
声明一个拷贝文件的目标。
所有的输出文件都必须在构建输出目录的里面。通常会用到 |$target_out_dir| 或者 |$target_gen_dir|,这两个分别是生成目标的最终目录,以及产生中间文件的目录。
<sources>和<outputs>必须被指定,<sources>你可以指定多少都行,但<outputs>只能有一项。
如果有多个文件输入,那么就要用源扩展。(可以查看sources_expansion用法)
可以看看占位符"{{source_name_part}}"的用法。
例子:
# Write a rule that copies a checked-in DLL to the output directory. copy("mydll") { sources = [ "mydll.dll" ] outputs = [ "$target_out_dir/mydll.dll" ] } # Write a rule to copy several files to the target generated files directory. copy("myfiles") { sources = [ "data1.dat", "data2.dat", "data3.dat" ] # Use source expansion to generate output files with the corresponding file # names in the gen dir. This will just copy each file. outputs = [ "$target_gen_dir/{{source_file_part}}" ] }
executable:
生成可执行文件目标。目标的生成要取决于这个目标中的源文件是用什么编程语言,一个目标不可以有多种编译语言,比如一个target可以包含C和C++源文件,但不可以有C和Rust源文件。
可用变量:
Flags: cflags, cflags_c, cflags_cc, cflags_objc, cflags_objcc, asmflags, defines, include_dirs, inputs, ldflags, lib_dirs, libs, precompiled_header, precompiled_source, rustflags, rustenv, swiftflags Deps: data_deps, deps, public_deps Dependent configs: all_dependent_configs, public_configs General: check_includes, configs, data, friend, inputs, metadata, output_name, output_extension, public, sources, testonly, visibility Rust variables: aliased_deps, crate_root, crate_name
generated_file:
声明一个generated_file类型的目标。在解析式将数据写到磁盘。
这个目标类型反映了write_file()函数的一些功能,也具有从它的依赖中手机metadata的能力。
<outputs>变量表示输出到的文件名,它必须是一个包含单个元素的列表。
<output_conversion>变量表示写数据值的格式。
<contents>和<data_keys>必须被指定其中的一个,使用<data>就会把值的内容写到文件,而使用<data_keys>就会触发metadata的收集。
例子:
Given the following targets defined in //base/BUILD.gn, where A depends on B and B depends on C and D: group("a") { metadata = { doom_melon = [ "enable" ] my_files = [ "foo.cpp" ] # Note: this is functionally equivalent to not defining `my_barrier` # at all in this target's metadata. my_barrier = [ "" ] } deps = [ ":b" ] } group("b") { metadata = { my_files = [ "bar.cpp" ] my_barrier = [ ":c" ] } deps = [ ":c", ":d" ] } group("c") { metadata = { doom_melon = [ "disable" ] my_files = [ "baz.cpp" ] } } group("d") { metadata = { my_files = [ "missing.cpp" ] } } If the following generated_file target is defined: generated_file("my_files_metadata") { outputs = [ "$root_build_dir/my_files.json" ] data_keys = [ "my_files" ] deps = [ "//base:a" ] } The following will be written to "$root_build_dir/my_files.json" (less the comments): [ "baz.cpp", // from //base:c via //base:b "missing.cpp" // from //base:d via //base:b "bar.cpp", // from //base:b via //base:a "foo.cpp", // from //base:a ] Alternatively, as an example of using walk_keys, if the following generated_file target is defined: generated_file("my_files_metadata") { outputs = [ "$root_build_dir/my_files.json" ] data_keys = [ "my_files" ] walk_keys = [ "my_barrier" ] deps = [ "//base:a" ] } The following will be written to "$root_build_dir/my_files.json" (again less the comments): [ "baz.cpp", // from //base:c via //base:b "bar.cpp", // from //base:b via //base:a "foo.cpp", // from //base:a ] If `rebase` is used in the following generated_file target: generated_file("my_files_metadata") { outputs = [ "$root_build_dir/my_files.json" ] data_keys = [ "my_files" ] walk_keys = [ "my_barrier" ] rebase = root_build_dir deps = [ "//base:a" ] } The following will be written to "$root_build_dir/my_files.json" (again less the comments) (assuming root_build_dir = "//out"): [ "../base/baz.cpp", // from //base:c via //base:b "../base/bar.cpp", // from //base:b via //base:a "../base/foo.cpp", // from //base:a ]
变量:
contents data_keys rebase walk_keys output_conversion Deps: data_deps, deps, public_deps Dependent configs: all_dependent_configs, public_configs
group:
声明指定的目标组。
此目标类型允许您创建元目标,它只将一组依赖项收集到一个命名的目标中。组还可以指定适用于其依赖项的配置。
变量:
Deps: data_deps, deps, public_deps Dependent configs: all_dependent_configs, public_configs
例子:
group("all") { deps = [ "//project:runner", "//project:unit_tests", ] }
你可以把一组依赖,或者一组配置放在一个group里面。
shared_library:
声明一个共享库目标。Linux平台会生成一个.so文件,也就是动态库。
变量:
Flags: cflags, cflags_c, cflags_cc, cflags_objc, cflags_objcc, asmflags, defines, include_dirs, inputs, ldflags, lib_dirs, libs, precompiled_header, precompiled_source, rustflags, rustenv, swiftflags Deps: data_deps, deps, public_deps Dependent configs: all_dependent_configs, public_configs General: check_includes, configs, data, friend, inputs, metadata, output_name, output_extension, public, sources, testonly, visibility Rust variables: aliased_deps, crate_root, crate_name, crate_type
source_set:
声明一个源集类型目标。目前只支持C语言的源集。(也就是类C风格,比如C,C++)
变量:
Flags: cflags, cflags_c, cflags_cc, cflags_objc, cflags_objcc, asmflags, defines, include_dirs, inputs, ldflags, lib_dirs, libs, precompiled_header, precompiled_source, rustflags, rustenv, swiftflags Deps: data_deps, deps, public_deps Dependent configs: all_dependent_configs, public_configs General: check_includes, configs, data, friend, inputs, metadata, output_name, output_extension, public, sources, testonly, visibility
static_library:
生成一个静态库。
变量:
complete_static_lib Flags: cflags, cflags_c, cflags_cc, cflags_objc, cflags_objcc, asmflags, defines, include_dirs, inputs, ldflags, lib_dirs, libs, precompiled_header, precompiled_source, rustflags, rustenv, swiftflags Deps: data_deps, deps, public_deps Dependent configs: all_dependent_configs, public_configs General: check_includes, configs, data, friend, inputs, metadata, output_name, output_extension, public, sources, testonly, visibility Rust variables: aliased_deps, crate_root, crate_name
target:
用所给的类型生成一个target。
target(target_type_string, target_name_string) { ... }
例如
target("shared_library", "doom_melon") 就等同于 shared_library("doom_melon")
target("static_library", "doom_melon") 就等同于 static_library("doom_melon")
例子:
if (foo_build_as_shared) { my_type = "shared_library" } else { my_type = "source_set" } target(my_type, "foo") { ... }
assert:
断言一个表达式为真。与C语言assert一样。
assert(<condition> [, <error string>])
如果表达式为假,构建就会失败,当个为假的时候就会输出第二个参数的内容。
例子:
assert(is_win) assert(defined(sources), "Sources must be defined");
config:
声明一个config对象。
这个配置可以应用于目标上。
这个config里面可以包含flags(cflags/cflags_c/cflags_cc/...), 头文件路径,变量或宏定义(defines)等等。
这个配置可以像target一样通过它自己的标签来被引用。
一个目标按这样的顺序生成:
1. 使用本目标中直接被定义的值;
2. 使用<configs>指定的配置;
3. 根据<public_configs>的指定,遍历依赖查找配置;
4. 根据<all_dependent_configs>的指定,遍历依赖查找配置。
在配置定义中有效的变量:
Flags: cflags, cflags_c, cflags_cc, cflags_objc, cflags_objcc, asmflags, defines, include_dirs, inputs, ldflags, lib_dirs, libs, precompiled_header, precompiled_source, rustflags, rustenv, swiftflags Nested configs: configs
用于应用配置的目标上的变量:
all_dependent_configs, configs, public_configs
例子:
config("myconfig") { include_dirs = [ "include/common" ] defines = [ "ENABLE_DOOM_MELON" ] } executable("mything") { configs = [ ":myconfig" ] }
declare_args:
声明构建参数。
如果命令行或者工具链参数都没有指定值,那么就会用declare_args设置的默认值,这个默认值无法覆盖命令行的值。
1. declare_args()执行,那么在这个闭包({} 代码块之间)中定义的值都是可以读的,而在这个之前定义的值都不可以。
2. 执行完这个块作用域,在里面设置的变量就会被保存,这些变量称之为"默认值"。一经保存,这些值就可以通过args.gn文件来重写。
3. "gn args"可以重写默认值,在文件中的代码可以使用那些变量。
- 在declare_args() { ... }这个块作用域中不用执行复杂的工作,因为这是设置默认值的,复杂的工作可能会被忽视。尤其是,不要用exec_script()去设置默认值,如果你想用脚本设置默认值,你应该在declare_args()这个块作用域之后再设置,而且应该是设置一些没被定义的值,比如 [],"",或者-1。
- 因为你不能在同一个块作用域中读定义的变量,如果你想用一个被定义的默认值去定义另一个变量,那么你可以写两个declare_args() { ... } 块:
declare_args() { enable_foo = true } declare_args() { # Bar defaults to same user-overridden state as foo. enable_bar = enable_foo }
例子:
declare_args() { enable_teleporter = true enable_doom_melon = false } 如果你想重写enable_doom_melon: gn --args="enable_doom_melon=true enable_teleporter=true" 注意: enable_teleporter=true也要写上, 不需要改变就写原来的值。(好像--args是修改args.gn文件,会覆盖文件中的内容,~_~ 谁会把重要东西写在args.gn呢?反正我不用这个文件。)
defined:
返回ture如果所给的参数被定义了。
例子:
template("mytemplate") { # To help users call this template properly... assert(defined(invoker.sources), "Sources must be defined") # If we want to accept an optional "values" argument, we don't # want to dereference something that may not be defined. if (defined(invoker.values)) { values = invoker.values } else { values = "some default value" } }
exec_script:
同步执行一个脚本,返回输出。
exec_script(filename, arguments = [], input_conversion = "", file_dependencies = []) 如果脚本不存在,返回非零错误码。
filename:
要执行的脚本名称,如果filename不是绝对路径,则会被当成相对于当前目录的路径。可以用rebase_path()改变路径,这个函数经常用到,只要你用文件了,可能就要用用它转换路径。
arguments:
作为参数传递给脚本。可以为空,表示没有参数。
input_conversion:
控制文件如何读取或者解析。可以查看io_conversion的帮助。(gn help io_conversion)
file_dependencies(可选的):
脚本读取或者依赖的一个文件列表,这些依赖会被添加到构建结果中,如果这些依赖有改变,构建就会重新生成,脚本也会再运行。
例子:
all_lines = exec_script( "myscript.py", [some_input], "list lines", [ rebase_path("data_file.txt", root_build_dir) ]) # This example just calls the script with no arguments and discards the # result. exec_script("//foo/bar/myscript.py")
filter_exclude:
filter_exclude(values, exclude_patterns)
values:
必须是一个字符串列表。
exclude_patterns:
用于匹配的文件模式列表。(也就是过滤规则)
[values]这列表中的值,如果在[exclude_patterns]中可以匹配到,那么就要被过滤掉。
也就是按照 [exclude_patterns] 的规则来筛选 [values] 里面的值。
可以总结为: 匹配到就过滤。
例子:
values = [ "foo.cc", "foo.h", "foo.proto" ] result = filter_exclude(values, [ "*.proto" ]) # result will be [ "foo.cc", "foo.h" ]
filter_include:
filter_include(values, include_patterns)
与<filter_exclude>作用相反。
[values]这列表中的值,如果在[include_patterns]中可以匹配到,那么就要被保留。
可以总结为: 匹配到就保留。
例子:
values = [ "foo.cc", "foo.h", "foo.proto" ] result = filter_include(values, [ "*.proto" ]) # result will be [ "foo.proto" ]
foreach:
foreach(<loop_var>, <list>) { <loop contents> }
遍历列表。
例子:
mylist = [ "a", "b", "c" ] foreach(i, mylist) { print(i) } Prints: a b c
forward_variables_from:
从不同的作用域拷贝变量。
forward_variables_from(from_scope, variable_list_or_star, variable_to_not_forward_list = [])
from_scope:
给定的作用域。 也就是将从这个作用域中拷贝变量。
variable_list_or_star:
要拷贝的变量列表。可以给定一个变量(variable)列表,或者给定一个星号(*)。
variable_to_not_forward_list:
不拷贝的变量列表。当 "variable_list_or_star" 设置为 "*" 的时候这个很有用。
从给定的作用域将变量拷贝到当前作用域中如果变量存在。(这个用法在<template>中很常用)
如果要拷贝的变量没有找到,那就在当前作用域中把该变量当作未定义处理。
"*"会拷贝在给定的作用域定义的变量,不在里面直接定义的不包括。
如果要拷贝的变量在当前作用域已经存在了,那就会出错。
如果要拷贝的变量是"*",那么当前作用域的变量就会被废掉,也就是使用给定作用域的变量。
如果你想自己也定义变量呢? 可以判断给定作用域的变量是否存在,如果存在就用 "+=" 来添加,不存在就直接为当前作用域的变量定义。(可以看一些例子就是这样)
例子:
# forward_variables_from(invoker, ["foo"]) # is equivalent to: assert(!defined(foo)) if (defined(invoker.foo)) { foo = invoker.foo } # This is a common action template. It would invoke a script with some given # parameters, and wants to use the various types of deps and the visibility # from the invoker if it's defined. It also injects an additional dependency # to all targets. template("my_test") { action(target_name) { forward_variables_from(invoker, [ "data_deps", "deps", "public_deps", "visibility"]) # Add our test code to the dependencies. # "deps" may or may not be defined at this point. if (defined(deps)) { deps += [ "//tools/doom_melon" ] } else { deps = [ "//tools/doom_melon" ] } } } # This is a template around a target whose type depends on a global variable. # It forwards all values from the invoker. template("my_wrapper") { target(my_wrapper_target_type, target_name) { forward_variables_from(invoker, "*") } } # A template that wraps another. It adds behavior based on one # variable, and forwards all others to the nested target. template("my_ios_test_app") { ios_test_app(target_name) { forward_variables_from(invoker, "*", ["test_bundle_name"]) if (!defined(extra_substitutions)) { extra_substitutions = [] } extra_substitutions += [ "BUNDLE_ID_TEST_NAME=$test_bundle_name" ] } }
get_label_info:
get_label_info(target_label, what)
给定一个目标的标签,返回那个目标的属性。
target_label:
目标标签。
[what] 可能的值:
"name":
目标的名字。会匹配目标中定义的<target_name>变量。例如 对于 label "//foo/far:baz"将返回 "baz"
"dir":
目标定义所在的目录。(末尾不带斜杠) 例如 对于 label "//foo/far:baz"将返回 "//foo/far"
"target_gen_dir":
目标构建过程中生成的中间文件的路径。它会匹配目标声明的<target_gen_dir>变量。
"root_gen_dir":
目标构建过程中生成的中间文件的根路径。它会匹配目标声明的<root_gen_dir>变量。
"target_out_dir":
目标输出目录。它会匹配目标声明的<target_out_dir>变量。
"root_out_dir":
目标输出的根目录。它会匹配目标声明的<root_out_dir>变量。
"label_no_toolchain":
返回不包含工具链的标签。 例如 ":bar" 可能返回 "//foo:bar"
"label_with_toolchain":
返回包含工具链的标签。 例如 ":bar" 可能返回 "//foo:bar(//toolchain:x64)"
每个label后面都可以指定toolchain,用括号包含,这种是显式指定,那些没有括号的都是隐式指定采用默认的工具链。
"toolchain":
匹配在该目标中声明的<current_toochain>变量。
例子:
get_label_info(":foo", "name") # Returns string "foo". get_label_info("//foo/bar:baz", "target_gen_dir") # Returns string "//out/Debug/gen/foo/bar".
get_path_info:
get_path_info(input, what)
input:
是一个文件或者目录名的字符串,或者是一个字符串列表。如果是一个列表,那么就会对列表中的每一项都处理,然后把结果以列表形式返回。
[what] 可能的值:
"file":
返回路径最后一个斜杠后面的字符串。(包含名字和后缀)
例如:
"foo/bar.txt" => "bar.txt"
"bar.txt" => "bar.txt"
"/" => ""
"" => ""
"name":
返回不包含后缀的文件名。
例如:
"foo/bar.txt" => "bar"
"foo/bar" => "bar"
"foo/" => ""
"extension":
返回最后一个斜杆后面的点后面的字符串。
例如:
"foo/bar.txt" => "txt"
"foo/bar" => ""
"dir":
返回名字部分的目录,不包含斜杠。
例如:
"foo/bar.txt" => "foo"
"//foo/bar" => "//foo"
"foo" => "."
"out_dir":
返回与给定文件路径对应的输出文件目录,不包含末尾斜杠。
例如:
"//foo/bar/bar.txt" => "//out/Debug/obj/foo/bar"
"gen_dir":
返回与给定文件路径对应的生成文件目录,不包含末尾斜杠。
例如:
"//foo/bar/bar.txt" => "//out/Debug/gen/foo/bar"
"abspath":
返回一个全路径。
如果输入的是绝对路径,那就把这个路径返回。
如果输入的是相对路径,那么就转换为源绝对路径。(GN中把"//"开头成为源绝对路径,".gn"文件所在的路径)
例如:
"foo/bar.txt" => "//mydir/foo/bar.txt"
"foo/" => "//mydir/foo/"
"//foo/bar" => "//foo/bar" (已经是源绝对路径)
"/usr/include" => "/usr/include" (绝对路径)
如果想让路径相对于另一个路径,那就用 rebase_path()。
例子:
sources = [ "foo.cc", "foo.h" ] result = get_path_info(source, "abspath") # result will be [ "//mydir/foo.cc", "//mydir/foo.h" ] result = get_path_info("//foo/bar/baz.cc", "dir") # result will be "//foo/bar" # Extract the source-absolute directory name, result = get_path_info(get_path_info(path, "dir"), "abspath")
get_target_outputs:
get_target_outputs(target_label)
返回给定目标标签的输出文件列表。在这个函数调用之前,这个目标标签必须在这个文件中已经被定义了。
只有<copy>,<generated_file>,<action>这样的目标标签才被支持。
返回一个list,里面的路径都是源绝对路径(以"//"形式开头的路径)。
对于<copy>,<generated_file>,<action>这几个目标(target)标签,会返回他们在target中定义的<outputs>变量指定的文件。
例子:
# Say this action generates a bunch of C source files. action_foreach("my_action") { sources = [ ... ] outputs = [ ... ] } # Compile the resulting source files into a source set. source_set("my_lib") { sources = get_target_outputs(":my_action") }
getenv:
value = getenv(env_var_name)
获取环境变量的值。(区分大小写)
例子:
home_dir = getenv("HOME")
import:
将文件导入到当前作用域内。
通常被导入文件的后缀是 .gni
不能导入一个在构建中使用的BUILD.gn文件。
被导入文件的作用域会和在执行import命令的地方进行合并。如果被导入文件中的一些变量或者规则和当前作用域中有同样的变量或规则,仅仅值不相同,这就会产生冲突,从而在运行时报错。
以下划线"_"开头的变量或者模板通常被认为是私有的,因此不会被导入。被导入文件可以用这些私有的变量进行内部计算,从而不会影响其它文件。
例子:
import("//build/rules/idl_compilation_rule.gni") # Looks in the current directory. import("my_vars.gni")
not_needed:
not_needed(variable_list_or_star, variable_to_ignore_list = []) not_needed(from_scope, variable_list_or_star, variable_to_ignore_list = [])
在当前作用域或者给定作用域中,将变量标记为“不需要的”,这样对于这样未被使用的变量就不会出错。
variable_list_or_star:
需要被标记的变量列表或者通配符 "*" 。
variable_to_ignore_list:
当第一个参数<variable_list_or_star>是通配符 "*" 时,<variable_to_ignore_list>可以将一些变量排除在外,不被标记为“不需要的”。
例子:
not_needed("*", [ "config" ]) => 除了"config"不被标记,其它的都标记。 not_needed([ "data_deps", "deps" ]) => "data_deps"被标记。 not_needed(invoker, "*", [ "config" ]) => 标记<invoker>作用域中所有变量,除了"config"。 not_needed(invoker, [ "data_deps", "deps" ]) => 标记<invoker>作用域中"data_deps"变量。
pool:
Pool 对象可以应用到一个可以限制构建并行性的工具上。
这个对象只有一个属性<depth>,它表示了可以同时运行的任务数量。
由于包含pool定义的文件可能会在多个工具链(toolchain)的上下文中执行,因此,当你在定义和引用一个pool对象的时候,推荐你显式的指定一个toolchain工具链。
在根构建文件中定义一个名为"console"的pool对象,这个对象就代表了Ninja的console pool。使用这个pool对象的目标(targets)都可以访问console的标准输入(stdin)和标准输出(stdout),这个特殊的pool必须有一个为1的depth值。
不是在root下面定义的pool对象不可以命名为"console"。
console pool 只能为默认的工具链(default_toolchain)定义。
pool对象可以像一个目标一样通过它自己的标签来被引用。
例子:
if (current_toolchain == default_toolchain) { pool("link_pool") { depth = 1 } } toolchain("toolchain") { tool("link") { command = "..." pool = ":link_pool($default_toolchain)" } }
print:
打印到控制台上面显示。主要用于debug。
例子:
print("Hello world") print(sources, deps)
process_file_template:
process_file_template(source_list, template)
用模板来处理文件。
source_list:
文件列表。
template:
模板列表。
返回结果就是每个模板处理的每个文件。
如果模板是一个列表,那么列表中的每个模板都会处理这个文件列表。也就是说,每个文件输入之后都会使用模板列表中的所有模板。
比较典型的用法就是根据输入文件来计算输出文件的名字。
与get_target_outputs()功能一样,在没有target或者target在别的构建文件中定义的时候就可以使用process_file_template()来处理。
模板可以使用源扩展(source expansion),用法查看 "gn help source_expansion"
例子:
sources = [ "foo.idl", "bar.idl", ] myoutputs = process_file_template( sources, [ "$target_gen_dir/{{source_name_part}}.cc", "$target_gen_dir/{{source_name_part}}.h" ]) The result in this case will be: [ "//out/Debug/foo.cc" "//out/Debug/foo.h" "//out/Debug/bar.cc" "//out/Debug/bar.h" ]
read_file:
read_file(filename, input_conversion)
把文件读入到一个变量中。如果文件不能打开就会出错。
filename:
要读的文件名称。
input_conversion:
控制文件怎么读和解析。
详解 gn help io_conversion
input_conversion / output_conversion 可能的值:
(
解释一下下面的用法,有的人可能看不太懂。就拿第二个用法来解释说明:
"list lines":
input:
output:
当<input>,也就是read_file中的<input_conversion>值为"list lines"时,对应的用法解释是 "input: "的内容。
当<output>,也就是write_file中的<output_conversion>值为"list lines"时,对应的用法解释是 "output: "的内容。
)
""(默认):
input: 忽略结果,返回None。
output: 如果值是一个列表就"list lines";否则 "value"。
"list lines":
input:
把文件内容作为列表返回,每行用一个string字符串表示。新行不会在结果中展示。
拆分好之后,把每行两端的空白字符去掉。
output:
把值的内容作为一个列表,每个string字符串为一行。新行不会在结果中展示。
最后一行要以新行结尾。
"scope":
input:
把这个块当作GN代码执行,将结果以scope的方式返回。
如果输入是: a = ["hello.cc", "world.cc"]; b = 26
把这个输入读到一个变量val中,那么就可以用"."的方式来读取内容:
sources = val.a ; some_count = val.b
output: 与上面相反。
"string":
input: 将文件内容放到一个string字符串中。
output:
将值的内容放进一个string字符串中。输出如下:
字符串用双引号: "str"
整数: "6"
布尔值: "true"
列表就显示内容: "[\"str\", 6]"
区块:
如果值是: Value val; val.a = ["hello.cc", "world.cc"]; val.b = 26
输出就是: a = [\"hello.cc\", \"world.cc\"]; b = 26
"value":
input:
输入 ["foo", "bar"] ,处理结果就是一个list列表。
输入 "foo bar", 处理结果就是一个string字符串。
输入 5,处理结果就是一个整数。
如果输入是空的,那么就会把null赋值给变量,这就会出错。
output: 把值内容作为文字形式的右值,字符串要转义双引号。
"json":
input: 将输入当作JSON对象,把它转换成等价的GN右值。
output: 将值转换成等价的JSON值。
数据类型映射:
JSON字符串 => GN字符串
JOSN证书 => GN 整数
JOSN浮点数 => GN不支持,会出错
JOSN对象 =>GN 区块 (也就是{}形式)
JOSN数组 => GN list表
JOSN布尔 => GN布尔
JOSN中的null => GN不支持,会出错误。
注意:输入的值需要是GN支持的类型,不然就会出错。
"trim ..." (只输入):
以"trim"为前缀的其它转换,在处理前都会被去掉空白字符。
例如: "trim string" 或者 "trim list lines"
"trim value"是没用的,因为value解析的时候会自动跳过空白字符
例子:
lines = read_file("foo.txt", "list lines")
rebase_path:
converted = rebase_path(input, new_base = "", current_base = ".")
把一个文件或者目录相对于另一个位置进行路径转换。
input:
代表文件或者目录的一个字符串或者字符串列表,这个参数可以是相对路径,绝对路径,或者源绝对路径(以"//"开头的路径)。
new_base:
要将路径转换为相对的目录,也就是要相对于<new_base>来转换路径,<new_base>就是新的参照路径。
可以是绝对路径或者相对路径(相对于当前build文件目录)
如果这个值是空的(默认值),那么所有路径都会转换为系统绝对路径(路径的格式取决于本地风格,windows风格?Linux风格?),这个对于调用外部程序是有用的。
current_base:
表示输入中相对路径的基的目录,也就是输入的文件或者目录名字目前是基于<current_base>而找到的。
如果不是绝对路径,它就会被当作相对于当前build文件而言。使用"."(默认值)从当前build文件目录去转换路径。
返回值类型和输入类型一样,要么是字符串,要么是字符串列表。所有相对和源绝对路径文件名都将被转换成相对于所请求的不会改变的输出系统绝对路径。
输入路径末尾有没有斜杠取决于输入的时候有还是没有,如果输入的时候路径末尾没有"/",那么输出的文件路径也不会有;如果输入的时候末尾有"/",那么输出的文件路径末尾也会有"/"。
例子:
# Convert a file in the current directory to be relative to the build # directory (the current dir when executing compilers and scripts). foo = rebase_path("myfile.txt", root_build_dir) # might produce "../../project/myfile.txt". # Convert a file to be system absolute: foo = rebase_path("myfile.txt") # Might produce "D:\\source\\project\\myfile.txt" on Windows or # "/home/you/source/project/myfile.txt" on Linux. # Typical usage for converting to the build directory for a script. action("myscript") { # Don't convert sources, GN will automatically convert these to be relative # to the build directory when it constructs the command line for your # script. sources = [ "foo.txt", "bar.txt" ] # Extra file args passed manually need to be explicitly converted # to be relative to the build directory: args = [ "--data", rebase_path("//mything/data/input.dat", root_build_dir), "--rel", rebase_path("relative_path.txt", root_build_dir) ] + rebase_path(sources, root_build_dir) }
set_default_toolchain:
set_default_toolchain(toolchain_label)
设置默认的工具链。
toolchain_label:
用来识别工具链的标签,由toolchain("mytoolchain")指定。
所有的目标都会默认只用这个toolchain,除非有的目标指定了别的。
例子:
# Set default toolchain only has an effect when run in the context of the # default toolchain. Pick the right one according to the current CPU # architecture. if (target_cpu == "x64") { set_default_toolchain("//toolchains:64") } else if (target_cpu == "x86") { set_default_toolchain("//toolchains:32") }
set_defaults:
set_defaults(<target_type_name>) { <values...> }
为目标类型设置默认值。
所有定义这种类型的地方都会把默认值拷贝进去。
比如:
set_defaults("static_library") { configs = [ "//tools/mything:settings" ] } static_library("mylib") { # 在这个静态库定义时就会把默认值拷贝到当前作用域 # The configs will be auto-populated as above. You can remove it if # you don't want the default for a particular default: configs -= [ "//tools/mything:settings" ] }
set_sources_assignment_filter:
设置一个模式(pattern)来过滤源文件。
如果传递一个[]空模式,那么就不会过滤。
set_sources_assignment_filter([])会清除过滤模式。
例子:
# Filter out all _win files. set_sources_assignment_filter([ "*_win.cc", "*_win.h" ]) sources = [ "a.cc", "b_win.cc" ] print(sources) # Will print [ "a.cc" ]. b_win one was filtered out.
split_list:
result = split_list(input, n)
把一个列表分割到不同的子列表中。
n表示将input分割成几个子列表,分割时会让每个列表大小差不多。
如果n大于input列表里面的元素个数,那么会填充空列表。
例子:
The code: mylist = [1, 2, 3, 4, 5, 6] print(split_list(mylist, 3)) Will print: [[1, 2], [3, 4], [5, 6]
string_join:
result = string_join(separator, strings)
用分隔符连接列表的字符串。
例子:
string_join("", ["a", "b", "c"]) --> "abc" string_join("|", ["a", "b", "c"]) --> "a|b|c" string_join(", ", ["a", "b", "c"]) --> "a, b, c" string_join("s", ["", ""]) --> "s"
string_replace:
result = string_replace(str, old, new[, max])
替换所给字符串中的子字符串。
例子:
The code: mystr = "Hello, world!" print(string_replace(mystr, "world", "GN")) Will print: Hello, GN!
string_split:
以指定分隔符将字符串分割到一个字符串列表中。
例子:
string_split("") --> [] string_split("a") --> ["a"] string_split(" aa bb") --> ["aa", "bb"]
string_split("", "|") --> [""] string_split(" a b ", " ") --> ["", "", "a", "b", "", ""] string_split("aa+-bb+-c", "+-") --> ["aa", "bb", "c"]
template:
定义模板。
模板定义了一个自定义名称,其作用类似于函数。
定义模板实例:
template("my_idl") { # Be nice and help callers debug problems by checking that the variables # the template requires are defined. This gives a nice message rather than # giving the user an error about an undefined variable in the file defining # the template # # You can also use defined() to give default values to variables # unspecified by the invoker. assert(defined(invoker.sources), "Need sources in $target_name listing the idl files.") # Name of the intermediate target that does the code gen. This must # incorporate the target name so it's unique across template # instantiations. code_gen_target_name = target_name + "_code_gen" # Intermediate target to convert IDL to C source. Note that the name is # based on the name the invoker of the template specified. This way, each # time the template is invoked we get a unique intermediate action name # (since all target names are in the global scope). action_foreach(code_gen_target_name) { # Access the scope defined by the invoker via the implicit "invoker" # variable. sources = invoker.sources # Note that we need an absolute path for our script file name. The # current directory when executing this code will be that of the invoker # (this is why we can use the "sources" directly above without having to # rebase all of the paths). But if we need to reference a script relative # to the template file, we'll need to use an absolute path instead. script = "//tools/idl/idl_code_generator.py" # Tell GN how to expand output names given the sources. # See "gn help source_expansion" for more. outputs = [ "$target_gen_dir/{{source_name_part}}.cc", "$target_gen_dir/{{source_name_part}}.h" ] } # Name the source set the same as the template invocation so instancing # this template produces something that other targets can link to in their # deps. source_set(target_name) { # Generates the list of sources, we get these from the action_foreach # above. sources = get_target_outputs(":$code_gen_target_name") # This target depends on the files produced by the above code gen target. deps = [ ":$code_gen_target_name" ] } }
调用模板实例:
# This calls the template code above, defining target_name to be # "foo_idl_files" and "invoker" to be the set of stuff defined in the curly # brackets. my_idl("foo_idl_files") { # Goes into the template as "invoker.sources". sources = [ "foo.idl", "bar.idl" ] } # Here is a target that depends on our template. executable("my_exe") { # Depend on the name we gave the template call above. Internally, this will # produce a dependency from executable to the source_set inside the # template (since it has this name), which will in turn depend on the code # gen action. deps = [ ":foo_idl_files" ] }
tool:
指定传递给工具链的参数。
用法:
tool(<tool type>) { <tool variables...> }
tool type:
Compiler tools: "cc": C compiler "cxx": C++ compiler "cxx_module": C++ compiler used for Clang .modulemap files "objc": Objective C compiler "objcxx": Objective C++ compiler "rc": Resource compiler (Windows .rc files) "asm": Assembler "swift": Swift compiler driver Linker tools: "alink": Linker for static libraries (archives) "solink": Linker for shared libraries "link": Linker for executables Other tools: "stamp": Tool for creating stamp files "copy": Tool to copy files. "action": Defaults for actions Platform specific tools: "copy_bundle_data": [iOS, macOS] Tool to copy files in a bundle. "compile_xcassets": [iOS, macOS] Tool to compile asset catalogs. Rust tools: "rust_bin": Tool for compiling Rust binaries "rust_cdylib": Tool for compiling C-compatible dynamic libraries. "rust_dylib": Tool for compiling Rust dynamic libraries. "rust_macro": Tool for compiling Rust procedural macros. "rust_rlib": Tool for compiling Rust libraries. "rust_staticlib": Tool for compiling Rust static libraries.
tool variables:
command [string with substitutions] Valid for: all tools except "action" (required) The command to run. command_launcher [string] Valid for: all tools except "action" (optional) The prefix with which to launch the command (e.g. the path to a Goma or CCache compiler launcher). Note that this prefix will not be included in the compilation database or IDE files generated from the build. default_output_dir [string with substitutions] Valid for: linker tools Default directory name for the output file relative to the root_build_dir. It can contain other substitution patterns. This will be the default value for the {{output_dir}} expansion (discussed below) but will be overridden by the "output_dir" variable in a target, if one is specified. GN doesn't do anything with this string other than pass it along, potentially with target-specific overrides. It is the tool's job to use the expansion so that the files will be in the right place. default_output_extension [string] Valid for: linker tools Extension for the main output of a linkable tool. It includes the leading dot. This will be the default value for the {{output_extension}} expansion (discussed below) but will be overridden by by the "output extension" variable in a target, if one is specified. Empty string means no extension. GN doesn't actually do anything with this extension other than pass it along, potentially with target-specific overrides. One would typically use the {{output_extension}} value in the "outputs" to read this value. Example: default_output_extension = ".exe" depfile [string with substitutions] Valid for: compiler tools (optional) If the tool can write ".d" files, this specifies the name of the resulting file. These files are used to list header file dependencies (or other implicit input dependencies) that are discovered at build time. See also "depsformat". Example: depfile = "{{output}}.d" depsformat [string] Valid for: compiler tools (when depfile is specified) Format for the deps outputs. This is either "gcc" or "msvc". See the ninja documentation for "deps" for more information. Example: depsformat = "gcc" description [string with substitutions, optional] Valid for: all tools What to print when the command is run. Example: description = "Compiling {{source}}" exe_output_extension [string, optional, rust tools only] rlib_output_extension [string, optional, rust tools only] dylib_output_extension [string, optional, rust tools only] cdylib_output_extension [string, optional, rust tools only] rust_proc_macro_output_extension [string, optional, rust tools only] Valid for: Rust tools These specify the default tool output for each of the crate types. The default is empty for executables, shared, and static libraries and ".rlib" for rlibs. Note that the Rust compiler complains with an error if external crates do not take the form `lib<name>.rlib` or `lib<name>.<shared_extension>`, where `<shared_extension>` is `.so`, `.dylib`, or `.dll` as appropriate for the platform. lib_switch [string, optional, link tools only] lib_dir_switch [string, optional, link tools only] Valid for: Linker tools except "alink" These strings will be prepended to the libraries and library search directories, respectively, because linkers differ on how to specify them. If you specified: lib_switch = "-l" lib_dir_switch = "-L" then the "{{libs}}" expansion for [ "freetype", "expat" ] would be "-lfreetype -lexpat". framework_switch [string, optional, link tools only] weak_framework_switch [string, optional, link tools only] framework_dir_switch [string, optional, link tools only] Valid for: Linker tools These strings will be prepended to the frameworks and framework search path directories, respectively, because linkers differ on how to specify them. If you specified: framework_switch = "-framework " weak_framework_switch = "-weak_framework " framework_dir_switch = "-F" and: framework_dirs = [ "$root_out_dir" ] frameworks = [ "UIKit.framework", "Foo.framework" ] weak_frameworks = [ "MediaPlayer.framework" ] would be: "-F. -framework UIKit -framework Foo -weak_framework MediaPlayer" swiftmodule_switch [string, optional, link tools only] Valid for: Linker tools except "alink" The string will be prependend to the path to the .swiftmodule files that are embedded in the linker output. If you specified: swiftmodule_swift = "-Wl,-add_ast_path," then the "{{swiftmodules}}" expansion for [ "obj/foo/Foo.swiftmodule" ] would be "-Wl,-add_ast_path,obj/foo/Foo.swiftmodule" outputs [list of strings with substitutions] Valid for: Linker and compiler tools (required) An array of names for the output files the tool produces. These are relative to the build output directory. There must always be at least one output file. There can be more than one output (a linker might produce a library and an import library, for example). This array just declares to GN what files the tool will produce. It is your responsibility to specify the tool command that actually produces these files. If you specify more than one output for shared library links, you should consider setting link_output, depend_output, and runtime_outputs. Example for a compiler tool that produces .obj files: outputs = [ "{{source_out_dir}}/{{source_name_part}}.obj" ] Example for a linker tool that produces a .dll and a .lib. The use of {{target_output_name}}, {{output_extension}} and {{output_dir}} allows the target to override these values. outputs = [ "{{output_dir}}/{{target_output_name}}" "{{output_extension}}", "{{output_dir}}/{{target_output_name}}.lib", ] partial_outputs [list of strings with substitutions] Valid for: "swift" only An array of names for the partial outputs the tool produces. These are relative to the build output directory. The expansion will be evaluated for each file listed in the "sources" of the target. This is used to deal with whole module optimization, allowing to list one object file per source file when whole module optimization is disabled. pool [label, optional] Valid for: all tools (optional) Label of the pool to use for the tool. Pools are used to limit the number of tasks that can execute concurrently during the build. See also "gn help pool". link_output [string with substitutions] depend_output [string with substitutions] Valid for: "solink" only (optional) These two files specify which of the outputs from the solink tool should be used for linking and dependency tracking. These should match entries in the "outputs". If unspecified, the first item in the "outputs" array will be used for all. See "Separate linking and dependencies for shared libraries" below for more. On Windows, where the tools produce a .dll shared library and a .lib import library, you will want the first two to be the import library and the third one to be the .dll file. On Linux, if you're not doing the separate linking/dependency optimization, all of these should be the .so output. output_prefix [string] Valid for: Linker tools (optional) Prefix to use for the output name. Defaults to empty. This prefix will be prepended to the name of the target (or the output_name if one is manually specified for it) if the prefix is not already there. The result will show up in the {{output_name}} substitution pattern. Individual targets can opt-out of the output prefix by setting: output_prefix_override = true (see "gn help output_prefix_override"). This is typically used to prepend "lib" to libraries on Posix systems: output_prefix = "lib" precompiled_header_type [string] Valid for: "cc", "cxx", "objc", "objcxx" Type of precompiled headers. If undefined or the empty string, precompiled headers will not be used for this tool. Otherwise use "gcc" or "msvc". For precompiled headers to be used for a given target, the target (or a config applied to it) must also specify a "precompiled_header" and, for "msvc"-style headers, a "precompiled_source" value. If the type is "gcc", then both "precompiled_header" and "precompiled_source" must resolve to the same file, despite the different formats required for each." See "gn help precompiled_header" for more. restat [boolean] Valid for: all tools (optional, defaults to false) Requests that Ninja check the file timestamp after this tool has run to determine if anything changed. Set this if your tool has the ability to skip writing output if the output file has not changed. Normally, Ninja will assume that when a tool runs the output be new and downstream dependents must be rebuild. When this is set to trye, Ninja can skip rebuilding downstream dependents for input changes that don't actually affect the output. Example: restat = true rspfile [string with substitutions] Valid for: all tools except "action" (optional) Name of the response file. If empty, no response file will be used. See "rspfile_content". rspfile_content [string with substitutions] Valid for: all tools except "action" (required when "rspfile" is used) The contents to be written to the response file. This may include all or part of the command to send to the tool which allows you to get around OS command-line length limits. This example adds the inputs and libraries to a response file, but passes the linker flags directly on the command line: tool("link") { command = "link -o {{output}} {{ldflags}} @{{output}}.rsp" rspfile = "{{output}}.rsp" rspfile_content = "{{inputs}} {{solibs}} {{libs}} {{rlibs}}" } runtime_outputs [string list with substitutions] Valid for: linker tools If specified, this list is the subset of the outputs that should be added to runtime deps (see "gn help runtime_deps"). By default (if runtime_outputs is empty or unspecified), it will be the link_output.
tool variables 扩展:
All paths are relative to the root build directory, which is the current directory for running all tools. These expansions are available to all tools: {{label}} The label of the current target. This is typically used in the "description" field for link tools. The toolchain will be omitted from the label for targets in the default toolchain, and will be included for targets in other toolchains. {{label_name}} The short name of the label of the target. This is the part after the colon. For "//foo/bar:baz" this will be "baz". Unlike {{target_output_name}}, this is not affected by the "output_prefix" in the tool or the "output_name" set on the target. {{label_no_toolchain}} The label of the current target, never including the toolchain (otherwise, this is identical to {{label}}). This is used as the module name when using .modulemap files. {{output}} The relative path and name of the output(s) of the current build step. If there is more than one output, this will expand to a list of all of them. Example: "out/base/my_file.o" {{target_gen_dir}} {{target_out_dir}} The directory of the generated file and output directories, respectively, for the current target. There is no trailing slash. See also {{output_dir}} for linker tools. Example: "out/base/test" {{target_output_name}} The short name of the current target with no path information, or the value of the "output_name" variable if one is specified in the target. This will include the "output_prefix" if any. See also {{label_name}}. Example: "libfoo" for the target named "foo" and an output prefix for the linker tool of "lib". Compiler tools have the notion of a single input and a single output, along with a set of compiler-specific flags. The following expansions are available: {{asmflags}} {{cflags}} {{cflags_c}} {{cflags_cc}} {{cflags_objc}} {{cflags_objcc}} {{defines}} {{include_dirs}} Strings correspond that to the processed flags/defines/include directories specified for the target. Example: "--enable-foo --enable-bar" Defines will be prefixed by "-D" and include directories will be prefixed by "-I" (these work with Posix tools as well as Microsoft ones). {{module_deps}} {{module_deps_no_self}} Strings that correspond to the flags necessary to depend upon the Clang modules referenced by the current target. The "_no_self" version doesn't include the module for the current target, and can be used to compile the pcm itself. {{source}} The relative path and name of the current input file. Example: "../../base/my_file.cc" {{source_file_part}} The file part of the source including the extension (with no directory information). Example: "foo.cc" {{source_name_part}} The filename part of the source file with no directory or extension. Example: "foo" {{source_gen_dir}} {{source_out_dir}} The directory in the generated file and output directories, respectively, for the current input file. If the source file is in the same directory as the target is declared in, they will will be the same as the "target" versions above. Example: "gen/base/test" Linker tools have multiple inputs and (potentially) multiple outputs. The static library tool ("alink") is not considered a linker tool. The following expansions are available: {{inputs}} {{inputs_newline}} Expands to the inputs to the link step. This will be a list of object files and static libraries. Example: "obj/foo.o obj/bar.o obj/somelibrary.a" The "_newline" version will separate the input files with newlines instead of spaces. This is useful in response files: some linkers can take a "-filelist" flag which expects newline separated files, and some Microsoft tools have a fixed-sized buffer for parsing each line of a response file. {{ldflags}} Expands to the processed set of ldflags and library search paths specified for the target. Example: "-m64 -fPIC -pthread -L/usr/local/mylib" {{libs}} Expands to the list of system libraries to link to. Each will be prefixed by the "lib_switch". Example: "-lfoo -lbar" {{output_dir}} The value of the "output_dir" variable in the target, or the the value of the "default_output_dir" value in the tool if the target does not override the output directory. This will be relative to the root_build_dir and will not end in a slash. Will be "." for output to the root_build_dir. This is subtly different than {{target_out_dir}} which is defined by GN based on the target's path and not overridable. {{output_dir}} is for the final output, {{target_out_dir}} is generally for object files and other outputs. Usually {{output_dir}} would be defined in terms of either {{target_out_dir}} or {{root_out_dir}} {{output_extension}} The value of the "output_extension" variable in the target, or the value of the "default_output_extension" value in the tool if the target does not specify an output extension. Example: ".so" {{solibs}} Extra libraries from shared library dependencies not specified in the {{inputs}}. This is the list of link_output files from shared libraries (if the solink tool specifies a "link_output" variable separate from the "depend_output"). These should generally be treated the same as libs by your tool. Example: "libfoo.so libbar.so" {{rlibs}} Any Rust .rlibs which need to be linked into a final C++ target. These should be treated as {{inputs}} except that sometimes they might have different linker directives applied. Example: "obj/foo/libfoo.rlib" {{frameworks}} Shared libraries packaged as framework bundle. This is principally used on Apple's platforms (macOS and iOS). All name must be ending with ".framework" suffix; the suffix will be stripped when expanding {{frameworks}} and each item will be preceded by "-framework" or "-weak_framework". {{swiftmodules}} Swift .swiftmodule files that needs to be embedded into the binary. This is necessary to correctly link with object generated by the Swift compiler (the .swiftmodule file cannot be embedded in object files directly). Those will be prefixed with "swiftmodule_switch" value. The static library ("alink") tool allows {{arflags}} plus the common tool substitutions. The copy tool allows the common compiler/linker substitutions, plus {{source}} which is the source of the copy. The stamp tool allows only the common tool substitutions. The copy_bundle_data and compile_xcassets tools only allows the common tool substitutions. Both tools are required to create iOS/macOS bundles and need only be defined on those platforms. The copy_bundle_data tool will be called with one source and needs to copy (optionally optimizing the data representation) to its output. It may be called with a directory as input and it needs to be recursively copied. The compile_xcassets tool will be called with one or more source (each an asset catalog) that needs to be compiled to a single output. The following substitutions are available: {{inputs}} Expands to the list of .xcassets to use as input to compile the asset catalog. {{bundle_product_type}} Expands to the product_type of the bundle that will contain the compiled asset catalog. Usually corresponds to the product_type property of the corresponding create_bundle target. {{bundle_partial_info_plist}} Expands to the path to the partial Info.plist generated by the assets catalog compiler. Usually based on the target_name of the create_bundle target. {{xcasset_compiler_flags}} Expands to the list of flags specified in corresponding create_bundle target. The Swift tool has multiple input and outputs. It must have exactly one output of .swiftmodule type, but can have one or more object file outputs, in addition to other type of ouputs. The following expansions are available: {{module_name}} Expands to the string representing the module name of target under compilation (see "module_name" variable). {{module_dirs}} Expands to the list of -I<path> for the target Swift module search path computed from target dependencies. {{swiftflags}} Expands to the list of strings representing Swift compiler flags. Rust tools have the notion of a single input and a single output, along with a set of compiler-specific flags. The following expansions are available: {{crate_name}} Expands to the string representing the crate name of target under compilation. {{crate_type}} Expands to the string representing the type of crate for the target under compilation. {{externs}} Expands to the list of --extern flags needed to include addition Rust libraries in this target. Includes any specified renamed dependencies. {{rustdeps}} Expands to the list of -Ldependency=<path> strings needed to compile this target. {{rustenv}} Expands to the list of environment variables. {{rustflags}} Expands to the list of strings representing Rust compiler flags.
例子:
All paths are relative to the root build directory, which is the current directory for running all tools. These expansions are available to all tools: {{label}} The label of the current target. This is typically used in the "description" field for link tools. The toolchain will be omitted from the label for targets in the default toolchain, and will be included for targets in other toolchains. {{label_name}} The short name of the label of the target. This is the part after the colon. For "//foo/bar:baz" this will be "baz". Unlike {{target_output_name}}, this is not affected by the "output_prefix" in the tool or the "output_name" set on the target. {{label_no_toolchain}} The label of the current target, never including the toolchain (otherwise, this is identical to {{label}}). This is used as the module name when using .modulemap files. {{output}} The relative path and name of the output(s) of the current build step. If there is more than one output, this will expand to a list of all of them. Example: "out/base/my_file.o" {{target_gen_dir}} {{target_out_dir}} The directory of the generated file and output directories, respectively, for the current target. There is no trailing slash. See also {{output_dir}} for linker tools. Example: "out/base/test" {{target_output_name}} The short name of the current target with no path information, or the value of the "output_name" variable if one is specified in the target. This will include the "output_prefix" if any. See also {{label_name}}. Example: "libfoo" for the target named "foo" and an output prefix for the linker tool of "lib". Compiler tools have the notion of a single input and a single output, along with a set of compiler-specific flags. The following expansions are available: {{asmflags}} {{cflags}} {{cflags_c}} {{cflags_cc}} {{cflags_objc}} {{cflags_objcc}} {{defines}} {{include_dirs}} Strings correspond that to the processed flags/defines/include directories specified for the target. Example: "--enable-foo --enable-bar" Defines will be prefixed by "-D" and include directories will be prefixed by "-I" (these work with Posix tools as well as Microsoft ones). {{module_deps}} {{module_deps_no_self}} Strings that correspond to the flags necessary to depend upon the Clang modules referenced by the current target. The "_no_self" version doesn't include the module for the current target, and can be used to compile the pcm itself. {{source}} The relative path and name of the current input file. Example: "../../base/my_file.cc" {{source_file_part}} The file part of the source including the extension (with no directory information). Example: "foo.cc" {{source_name_part}} The filename part of the source file with no directory or extension. Example: "foo" {{source_gen_dir}} {{source_out_dir}} The directory in the generated file and output directories, respectively, for the current input file. If the source file is in the same directory as the target is declared in, they will will be the same as the "target" versions above. Example: "gen/base/test" Linker tools have multiple inputs and (potentially) multiple outputs. The static library tool ("alink") is not considered a linker tool. The following expansions are available: {{inputs}} {{inputs_newline}} Expands to the inputs to the link step. This will be a list of object files and static libraries. Example: "obj/foo.o obj/bar.o obj/somelibrary.a" The "_newline" version will separate the input files with newlines instead of spaces. This is useful in response files: some linkers can take a "-filelist" flag which expects newline separated files, and some Microsoft tools have a fixed-sized buffer for parsing each line of a response file. {{ldflags}} Expands to the processed set of ldflags and library search paths specified for the target. Example: "-m64 -fPIC -pthread -L/usr/local/mylib" {{libs}} Expands to the list of system libraries to link to. Each will be prefixed by the "lib_switch". Example: "-lfoo -lbar" {{output_dir}} The value of the "output_dir" variable in the target, or the the value of the "default_output_dir" value in the tool if the target does not override the output directory. This will be relative to the root_build_dir and will not end in a slash. Will be "." for output to the root_build_dir. This is subtly different than {{target_out_dir}} which is defined by GN based on the target's path and not overridable. {{output_dir}} is for the final output, {{target_out_dir}} is generally for object files and other outputs. Usually {{output_dir}} would be defined in terms of either {{target_out_dir}} or {{root_out_dir}} {{output_extension}} The value of the "output_extension" variable in the target, or the value of the "default_output_extension" value in the tool if the target does not specify an output extension. Example: ".so" {{solibs}} Extra libraries from shared library dependencies not specified in the {{inputs}}. This is the list of link_output files from shared libraries (if the solink tool specifies a "link_output" variable separate from the "depend_output"). These should generally be treated the same as libs by your tool. Example: "libfoo.so libbar.so" {{rlibs}} Any Rust .rlibs which need to be linked into a final C++ target. These should be treated as {{inputs}} except that sometimes they might have different linker directives applied. Example: "obj/foo/libfoo.rlib" {{frameworks}} Shared libraries packaged as framework bundle. This is principally used on Apple's platforms (macOS and iOS). All name must be ending with ".framework" suffix; the suffix will be stripped when expanding {{frameworks}} and each item will be preceded by "-framework" or "-weak_framework". {{swiftmodules}} Swift .swiftmodule files that needs to be embedded into the binary. This is necessary to correctly link with object generated by the Swift compiler (the .swiftmodule file cannot be embedded in object files directly). Those will be prefixed with "swiftmodule_switch" value. The static library ("alink") tool allows {{arflags}} plus the common tool substitutions. The copy tool allows the common compiler/linker substitutions, plus {{source}} which is the source of the copy. The stamp tool allows only the common tool substitutions. The copy_bundle_data and compile_xcassets tools only allows the common tool substitutions. Both tools are required to create iOS/macOS bundles and need only be defined on those platforms. The copy_bundle_data tool will be called with one source and needs to copy (optionally optimizing the data representation) to its output. It may be called with a directory as input and it needs to be recursively copied. The compile_xcassets tool will be called with one or more source (each an asset catalog) that needs to be compiled to a single output. The following substitutions are available: {{inputs}} Expands to the list of .xcassets to use as input to compile the asset catalog. {{bundle_product_type}} Expands to the product_type of the bundle that will contain the compiled asset catalog. Usually corresponds to the product_type property of the corresponding create_bundle target. {{bundle_partial_info_plist}} Expands to the path to the partial Info.plist generated by the assets catalog compiler. Usually based on the target_name of the create_bundle target. {{xcasset_compiler_flags}} Expands to the list of flags specified in corresponding create_bundle target. The Swift tool has multiple input and outputs. It must have exactly one output of .swiftmodule type, but can have one or more object file outputs, in addition to other type of ouputs. The following expansions are available: {{module_name}} Expands to the string representing the module name of target under compilation (see "module_name" variable). {{module_dirs}} Expands to the list of -I<path> for the target Swift module search path computed from target dependencies. {{swiftflags}} Expands to the list of strings representing Swift compiler flags. Rust tools have the notion of a single input and a single output, along with a set of compiler-specific flags. The following expansions are available: {{crate_name}} Expands to the string representing the crate name of target under compilation. {{crate_type}} Expands to the string representing the type of crate for the target under compilation. {{externs}} Expands to the list of --extern flags needed to include addition Rust libraries in this target. Includes any specified renamed dependencies. {{rustdeps}} Expands to the list of -Ldependency=<path> strings needed to compile this target. {{rustenv}} Expands to the list of environment variables. {{rustflags}} Expands to the list of strings representing Rust compiler flags.
toolchain:
定义一个工具链。
工具链是一个用来编译源代码的命令和构建标志的集合。toolchaind()函数可以定义这些命令。
函数和变量:
tool():
这个函数调用指定为给定步骤运行的命令。使用方面看上面 ↑
toolchain_args[scope]:
调用工具链时覆盖要传递给工具链的构建参数。这是一个"scope"类型的变量,里面的变量名要和declare_args()中相对应。
当你指定一个使用替代工具链的目标时,主构建配置文件将在该工具链的上下文中重新解释。toolchain_args允许您控制传递到构建的这个备用调用中的参数。
任何默认的系统参数或通过“gn args”传入的参数也将被传递给备用调用,除非被toolchain_args显式覆盖。
当工具链被定义为默认的时候,toolchain_args就会被忽略。
propagates_configs [boolean, default=false]:
确定这个工具链中的public_configs和all_dependent_configs是否传播到其他工具链中的目标。false, 不能传;true,可以传。
deps[string list]:
这个工具链的依赖。在任何使用这个工具链编译的目标之前,依赖都会被解决。为了避免循环依赖,这些必须是在另一个工具链中定义的目标。
这是一个目标列表,通常这些目标会指定一个工具链:
deps = [ "//foo/bar:baz(//build/toolchain:bootstrap)" ]
工具链定义实例:
toolchain("32") { tool("cc") { command = "gcc {{source}}" ... } toolchain_args = { use_doom_melon = true # Doom melon always required for 32-bit builds. current_cpu = "x86" } } toolchain("64") { tool("cc") { command = "gcc {{source}}" ... } toolchain_args = { # use_doom_melon is not overridden here, it will take the default. current_cpu = "x64" } }
交叉工具链依赖实例:
If a 64-bit target wants to depend on a 32-bit binary, it would specify a dependency using data_deps (data deps are like deps that are only needed at runtime and aren't linked, since you can't link a 32-bit and a 64-bit library). executable("my_program") { ... if (target_cpu == "x64") { # The 64-bit build needs this 32-bit helper. data_deps = [ ":helper(//toolchains:32)" ] } } if (target_cpu == "x86") { # Our helper library is only compiled in 32-bits. shared_library("helper") { ... } }
write_file:
write_file(filename, data, output_conversion = "")
写一个文件到磁盘。
filename: 要写的文件名。
data:要写的数据。
output_conversion: 写入的方式。 查看上面read_file里面关于 io_conversion详解。
内置预定义变量
current_cpu: 当前工具链处理器架构
current_os:
current_toolchain:
default_toolchain:
gn_version:
host_cpu:
host_os:
invoker: 可以在模板中使用,用它可以访问调用模板的目标的所有变量。
例子:
template("my_template") { print(invoker.sources) # Prints [ "a.cc", "b.cc" ] print(defined(invoker.foo)) # Prints false. print(defined(invoker.bar)) # Prints true. } my_template("doom_melon") { sources = [ "a.cc", "b.cc" ] bar = 123 }
在模板中直接用invoker就可以访问到 "my_template("doom_melon")" 中定义的所有变量。
python_path:
root_build_dir: build命令运行的目录。
root_gen_dir: 工具链生成中间文件的路径。
root_out_dir: 工具链输出文件的根目录。
target_cpu:
target_gen_dir:
target_name: 当前target的名字。
在模板中使用需要注意,并不是模板的名字。
executable("doom_melon") { print(target_name) # Prints "doom_melon". } template("my_template") { # 这个是模板的名字 print(target_name) # Prints "space_ray" when invoked below. executable(target_name + "_impl") { print(target_name) # Prints "space_ray_impl". } } my_template("space_ray") { # 这个才是target的名字,是用模板生成"space_ray"这个target。 }
target_os:
target_out_dir: targets的输出目录。
在target中可以设置的变量:
all_dependent_configs:
config的列表。
这个变量中列出的config会被强制应用到当前target,以及依赖当前target的target中,也会传递下去。
比如 target A 中设置了这个值,而B依赖A, C依赖B, D依赖C,这么B, C, D都会被应用这个变量所指定的config。
这个变量指定的config的传递,不需要看是私有依赖(deps),还是公有依赖(public_deps)。
只有当一个目标和它所有的依赖项都被解释后,也就是先把依赖关系问题解决好,才会添加这个变量,才知道该给哪些依赖项添加这个变量,因此,通常这个变量的配置应该是包含的 defines 和 编译目标所需要的头文件include目录。
值(values)和标志(flags)的排序:
- 直接在当前目标中设置的。(不是在配置里面的)
- "configs"这个变量中指定的配置,按照"configs"列表中config出现的顺序。
- 当前目标的"all_dependent_configs"变量中指定的配置,按照这个变量中config的顺序。
- 当前目标的"public_configs"变量中指定的配置,按照这个变量中config的顺序。
- 当前目标的依赖项中的"all_dependent_configs"变量中指定的配置,按照这个变量中config的顺序。
- 当前目标的依赖项中"public_configs"变量中指定的配置,按照这个变量中config的顺序。
allow_circular_includes_from:
允许循环依赖。也就是可以互相引入对方的头文件。
详解:
目标A引用了一个目标B中的文件,那么A就必须把B作为依赖项。
而有时候B也需要引用A中的头文件,这种情况有时候是无法避免的,那么就可以使用这个变量。
将B放入这个变量中即可。用法就是这样,当前目标允许它的哪些依赖项可以引用它的文件,那么就把那些依赖性放到这个变量列表中。
可以把公共依赖的目标放入<group>中。也就是如果A依赖于C,B依赖于C,就把C放入<group>中。
例子:
source_set("a") { deps = [ ":b", ":a_b_shared_deps" ] allow_circular_includes_from = [ ":b" ] ... } source_set("b") { deps = [ ":a_b_shared_deps" ] # Sources here can include headers from a despite lack of deps. ... } group("a_b_shared_deps") { public_deps = [ ":c" ] }
arflags:
一个flags列表,可以传递给创建静态库的命令,用以生成静态库。
args:
传递给<action>的参数。
asmflags:
如果一个tool把 .asm或者.S 文件作为输入参数,那么"asmflags"就会被传递给这个tool。
assert_no_deps:
标签模式列表。 确保这些目标标签没有依赖项。
例子:
executable("doom_melon") { deps = [ "//foo:bar" ] ... assert_no_deps = [ "//evil/*", # Don't link any code from the evil directory. 不使用该目录下的任何code,也就是不依赖这个目录下的任何东西。 "//foo:test_support", # This target is also disallowed. ] }
bridge_header: [string] Path to C/Objective-C compatibility header.
cflags*: Flags passed to the C compiler.
cflags
cflags_c => 传递个C编译器
cflags_cc => C++
cflags_objc => objc
cflags_objcc => objc++
check_includes:
是个布尔值。
false:不检查目标中的文件。(#include 引入的文件)
true: 检查目标中的文件。
例子:
source_set("busted_includes") { # This target's includes are messed up, exclude it from checking. check_includes = false ... }
code_signing_args: [string list] Arguments passed to code signing script.
code_signing_outputs: [file list] Output files for code signing step.
code_signing_script: [file name] Script for code signing."
code_signing_sources: [file list] Sources for code signing step.
complete_static_lib:
将所有依赖链接到一个静态库中。
正常情况下静态库是不会包括来自依赖项的代码,但是它会沿着依赖链转发那些静态库和源集合(<source_set>),直到它遇到一个可链接(例如 可执行目标(executable),共享库(shared library))的目标。
最终的可链接目标只会链接一次静态库,即使这个库在依赖中出现了多次。
在某些情况下,静态库可能是最终所需的输出。比如:你可能正在生成一个用于分发给第三方的静态库。
在这种情况下,静态库应该在一个完整包中包含所有依赖项的代码。然而,完整的静态库本身永远不会链接到其他完整的静态库中。所有完整的静态库都是用于分发的,在这种情况下,链接它们会导致代码重复。如果静态库不是用于分发的,那么它就不应该是完整的。
当非完全静态库被链接到完全静态库的时候,GN会把非完全静态库当作一个源集合。之所以这样做,是因为像AR这样的一些工具不能正确地处理依赖的静态库。这使得编写“alink”规则变得更容易。
例子:
static_library("foo") { complete_static_lib = true deps = [ "bar" ] }
configs:
应用于目标上的配置,或者可以在<config>中使用。
<configs>在目标中使用:
<config>中可以包含<include_dirs> <defines>等等,配置中的这些变量会在当前target中直接定义的相同变量之后出现。
可以查看上面在讲解<all_dependent_configs>用法时有个排序的讲解。对于target而言,它会先用自己直接定义的变量。
<configs>在<config>中使用:
可以在<config>中指定<configs>,形成复合配置。
例子:
# Configs on a target. source_set("foo") { # Don't use the default RTTI config that BUILDCONFIG applied to us. configs -= [ "//build:no_rtti" ] # Add some of our own settings. configs += [ ":mysettings" ] } # Create a default_optimization config that forwards to one of a set of more # specialized configs depending on build flags. This pattern is useful # because it allows a target to opt in to either a default set, or a more # specific set, while avoid duplicating the settings in two places. config("super_optimization") { cflags = [ ... ] } config("default_optimization") { if (optimize_everything) { configs = [ ":super_optimization" ] } else { configs = [ ":no_optimization" ] } }
contents: 要写入文件的内容
<generated_file>目标的文件内容。可以查看<generated_file>的用法。
data:
运行时数据文件依赖。
data_deps: Non-linked dependencies.
通常使用是为了plugins或者目标在运行时需要用到的helper程序。
例子:
executable("foo") { deps = [ "//base" ] data_deps = [ "//plugins:my_runtime_plugin" ] }
data_keys: Keys from which to collect metadata.
defines:
定义的变量会被C编译器使用,类似于C语言的#defines。
可以为C/C++文件定义宏,如果有需要可以用"="为变量赋值。
例如:
defines = [ "AWESOME_FEATURE", "LOG_LEVEL=3" ]
depfile: [string] File name for input dependencies for actions.
为<action> <action_foreach>使用,这两个行为的输入项的依赖项。
<action> 或者 <action_foreach>会生成 ".d" 后缀的文件,这个文件包含了输入项的依赖项。
文件的格式就是makefile的格式。
例子:
action_foreach("myscript_target") { script = "myscript.py" sources = [ ... ] # Locate the depfile in the output directory named like the # inputs but with a ".d" appended. depfile = "$relative_target_output_dir/{{source_name}}.d" # Say our script uses "-o <d file>" to indicate the depfile. args = [ "{{source}}", "-o", depfile ] }
deps: 私有依赖
不能从依赖中#include头文件,公开配置也无法被传递。
Details of dependency propagation 依赖性传递详解
Source sets, shared libraries, and non-complete static libraries will be propagated up the dependency tree across groups, non-complete static libraries and source sets. Executables, shared libraries, and complete static libraries will link all propagated targets and stop propagation. Actions and copy steps also stop propagation, allowing them to take a library as an input but not force dependents to link to it. Propagation of all_dependent_configs and public_configs happens independently of target type. all_dependent_configs are always propagated across all types of targets, and public_configs are always propagated across public deps of all types of targets. Data dependencies are propagated differently. See "gn help data_deps" and "gn help runtime_deps". See also "public_deps".
friend: 允许目标包含私有头文件
正常情况,当一个目标中把一些头文件放进了 "public"列表里,那么其余的头文件就被隐性的认为是私有的(private),而其它目标是不可以包含私有头文件的,即使你是公共继承的。
<friend>的声明就可以让一个或者多个目标包含私有头文件。
而没有依赖关系的目标依旧是不可以包含私有头文件的。
<friend>无法在依赖直接被传递,也不影响<visibility>。
例子:
static_library("lib") { # This target can include our private headers. friend = [ ":unit_tests" ] public = [ "public_api.h", # Normal public API for dependent targets. ] # Private API and sources. sources = [ "a_source_file.cc", # Normal targets that depend on this one won't be able to include this # because this target defines a list of "public" headers. Without the # "public" list, all headers are implicitly public. "private_api.h", ] } executable("unit_tests") { sources = [ # This can include "private_api.h" from the :lib target because it # depends on that target and because of the friend annotation. "my_test.cc", ] deps = [ ":lib", # Required for the include to be allowed. ] }
include_dirs:
目标引用头文件的搜索路径。会在这写目录下面查找要使用的头文件。
例子:
include_dirs = [ "src/include", "//third_party/foo" ]
inputs: Additional compile-time dependencies.
通常只用于<action>和<action_foreach>
ldflags: 传给链接器的标志
大部分目标不需要使用这个,相反地,会使用<libs> 和 <lib_dirs>。
<lfflags>不会被推给依赖项,因此把这个标志传递给<source_set>和<static_library>是不可行的。
如果你想把这个标志传递给依赖项,你可以把它放在<config>中,然后把<config>放入<all_dependent_configs> 或者<public_configs>中。
lib_dirs:
用于链接器搜索所需要的库的路径。
如果不是绝对路径,那么就会被转换成相对于当前build文件的路径。
例子:
lib_dirs = [ "/usr/lib/foo", "lib/doom_melon" ]
libs:
其它要链接的库。
<libs>的类型:
文件路径:
包含"/"的值将被当作对文件的引用。
那些在构建中生成的库,就用GN的依赖方式来使用它们。
系统库:
不包含"/"的值会被当作系统库名字。这些值会不做任何修改与"lib_switch"属性作为前缀直接传给链接器。
通常你要设置<lib_dirs>为了这些库可以被找到。
在你的BUILD.gn文件中不应该指定switch(像"-l"这样的): 这将被编码在<tool>的<lib_switch>中。
例子:
On Windows: libs = [ "ctl3d.lib" ] On Linux: libs = [ "ld" ]
output_conversion:
<generated_file>目标的数据格式。
output_dir:
要放入输出文件的目录。
最后的输出通常会在<root_out_dir>或者其子目录下。
如果这个变量未定义或者是空值,那么就会使用默认的位置。
一般toolchain都会为库和可执行文件指定好输出目录。
例子:
shared_library("doom_melon") { output_dir = "$root_out_dir/plugin_libs" ... }
output_extension:
输出文件的扩展名。
通常情况下,一个目标的扩展名取决于目标的类型和操作系统,但是极少情况下你需要重写这个扩展名。
比如在Linux系统上,用 "libfreetype.so.6"代替 "libfreetype.so"
这个值不应该以"."开头。如果未定义,那么就会使用<tool>定义的默认值。如果设置成空,就表示没有扩展名要用。
这个变量值将会用来设置"{{output_extension}}"。
例子:
shared_library("freetype") { if (is_linux) { # Call the output "libfreetype.so.6" output_extension = "so.6" } ... } # On Windows, generate a "mysettings.cpl" control panel applet. Control panel # applets are actually special shared libraries. if (is_win) { shared_library("mysettings") { output_extension = "cpl" ... } }
output_name:
为输出文件定义一个名字,而不是默认名称。
通常一个目标的输出文件名是基于目标的名字的,因此目标"//foo/bar:bar_unittests"将会生成一个"bar_unittests.exe"的输出文件。(在Windows平台上)
输出文件的名字不应该有扩展或者前缀,因为这会有默认的系统规则去添加上去。
例如在Linux系统上,用名字"foo"将生成一个"libfoo.so"的共享库,你无法重写这个前缀。
如果你想要复杂的,你可以创建一个<copy>目标来生成你想要的文件。
例子:
static_library("doom_melon") { output_name = "fluffy_bunny" }
output_prefix_override:
不要为输出名称使用前缀。布尔值,默认是false。
一些系统会为最终输出的文件加上前缀。例如Linux系统上面,目标名为"foo",生成"libfoo.so"
给定目标类型的前缀是由链接器工具指定的。有时候这个前缀是不被渴望出现的。
例子:
shared_library("doom_melon") { # Normally this will produce "libdoom_melon.so" on Linux. Setting this flag # will produce "doom_melon.so". output_prefix_override = true ... }
outputs: Output files for actions and copy targets.
pool: Label of the pool used by the action.
用pool() {...}来声明一个pool。
precompiled_header:
当一个目标指定了这个值,或者一个目标使用了指定这个值的config时,预编译头文件将会被使用。
另外,与源文件相对应的工具(tool)也要指定预编译头文件,工具(tool)还将指定预编译头使用的类型,通过将<precompiled_header_type>设置成"gcc"或者"msvc"。
预编译头或者源(<precompiled_header>和<precompiled_source>)变量可以在一个目标(target)或者配置(config)上使用,但是应用到这个目标上的配置里面的预编译头/源变量值必须是一样的,因为一个目标只能有一个预编译头。
如果同时使用C和c++源,预编译头文件和源文件将按每种语言编译一次。
在C++文件中用 __cplusplus #ifdefs包起来的就会使用C风格编译。
GCC precompiled headers:
当使用GCC风格的预编译头时,“precompiled_source”包含一个.h文件的路径,该文件经过预编译,被设置了“precompiled_source”变量的目标中所有源文件包含。
“precompiled_header”的值不用于gcc样式的预编译头文件。
MSVC precompiled headers:
当使用MSVC风格的预编译头时,“precompiled_header”值是一个对应于header的字符串。这不是GN能识别的文件路径,而是源代码中#include行后引号中出现的确切字符串。编译器将根据include或强制include (/FI)匹配此字符串。
MSVC还需要一个源文件来编译头文件。这必须由“precompiled_source”值指定。与header值相比,这是一个GN样式的文件名,它告诉GN要编译哪个源文件来生成用于后续编译的.pch文件。
例子,如果toolchain指定了MSVC头:
toolchain("vc_x64") { ... tool("cxx") { precompiled_header_type = "msvc" ... You might make a config like this: config("use_precompiled_headers") { precompiled_header = "build/precompile.h" precompiled_source = "//build/precompile.cc" # Either your source files should #include "build/precompile.h" # first, or you can do this to force-include the header. cflags = [ "/FI$precompiled_header" ] } And then define a target that uses the config: executable("doom_melon") { configs += [ ":use_precompiled_headers" ] ...
precompiled_header_type: [string] “gcc” or “msvc”.
precompiled_source: [file name] Source file to precompile.
使用“msvc”风格的预编译头文件时伴随precompiled_header的源文件。它将隐式地添加到目标的sources中。参见“gn帮助precompiled_header”。
product_type: Product type for Xcode projects.
Correspond to the type of the product of a create_bundle target. Only meaningful to Xcode (used as part of the Xcode project generation). When generating Xcode project files, only create_bundle target with a non-empty product_type will have a corresponding target in Xcode project.
public:
为目标声明公共头文件。
其它目标可以#include的文件列表。这些允许被检查(查看gn help check)。
如果没有<public>被声明,那么其它目标都可以#include当前目标<sources>中的文件(前提是visibility,可以查看<visibility>用法)。如果这个变量被定义了,那么其它目标就只能#include它指定的文件,除非依赖项被标记为"friend"。(查看<friend>用法)
头文件权限也受可见性(<visibility>)的影响。一个目标必须对另一个目标是可见,那个目标才能包括当前目标中的任意文件,而<public>只是指定了当前目标中的哪些文件可以被引用。
而public的文件是可以通过依赖关系传递的。因此,如果有这样一个依赖关系 A -> B -> C,然后A可以包含C的公开头文件。但是,对于可见性来说,情况并非如此,因此,除非A在C的可见性列表中,否则引用将被拒绝。
GN只认识在目标的<sources>和<public>部分声明的文件。如果include了构建不知道的文件,那么它将被允许。
测试目标要引入私有头文件是很普遍的情况,对于这种情况,你想要include哪个目标的私有文件,那么你就在那个目标的<friend>列表中把测试目标列进去,这样测试目标就可以包含那个目标的私有文件了。
当一个二进制目标没有显式或者隐式的定义公开头文件时("public"列表定义了,但是空的),GN会假定这个目标不能沿着依赖树传递任何编译时依赖关系。在这种情况下,构建可以更有效地并行化。
假设有依赖关系:
A (shared library) -> B (shared library) -> C (action).
正常情况下,C需要在A中的任何源文件被编译前就要完成(因为可能会有<action>产生的文件被包含)。但是当B显式地声明没有公开头文件(public headers)时,那么C就可以和A的编译步骤同时并行执行。C仍然必须在任何依赖的链接之前完成。
例子:
These exact files are public: public = [ "foo.h", "bar.h" ] No files are public (no targets may include headers from this one): # This allows starting compilation in dependent targets earlier. public = []
public_configs: Configs to be applied on dependents.
这个变量中的配置将会被应用到直接依赖当前目标的目标上。当前目标同样会使用这个变量中声明的配置。
假如 A中声明了"public_configs",如果B继承了A(不管是私有继承(deps)还是公共继承(public_deps)),那么B中都会包含在A中声明的"public_configs"。接下来,如果C继承了B,如果是通过公共继承的方式,那么C中也会包含这个"public_configs",但是如果是私有继承就不会包含这个配置了。以此类推,可以D继承C,E继承D。
例子:
static_library("toplevel") { # This target will get "my_config" applied to it. However, since this # target uses "deps" and not "public_deps", targets that depend on this # one won't get it. deps = [ ":intermediate" ] } static_library("intermediate") { # Depending on "lower" in any way will apply "my_config" to this target. # Additionall, since this target depends on "lower" via public_deps, # targets that depend on this one will also get "my_config". public_deps = [ ":lower" ] } static_library("lower") { # This will get applied to all targets that depend on this one. public_configs = [ ":my_config" ] }
Avoiding applying public configs to this target:
如果你想把"public_configs"应用到依赖当前目标的目标上,但并不应用到当前目标上,使用组(<group>)定义额外的间接层:
# External targets depend on this group. group("my_target") { # Config to apply to all targets that depend on this one. public_configs = [ ":external_settings" ] deps = [ ":internal_target" ] } # Internal target to actually compile the sources. static_library("internal_target") { # Force all external targets to depend on the group instead of directly # on this so the "external_settings" config will get applied. visibility = [ ":my_target" ] ... }
public_deps:
声明公共依赖。
公共依赖类似于私有依赖(参见“gn help deps”),但是附加地表示当前目标将列出的deps作为其公共API的一部分公开。
如果有三个目标: A -> B -> C,C的可见性(<visibility>)允许B依赖它但不允许A,这样A就无法包括任何来自于A的头文件,而C的"public_configs"也只能用于B。
如果B的<public_deps>而不是<deps>把C放进去了,那么A就继承了C的"public_configs",也可以使用C中的头文件。
例子:
# This target can include files from "c" but not from # "super_secret_implementation_details". executable("a") { deps = [ ":b" ] } shared_library("b") { deps = [ ":super_secret_implementation_details" ] public_deps = [ ":c" ] }
rebase: Rebase collected metadata as files.
response_file_contents: Contents of a response file for actions.
有时候传递给脚本的参数太长了对于系统命令行的承载能力来讲。尤其对于Windows平台,它的命令行最大长度是小于8K。而响应文件(response file)允许你用一个不限制数据大小的临时文件为<action>和<action_foreach>的脚本传递参数。
如果<response_file_contents>被定义了,且不是空值,这个列表就会在构建时被当作脚本的参数写到一个临时文件中。而临时文件的名字可以在脚本的<args>中用 "{{response_file_name}}"来表示。
响应文件内容将总是引用并根据Unix shell规则转义。要解析响应文件,Python脚本应该使用“shlex.split(file_contents)”。
例子:
action("process_lots_of_files") { script = "process.py", inputs = [ ... huge list of files ... ] # Write all the inputs to a response file for the script. Also, # make the paths relative to the script working directory. response_file_contents = rebase_path(inputs, root_build_dir) # The script expects the name of the response file in --file-list. args = [ "--enable-foo", "--file-list={{response_file_name}}", ] }
script:
行为(<action>和<action_foreach>)的脚本文件。
sources:
目标的源文件。
Sources for binary targets:
对于二进制目标(如source sets, executables, and libraries),这些已知文件的类型会用相关的工具来编译。而未知的文件类型和头文件会被跳过。但是,你仍然应该列出C/C++的头文件,所以GN知道这些文件的存在就是是为了文件引入检查(include check,可以查看 gn help check,检查头文件的引入合法性)的目的。
特殊情况,以".def"为后缀的文件会被当作Windows module 定义文件,在".def"文件前面加上"/DEF:",然后再被追加给链接行。例如: "/DEF:test.def"
目标中最多只能有一个.def文件,而且它们不跨越依赖边界(因此在静态库或源集中指定.def文件对它们链接到的可执行文件或共享库没有影响)。
Sources for non-binary targets(对于非二进制的目标):
<action_foreach>
"sources"就是脚本要遍历执行的输入项,"sources"中的每个文件都会执行一次脚本。
<action>
"sources"和"inputs"一样。可以查看 "gn help inputs"。
<copy>
"sources"就是要拷贝的文件。
testonly:
声明的目标只能用于测试。
默认值时false。
如果一个目标中定义了"testonly = true",那么这个目标就只能依赖那些同样定义了"testonly = true"的目标。否则,GN就会出现一个依赖不允许的错误。
这个特性的目的是防止在最终产品中把测试代码错误性地交付出去。
例子:
source_set("test_support") { testonly = true ... }
visibility: A list of labels that can depend on a target.
如果这个变量未被定义,则默认就是公开的,也就是所有目标都可见。
如果变量被定义,那么只有那些在<visibility>中被声明的目标才可以依赖当前目标。如果定义为空值,那么就表示任何目标都不可以依赖当前目标。
提示:如果你想在BUILD文件中的所有目标具有同样的可见性,那么你可以把<visibility>定义在文件的顶端,定义在任何目标的外面,这些目标就会继承那个作用范围并且引用定义。
Patterns:
查看用法 "gn help label_pattern"。
如果指定了toolchain,那么只有使用指定toolchain编译的目标才会被匹配到。
如果没有指定toolchain,那么所有的目标都会被匹配。
举例: static_library("my_static") { sources = [...] visibility = [ ":*(//toolchain:x86)" # 只对当前文件中使用 x86 工具链编译的目标可见 ] } shared_library("my_shared") { sources = [...] } executable("test1") { deps = [ ":my_static(//toolchain:x86)", # 使用 x86工具链编译 ":my_shared(//toolchain:arm64)" # 使用arm64工具链编译 ] }
例子:
Only targets in the current buildfile ("private"): visibility = [ ":*" ] No targets (used for targets that should be leaf nodes): visibility = [] Any target ("public", the default): visibility = [ "*" ] All targets in the current directory and any subdirectory: visibility = [ "./*" ] Any target in "//bar/BUILD.gn": visibility = [ "//bar:*" ] Any target in "//bar/" or any subdirectory thereof: visibility = [ "//bar/*" ] Just these specific targets: visibility = [ ":mything", "//foo:something_else" ] Any target in the current directory and any subdirectory thereof, plus any targets in "//bar/" and any subdirectory thereof. visibility = [ "./*", "//bar/*" ]
write_runtime_deps: Writes the target's runtime_deps to the given path.
其它帮助性话题:
构建参数概述:
构建参数是从构建外部传入的变量,build文件可以靠这些参数来决定build如何工作。
构建参数(build arguments)如何设置:
首先,系统默认参数是基于当前系统设置的,内置的参数有:
- host_cpu
- host_os
- current_cpu
- current_os
- target_cpu
- target_os
接下来,应用特定项目的重写值。这些可以在 .gn文件中的 default_args中设定。查看帮助 "gn help dotfile"
如果指定,则使用来自 -- args 命令行的参数。如果没有指定那个标志,那么来自于之前build文件中的参数就会被使用。(在build目录下的 args.gn 文件)。也就是如果没有 --args 传递参数,就使用 args.gn文件中的参数。
最后,对于使用非默认工具链编译的目标,则使用工具链中的重写值。这些是在toolchain定义的时候由<toolchain_args>设置。
如果你要重写的值在 declare_args中没有出现过,就会有非致命性的错误出现。
例子:
gn args out/FooBar Create the directory out/FooBar and open an editor. You would type something like this into that file: enable_doom_melon=false os="android" gn gen out/FooBar --args="enable_doom_melon=true os=\"android\"" This will overwrite the build directory with the given arguments. (Note that the quotes inside the args command will usually need to be escaped for your shell to pass through strings values.)
构建参数(build arguments)如何使用:
如果你想使用一个参数,你就用 declare_args() 指定默认值。如果在 上面"构建参数(build arguments)如何设置"一节中列出的步骤都不适用于给定的参数,则这些默认值将应用,但是这些默认值不会重写它们中的任何一个值。
通常,根构建配置(the root build config)会定义全局参数,这些参数会被传递给所有的build文件(BUILD.gn)。单独的构建文件也可以指定仅适用于这些文件的参数。在使用 "import" 导入的文件中定义参数是很有用的,如果你想让这些参数应用到多个构建文件上。
.gn file
当gn开始的时候,它会去在当前目录以及父级目录下去查找名称为".gn"的文件。".gn"文件所在的目录就是源根目录,也就是"//"所指的目录。 你也可以通过 --root指定别的源根目录。
".gn"文件将会在源根目录("//")下执行。
如果你指定了 --root,那么GN就会去这个目录下找 ".gn"文件。如果你想指定不同的文件,也就是不想用 ".gn"文件了,那么你可以使用 --dotfile来指定自己的 gn 文件:
gn gen out/Debug --root=/home/build --dotfile=/home/my_gn_file.gn
.gn 文件中的变量:
buildconfig是必须的,其余都是可选的。
- arg_file_template —— 文件路径。文件内容应该被作为默认 args.gn文件的内容当你运行 "gn args"时。
- buildconfig —— 构建配置文件的路径。这个文件用于为每个toolchain设置构建的执行环境。
- check_targets —— 一个标签或者标签模式列表,当运行 "gn check"或者"gn gen --check"的时候就会被检查。如果<check_targets>和<no_check_targets>都没有被指定,那么所有的目标都会被检查。如果都指定就会出错。如果这个值是空的,那么就都不检查。
- no_check_targets —— 与上面的<check_targets>相反,被指定的目标标签在运行 "gn check"或者"gn gen --check"时不会被检查。所有其它的目标都会被检查。
- check_system_includes —— 布尔值,控制是否系统路径(尖括号包含的路径,而不是双引号)会被检查当运行 "gn check"或者"gn gen --check"时。可以显式地检查系统文件使用 "gn check --check_system" 或者 "gn gen --check=system"。
- exec_script_whitelist —— .gn/.gni文件列表,这两种文件中可以执行exec_script()函数。如果这个表被设置了,那么在调用exec_script的时候就会按照这个表来检查,如果当前执行exec_script函数的文件不在列表中,那么GN就会失败。如果未指定,那么执行exec_script的能力就不受限制。通配符是不受支持的。
Example: exec_script_whitelist = [ "//base/BUILD.gn", "//build/my_config.gni", ]
- root —— 根构建目标的标签。GN构建将通过加载包含此目标名称的构建文件开始。这个默认为"//:"将会加载 "//BUILD.gn"。
- script_executable —— 在<action>/<action_foreach>和exec_script调用中使用的特定Python可执行文件或其他解释器的路径。GN默认会搜索python的路径来执行这些脚本。如果为空字符串,那么在<action>/<action_foreach>和exec_script中指定的路径就会被直接执行。
- secondary_cource —— 寻找输入文件的备用路径。当搜索BUILD.gn文件时,会先从源根路径(//)下面找。如果没有找到,就从辅助源根路径下面找。辅助源根必须在主源树中。
- default_args —— scope({}) 包含已声明参数的默认覆盖。这些值优先于在declare_args()块中指定的默认值,但是可以被 gn --args或者 args.gn文件重写。
- build_file_extension —— 如果设置为非空字符串,则将其添加到要加载的所有构建文件的名称中。GN会寻找文件名为"BUILD.$build_file_extension.gn"的构建文件。这个变量的目的是在迁移期间或者在同一个目录下面有两个独立的GN构建文件时使用。
- ninja_required_version —— 设置时将指定所需要的ninja的最低版本。默认需要的版本是1.7.2。指定更高的版本可以启用一些可以使构建更加高效的新特性。
.gn 文件的例子:
buildconfig = "//build/config/BUILDCONFIG.gn" check_targets = [ "//doom_melon/*", # Check everything in this subtree. "//tools:mind_controlling_ant", # Check this specific target. ] root = "//:root" secondary_source = "//build/config/temporary_buildfiles/" default_args = { # Default to release builds for this project. is_debug = false is_component_build = false }
构建图和执行概述(Build graph and execution overview)
整体构建流程(Overall build flow):
- 在当前目录查找 ".gn"文件,如果当前目录找不到,就沿着目录树往上找,直到找到这个文件。设置".gn"文件所在的目录为"source root"(也就是源根目录,用 "//"表示),并且解释这个文件(.gn)以寻找到构建配置的名字(buildconfig指定的文件)。
- 执行 .gn 文件识别到的构建配置文件,来设置全局变量和和默认工具链的名称(默认工具链设置函数为"set_default_toolchain()")。任何在这个文件中设置的参数,变量,默认值等等对构建过程中所有的文件都是可见的。
- 加载 //BUILD.gn文件。(在源根目录下)
- 递归评估规则,并且加载所有解决依赖关系所需要的存在于其它目录下的BUILD.gn文件。如果GN在指定位置没有找到BUILD.gn文件,GN将查找dotfile中定义的secondary_source中的对应位置。(查看帮助 "gn help dotfile")
- 当一个目标的依赖关系被解决后,就会把".ninja"后缀的文件写到磁盘上。
- 当所有目标都被解决后,就会写出一个根文件build.ninja。
注意,BUILD.gn文件名可以由 .gn参数调整,例如 build_file_extension
可执行目标的定义和模板(Executing target definitions and templates)
目标的定义是由它的类型和名字组成:
static_library("my_static_library") { ... target parameter definitions ... }
也可以用target()函数来定义目标。
可以用template定义新的类型。查看 "gn help template"
哪些目标会被构建:
在默认工具链中遇到的所有目标都将为它们生成构建规则,即使没有其他目标引用它们。它们的依赖关系必须被解析,并且它们将被添加到隐式的“all”规则中。非默认工具链中的目标只有在需要(直接或传递)在默认工具链中构建目标时才会生成。
Language and grammar for GN build files
GN构建规则和语法
注释用 "#"开头
空白字符和注释会被忽略。
空白字符:
空格 (U+0020)
tab (U+0009)
回车 (U+000D)
新行(U+000A).
Identifiers:
Identifiers name variables and functions. identifier = letter { letter | digit } . letter = "A" ... "Z" | "a" ... "z" | "_" . digit = "0" ... "9" .
Keywords:
下面的关键字是被保留的,不能用作标识符: else false if true
Integer literals:
表示的是10进制数字。不允许前导0和负0。
integer = [ "-" ] digit { digit } . # 负数就使用 "-"
String literals:
由双引号括起来的值。反斜杠后面是被转义的:
\" U+0022 双引号 \$ U+0024 $符号 \\ U+005C 反斜杠
插入任意字节值,就使用 $0xFF。例如, 插入一个新行: "Line one$0x0ALine two"。
看上面空白字符一节,$0x0A表示新行。
Punctuation
The following character sequences represent punctuation: + += == != ( ) - -= < <= [ ] ! = > >= { } && || . ,
Grammar
The input tokens form a syntax tree following a context-free grammar: File = StatementList . Statement = Assignment | Call | Condition . LValue = identifier | ArrayAccess | ScopeAccess . Assignment = LValue AssignOp Expr . Call = identifier "(" [ ExprList ] ")" [ Block ] . Condition = "if" "(" Expr ")" Block [ "else" ( Condition | Block ) ] . Block = "{" StatementList "}" . StatementList = { Statement } . ArrayAccess = identifier "[" Expr "]" . ScopeAccess = identifier "." identifier . Expr = UnaryExpr | Expr BinaryOp Expr . UnaryExpr = PrimaryExpr | UnaryOp UnaryExpr . PrimaryExpr = identifier | integer | string | Call | ArrayAccess | ScopeAccess | Block | "(" Expr ")" | "[" [ ExprList [ "," ] ] "]" . ExprList = Expr { "," Expr } . AssignOp = "=" | "+=" | "-=" . UnaryOp = "!" . BinaryOp = "+" | "-" // highest priority | "<" | "<=" | ">" | ">=" | "==" | "!=" | "&&" | "||" . // lowest priority All binary operators are left-associative.
Types
The GN language is dynamically typed. The following types are used: - Boolean: 使用关键字"true" 和"false". 在布尔值和整数值之间没有隐式转换。 - Integers: GN使用64位有符号整数. - Strings: Strings are 8-bit with no enforced encoding. When a string is used to interact with other systems with particular encodings (like the Windows and Mac filesystems) it is assumed to be UTF-8. See "String literals" above for more. - Lists: Lists are arbitrary-length ordered lists of values. See "Lists" below for more. - Scopes: Scopes are like dictionaries that use variable names for keys. See "Scopes" below for more.
Lists
list使用 []创建,用逗号(,)分隔。
mylist = [ 0, 1, 2, "some string" ]
列表的引用是以0开始的索引:
mylist[0] += 1 var = mylist[2]
可以用 "+" 或者 "+="连接列表。
可以用 "-" 或者 "-="从列表中移除某一项。
用"="将一个非空列表替换另一个非空列表是不允许的。可以用 "+="。
如果要重写一个列表,需要先为该列表赋空值:
mylist = [] mylist = otherlist
Scopes
All execution happens in the context of a scope which holds the current state (like variables). With the exception of loops and conditions, '{' introduces a new scope that has a parent reference to the old scope. Variable reads recursively search all nested scopes until the variable is found or there are no more scopes. Variable writes always go into the current scope. This means that after the closing '}' (again excepting loops and conditions), all local variables will be restored to the previous values. This also means that "foo = foo" can do useful work by copying a variable into the current scope that was defined in a containing scope. Scopes can also be assigned to variables. Such scopes can be created by functions like exec_script, when invoking a template (the template code refers to the variables set by the invoking code by the implicitly-created "invoker" scope), or explicitly like: empty_scope = {} myvalues = { foo = 21 bar = "something" } Inside such a scope definition can be any GN code including conditionals and function calls. After the close of the scope, it will contain all variables explicitly set by the code contained inside it. After this, the values can be read, modified, or added to: myvalues.foo += 2 empty_scope.new_thing = [ 1, 2, 3 ] Scope equality is defined as single-level scopes identical within the current scope. That is, all values in the first scope must be present and identical within the second, and vice versa. Note that this means inherited scopes are always unequal by definition.
File patterns
文件模式是非常有限的正则表达式。它们必须匹配整个输入字符串才能算作匹配。 在正则表达式中,会有隐式的"^...$" 包围你的输入。 如果你想匹配一个子串, 你需要在开始和结尾使用通配符。 模式匹配器只能理解两个特殊标记。 - "*" 匹配一个或多个任意字符. It does not depend on the preceding character (在正则表达式中它等价于".*"). - "\b" 匹配路径边界。This will match the beginning or end of a string, or a slash.
例子:
"*asdf*" Matches a string containing "asdf" anywhere. "asdf" Matches only the exact string "asdf". "*.cc" Matches strings ending in the literal ".cc". "\bwin/*" Matches "win/foo" and "foo/win/bar.cc" but not "iwin/foo".
Label patterns
A label pattern is a way of expressing one or more labels in a portion of the source tree. They are not general regular expressions. They can take the following forms only: - Explicit (no wildcard): "//foo/bar:baz" ":baz" - Wildcard target names: "//foo/bar:*" (all targets in the //foo/bar/BUILD.gn file) ":*" (all targets in the current build file) - Wildcard directory names ("*" is only supported at the end) "*" (all targets) "//foo/bar/*" (all targets in any subdir of //foo/bar) "./*" (all targets in the current build file or sub dirs) Any of the above forms can additionally take an explicit toolchain in parenthesis at the end of the label pattern. In this case, the toolchain must be fully qualified (no wildcards are supported in the toolchain name). "//foo:bar(//build/toolchain:mac)" An explicit target in an explicit toolchain. ":*(//build/toolchain/linux:32bit)" All targets in the current build file using the 32-bit Linux toolchain. "//foo/*(//build/toolchain:win)" All targets in //foo and any subdirectory using the Windows toolchain.
About labels(关于标签)
每个参与依赖关系图的都是被标签来标识的。(targets, configs, and toolchains)
一个很普通的标签:
//base/test:test_support
由路径,冒号,名字组成。
上面的标签就表示你要在"base/test/BUILD.gn"中查找名字为"test_support"的东西。
如果需要的话你也可以指定系统绝对路径。
Toolchains
A canonical label includes the label of the toolchain being used. Normally, the toolchain label is implicitly inherited from the current execution context, but you can override this to specify cross-toolchain dependencies: //base/test:test_support(//build/toolchain/win:msvc) Here GN will look for the toolchain definition called "msvc" in the file "//build/toolchain/win" to know how to compile this target.
Relative labels
如果你要在同一个文件中查找标签,那么你可以不写路径,比如:
:base
标签可以指定为相对于当前目录。从风格上来说,我们更喜欢对所有非文件-本地引用使用绝对路径,除非构建文件需要在不同的上下文中运行(比如一个项目需要是独立的,并且被拉到目录层次结构中不同位置的其他项目中)。
source/plugin:myplugin ../net:url_request
Implicit names 隐含名称
如果名字未被指定,那么就默认和目录名一样。
//net -> //net:net //tools/gn -> //tools/gn:gn
Ninja build rules (ninja构建规则)
The “all” and “default” rules:
All generated targets (see "gn help execution") will be added to an implicit build rule called "all" so "ninja all" will always compile everything. The default rule will be used by Ninja if no specific target is specified (just typing "ninja"). If there is a target named "default" in the root build file, it will be the default build rule, otherwise the implicit "all" rule will be used.
Phony rules
GN generates Ninja "phony" rules for targets in the default toolchain. The phony rules can collide with each other and with the names of generated files so are generated with the following priority: 1. Actual files generated by the build always take precedence. 2. Targets in the toplevel //BUILD.gn file. 3. Targets in toplevel directories matching the names of the directories. So "ninja foo" can be used to compile "//foo:foo". This only applies to the first level of directories since usually these are the most important (so this won't apply to "//foo/bar:bar"). 4. The short names of executables if there is only one executable with that short name. Use "ninja doom_melon" to compile the "//tools/fruit:doom_melon" executable. 5. The short names of all targets if there is only one target with that short name. 6. Full label name with no leading slashes. So you can use "ninja tools/fruit:doom_melon" to build "//tools/fruit:doom_melon". 7. Labels with an implicit name part (when the short names match the directory). So you can use "ninja foo/bar" to compile "//foo/bar:bar". These "phony" rules are provided only for running Ninja since this matches people's historical expectations for building. For consistency with the rest of the program, GN introspection commands accept explicit labels. To explicitly compile a target in a non-default toolchain, you must give Ninja the exact name of the output file relative to the build directory.
nogncheck:
被"nogncheck"注释的行在gn check的时候会被跳过检查。
Include lines containing the substring "nogncheck" will be excluded from header checking. The most common case is a conditional include: #if defined(ENABLE_DOOM_MELON) #include "tools/doom_melon/doom_melon.h" // nogncheck #endif
Actions and copies
Action and copy targets that are listed as "data_deps" will have all of their outputs and data files considered as runtime dependencies. Action and copy targets that are "deps" or "public_deps" will have only their data files considered as runtime dependencies. These targets can list an output file in both the "outputs" and "data" lists to force an output file as a runtime dependency in all cases. The different rules for deps and data_deps are to express build-time (deps) vs. run-time (data_deps) outputs. If GN counted all build-time copy steps as data dependencies, there would be a lot of extra stuff, and if GN counted all run-time dependencies as regular deps, the build's parallelism would be unnecessarily constrained. This rule can sometimes lead to unintuitive results. For example, given the three targets: A --[data_deps]--> B --[deps]--> ACTION GN would say that A does not have runtime deps on the result of the ACTION, which is often correct. But the purpose of the B target might be to collect many actions into one logic unit, and the "data"-ness of A's dependency is lost. Solutions: - List the outputs of the action in its data section (if the results of that action are always runtime files). - Have B list the action in data_deps (if the outputs of the actions are always runtime files). - Have B list the action in both deps and data deps (if the outputs might be used in both contexts and you don't care about unnecessary entries in the list of files required at runtime). - Split B into run-time and build-time versions with the appropriate "deps" for each.
Placeholders (gn 占位符)
这部分只套路actions的占位符。
还有其它在too()中使用的占位符。
{{source}} The name of the source file including directory (*). This will generally be used for specifying inputs to a script in the "args" variable. "//foo/bar/baz.txt" => "../../foo/bar/baz.txt" {{source_file_part}} The file part of the source including the extension. "//foo/bar/baz.txt" => "baz.txt" {{source_name_part}} The filename part of the source file with no directory or extension. This will generally be used for specifying a transformation from a source file to a destination file with the same name but different extension. "//foo/bar/baz.txt" => "baz" {{source_dir}} The directory (*) containing the source file with no trailing slash. "//foo/bar/baz.txt" => "../../foo/bar" {{source_root_relative_dir}} The path to the source file's directory relative to the source root, with no leading "//" or trailing slashes. If the path is system-absolute, (beginning in a single slash) this will just return the path with no trailing slash. This value will always be the same, regardless of whether it appears in the "outputs" or "args" section. "//foo/bar/baz.txt" => "foo/bar" {{source_gen_dir}} The generated file directory (*) corresponding to the source file's path. This will be different than the target's generated file directory if the source file is in a different directory than the BUILD.gn file. "//foo/bar/baz.txt" => "gen/foo/bar" {{source_out_dir}} The object file directory (*) corresponding to the source file's path, relative to the build directory. this us be different than the target's out directory if the source file is in a different directory than the build.gn file. "//foo/bar/baz.txt" => "obj/foo/bar" {{source_target_relative}} The path to the source file relative to the target's directory. This will generally be used for replicating the source directory layout in the output directory. This can only be used in actions and bundle_data targets. It is an error to use in process_file_template where there is no "target". "//foo/bar/baz.txt" => "baz.txt"
例子:
Non-varying outputs: action("hardcoded_outputs") { sources = [ "input1.idl", "input2.idl" ] outputs = [ "$target_out_dir/output1.dat", "$target_out_dir/output2.dat" ] } The outputs in this case will be the two literal files given. Varying outputs: action_foreach("varying_outputs") { sources = [ "input1.idl", "input2.idl" ] outputs = [ "{{source_gen_dir}}/{{source_name_part}}.h", "{{source_gen_dir}}/{{source_name_part}}.cc" ] } Performing source expansion will result in the following output names: //out/Debug/obj/mydirectory/input1.h //out/Debug/obj/mydirectory/input1.cc //out/Debug/obj/mydirectory/input2.h //out/Debug/obj/mydirectory/input2.cc
![Logo](https://devpress.csdnimg.cn/79de2bf0b7994defa4242ef90d5513fa.jpg)
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)