Fuchsia编译系统的GN结构

2023-12-19 10:32
文章标签 结构 编译系统 gn fuchsia

本文主要是介绍Fuchsia编译系统的GN结构,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 

在下载完成fuchsia的代码之后,编译代码之前,需要使用fx set命令指定要编译的目标(product.board)。参见以下的fx set命令的帮助信息。其中的PRODUCT和BOARD参数可由fx的命令list-products和命令list-boards获得,也可通过查看products目录和boards目录下的gni文件看到。--build-dir选项指定build输出目录,不指定的话默认目录为:`out/default`,并且此build目录将写入文件.fx-build-dir中,之后的fx命令默认使用此文件中保存的目录为(build)编译目录。

~/fuchsia$ fx help set
usage: fx set PRODUCT.BOARD [--with GNLABEL1,GNLABEL2,...][--release] [--auto-dir | --build-dir BUILDDIR][--args ARG] [--help-args [ARG]] [--variant VARIANT][--with-base GNLABEL1,GNLABEL2,...]

例如,使用如下的set命令。如果需要查看fx的详细执行过程,可增加-x参数,如fx -x set core.x64。

~/fuchsia$ fx set core.x64

fx命令是位于目录scripts/下的shell脚本文件。其包含有目录tools/devshell/lib/的shell脚本文件metrics.sh和vars.sh,需要使用到其中的一些变量和函数。首先需要找到fx指定的命令(此处为set)是否存在,参见函数find_command。按照优先级在以下三个位置查找名称为set的文件:1)tools/devshell;2)tools/devshell/contrib;和3)out/default/tools/。

function find_command {local -r cmd=$1local command_path="${fuchsia_dir}/tools/devshell/${cmd}"if [[ -x "${command_path}" ]]; thenecho "${command_path}"return 0filocal command_path="${fuchsia_dir}/tools/devshell/contrib/${cmd}"if [[ -x "${command_path}" ]]; thenecho "${command_path}"return 0filocal -r build_dir=$(get_build_dir)if [[ -n "${build_dir}" ]]; thenlocal command_path="${build_dir}/tools/${cmd}"if [[ -x "${command_path}" ]]; thenecho "${command_path}"return 0fifi...
}

 

在执行set命令之前,使用脚本文件metrics.sh中的函数track-command-execution,设置命令跟踪,如果metrics功能开启,将fx命令行信息发送到google的以下网址:https://www.google-analytics.com。使用命令fx metrics status可查看当前状态:

~/fuchsia$ fx metrics status
Collection of metrics is currently disabled for /home/kai/fuchsia
To change it, run fx metrics <enable|disable>
~/fuchsia$ 

之后,根据找到的set文件(存储在command_path变量中),出入fx set之后的参数到set命令文件中,通常情况下位于tools/devshell/set,其为shell脚本文件。参见其主函数main,find_config函数检查参数product_name是否在目录vendor/*/products/和目录products/下存在名称为product_name.gni的文件(注意多了后缀名.gni),对于board_name逻辑相同,只不过目录换做为boards目录。find_config函数返回相应gni的目录。

function main {cd "${FUCHSIA_DIR}"local gn_args=""case "$1" in*.*)local product_name="${1%.*}"local board_name="${1##*.}"local product="$(find_config "products" "${product_name}")"local board="$(find_config "boards" "${board_name}")"if [[ "${product}" == "" ]] || [[ "${board}" == "" ]]; thenexit 1fign_args+=" import(\"//${board}\") import(\"//${product}\")"

 

如下目录products和boards下的文件列表,存在core.gni和x64.gni文件。此后,gn_args变量的内容变为:import("//boards/x64.gni") import("//products/core.gni")。

~/fuchsia$ ls products/
bringup.gni  core.gni  OWNERS  README.md  router.gni  speaker.gni  terminal.gni  workstation.gni
~/fuchsia$ 
~/fuchsia$ ls boards/
arm64.gni           cleo.gni      kirin970.gni     mt8167s_ref.gni  qemu-arm64.gni  toulouse.gni  x64.gni
chromebook-x64.gni  hikey960.gni  msm8x53-som.gni  OWNERS           qemu-x64.gni    vim2.gni
~/fuchsia$ 

 

接下来,确定build目录,由于没有指定auto_dir命令选项,此处将build目录指定为out/default。

  local config_build_dirif $auto_dir; thenelsecase "$build_dir" in'')# Default is "//out/default".  Store it as relative.config_build_dir="out/default";;//*|out/*)esacfibuild_dir="${FUCHSIA_DIR}/${config_build_dir}"


由于fx命令仅指定了set core.x64,最终的gn_args参数如下。没有使用--with-base选项和--with选项指定packages,变量base_package_labels和universe_package_labels都为空。

import("//boards/x64.gni") import("//products/core.gni")
# See: fx args --list=base_package_labels
base_package_labels+=[]# See: fx args --list=cache_package_labels
cache_package_labels+=[]# See: fx args --list=universe_package_labels
universe_package_labels+=[]


最后,调用buildtools目录下的gn命令。

  "${FUCHSIA_DIR}/buildtools/gn" ${gn_cmd} "${build_dir}" \"${gn_switches[@]}" --args="${gn_args}" "$@"


翻译以上的命令,如下:

buildtools/gn gen /home/kai/work/fuchsia/out/default --check, --export-compile-commands --args= import("//boards/x64.gni") import("//products/core.gni")
# See: fx args --list=base_package_labels
base_package_labels+=[]# See: fx args --list=cache_package_labels
cache_package_labels+=[]# See: fx args --list=universe_package_labels
universe_package_labels+=[]


文件buildtools/gn的内容如下,非常简单,调用exec_tool.sh执行命令:

#!/usr/bin/env bashset -euo pipefailreadonly SCRIPT_ROOT="$(cd $(dirname ${BASH_SOURCE[0]} ) && pwd)"
readonly TOOL_NAME=$(basename "$0")source "${SCRIPT_ROOT}/exec_tool.sh"


文件buildtools/exec_tool.sh如下,其调用TOOL_PATH变量指定的工具。此处工具为buildtools/linux-x64/gn,gn为二进制的可执行程序,其参数$@即为之前介绍的传递给buildtools/gn脚本的参数。

case "$(uname -s)" inDarwin)readonly HOST_PLATFORM="mac-x64";;Linux)readonly HOST_PLATFORM="linux-x64";;*)echo "Unknown operating system. Cannot run ${TOOL_NAME}."exit 1;;
esacreadonly TOOL_PATH="${SCRIPT_ROOT}/${HOST_PLATFORM}/${TOOL_NAME}"exec "${TOOL_PATH}" "$@"

GN工具的子命令gen用于生产ninja所用的文件。默认情况下GN工具启动时,将在其目录或者上级目录中查找后缀为.gn的文件,当然也可在命令行使用选项--root指定查找目录。对于fuchsia,根gn文件BUILD.gn位于代码顶层目录,即GN工具所在目录buildtools/linux-x64的上上级目录:

~/fuchsia$ ls 
AUTHORS  BUILD.gn    buildtools
~/fuchsia$


如下为顶层的根BUILD.gn文件,看一下其参数声明部分。首先包含进了四个build目录下的.gni文件;其次由于在调用GN工具时传入的3个labels变量都为空,此处声明的base、cache和universe package labels变量同样都为空。最后一个参数zircon_tracelog可用于指定日志文件,当Zircon的GN运行时产生的日志将存放在此文件中,方便调试。

import("//build/board.gni")
import("//build/config/fuchsia/zircon.gni")
import("//build/testing/platforms.gni")
import("//build/toolchain/goma.gni")declare_args() {base_package_labels = []cache_package_labels = []universe_package_labels = []zircon_extra_args = {}zircon_extra_ninja_targets = []zircon_enable_kernel_debugging_features = falsezircon_enable_netsvc_debugging_features = false# Where to emit a tracelog from Zircon's GN run. No trace will be produced if# given the empty string. Path can be source-absolute or system-absolute.zircon_tracelog = ""
}


例如设置zircon_tracelog = "//zircon-gn.log",运行fx set core.x64之后,将在fuchsia目录生成zircon-gn.log日志文件,其为json格式。如下显示其部分内容:

~/fuchsia$ head zircon-gn.log 
{"traceEvents":
[{"pid":0,"tid":"140527708751616","ts":0,"ph":"M","name":"thread_name","args":{"name":"Main thread"}},
{"pid":0,"tid":"140527708751616","ts":14938,"ph":"X","dur":39,"name":"Parse args","cat":"setup"},
{"pid":0,"tid":"140527708751616","ts":14978,"ph":"X","dur":613,"name":"Save args file","cat":"setup"},
{"pid":0,"tid":"140527708751616","ts":15592,"ph":"X","dur":1,"name":"Fill Python Path","cat":"setup"},
{"pid":0,"tid":"140527708751616","ts":162,"ph":"X","dur":15432,"name":"DoSetup","cat":"setup"},
{"pid":0,"tid":"140527686739712","ts":15633,"ph":"X","dur":20438,"name":"//public/gn/BUILDCONFIG.gn","cat":"load"},
{"pid":0,"tid":"140527686739712","ts":36073,"ph":"X","dur":1824,"name":"//public/gn/BUILDCONFIG.gn","cat":"parse"},


通过build编译目录的args.gn文件可查看到GN运行的参数,如下:

~/fuchsia$ cat out/default/args.gn
import("//boards/x64.gni")
import("//products/core.gni")
# See: fx args --list=base_package_labels
base_package_labels += []# See: fx args --list=cache_package_labels
cache_package_labels += []# See: fx args --list=universe_package_labels
universe_package_labels += []
~/fuchsia$


以上为fuchsia项目的参数定义部分。对于zircon项目,BUILD.gn定义了单独的参数部分,如下:

declare_args() {zircon_args = {use_goma = use_gomagoma_dir = goma_dirif (clang_prefix != default_clang_prefix) {clang_tool_dir = clang_prefix}variants = zircon_variantsdefault_deps = []foreach(target, zircon_ninja_targets) {default_deps += [ ":$target" ]}enable_kernel_debugging_features = zircon_enable_kernel_debugging_featuresenable_netsvc_debugging_features = zircon_enable_netsvc_debugging_featuresforward_variables_from(zircon_extra_args, "*")}
}


同理,可通过最终生成的build编译目录,查看zircon系统的GN运行参数,如下:

~/fuchsia$ cat out/default.zircon/args.gn 
# THIS FILE IS CLOBBERED.  DO NOT EDIT!
# Instead, edit //out/default/args.gn to add
# zircon_extra_args = { ... } to override settings below.
forward_variables_from({default_deps = [ ":legacy-x64" ]enable_kernel_debugging_features = falseenable_netsvc_debugging_features = falsegoma_dir = "/home/kai/goma"use_goma = falsevariants = []},"*")
~fuchsia$ 


顶层根BUILD.gn文件,接下来要进行一个循环调用,如下的第一个exec_script脚本调用,其调用buildtools/gn脚本(原本就从此gn脚本执行到此)。传入的参数如上的gn_cmd变量的定义,由参数可见,此次调用gn脚本gen子命令,意在生成zircon的ninja编译文件。

# The Zircon GN is completely a puppet of this build.  This gen runs that gen.
if (current_toolchain == default_toolchain) {gn_cmd = ["gen","-q","--root=" + rebase_path("//zircon", root_build_dir),"--args=# THIS FILE IS CLOBBERED.  DO NOT EDIT!$0x0a" +"# Instead, edit $root_build_dir/args.gn to add$0x0a" +"# zircon_extra_args = { ... } to override settings below.$0x0a" +"forward_variables_from($zircon_args, \"*\")","--export-compile-commands=default",rebase_path(zircon_root_build_dir, root_build_dir),]if (zircon_tracelog != "") {gn_cmd += [ "--tracelog=" + rebase_path(zircon_tracelog, root_build_dir) ]}exec_script("//buildtools/gn", gn_cmd)


脚本buildtools/gn此次传入的参数如下。在文件config/fuchsia/zircon.gni中的赋值语句zircon_root_build_dir = "${root_build_dir}.zircon",将zircon_root_build_dir变量赋予了值:out/default.zircon。即此处gn脚本生成的文件存放在out/default.zircon目录下。另外,指定了--root参数选项,为zircon目录,GN工具运行时将使用zircon目录下的BUILD.gn文件。

gen -q --root=../../zircon --args=# THIS FILE IS CLOBBERED.  DO NOT EDIT!
# Instead, edit //out/default/args.gn to add
# zircon_extra_args = { ... } to override settings below.
forward_variables_from({default_deps = [":legacy-x64"]enable_kernel_debugging_features = falseenable_netsvc_debugging_features = falsegoma_dir = "/home/kai/goma"use_goma = falsevariants = []
}, "*") --export-compile-commands=default ../default.zircon


随后,使用python脚本build/zircon/populate_zircon_public.py,目前还不清楚其作用。

125   exec_script("//build/zircon/populate_zircon_public.py",
126               [ rebase_path("$zircon_root_build_dir/legacy_dirs.json") ],
127               "",
128               [ "$zircon_root_build_dir/legacy_dirs.json" ])
129 
130   # This file indicates what Ninja invocation must be done to build Zircon prerequisites before *any* Ninja invocation for this build.
132   write_file("$root_build_dir/zircon.json",
133              {
134                dir = rebase_path(zircon_root_build_dir, root_build_dir)
135                targets = zircon_ninja_targets
136              },
137              "json")
138 }


接下来,在build编译目录中创建fx.config文件,写入Fuchsia的编译目录和架构ARCH信息。

144 _relative_build_dir = rebase_path(root_build_dir, "//", "//")
145 _fx_config_lines = [
146   "# Generated by `gn gen`.",
147   "FUCHSIA_BUILD_DIR='${_relative_build_dir}'",
148   "FUCHSIA_ARCH='${target_cpu}'",
149 ]
150 write_file("$root_build_dir/fx.config", _fx_config_lines)


参见以下fx.config的内容。

~/fuchsia$ cat out/default/fx.config 
# Generated by `gn gen`.
FUCHSIA_BUILD_DIR='out/default'
FUCHSIA_ARCH='x64'
~/fuchsia$ 


顶层根BUILD.gn文件的剩余内容主要与测试相关。使用buildtools/gn的ls子命令可查看BUILD.gn文件定义target列表,如下。其中大部分的target都是由gn的group语法定义,只有fuzzers和tests两个target由generated_file定义,在build编译目录out/default/下,可看到fuzzers.json和tests.json两个输出文件。

~/fuchsia$ buildtools/gn ls out/default "//:*"
//:additional_base_packages
//:additional_cache_packages
//:additional_universe_packages
//:breakpad_symbols
//:build_time_checks
//:default
//:fuzzers
//:package_archive
//:recovery_image
//:tests
~/fuchsia$ 


另外使用以下的--as=buildfile命令选项,可查看顶层的target定义在哪些gn文件中,如下所示,仅有一个文件fuchsia/BUILD.gn。

~/fuchsia$ buildtools/gn ls out/default "//:*"  --as=buildfile
/home/kai/fuchsia/BUILD.gn
~/fuchsia$ 


以下以default目标target为例,看一下其依赖关系的定义。首先其依赖于本文件中的build_time_checks目标;其次依赖于build/images/BUILD.gn文件中的packeages目标;在此依赖于sdk/BUILD.gn文件中的sdk目标。最后的两个依赖关系是依据base_package_labels和cache_package_labels不为空而定义的。

155 group("default") {
156   deps = [
157     ":build_time_checks",
158     "//build/images:packages",
159     "//sdk",
160   ]
161   if (base_package_labels != [] || cache_package_labels != []) {
162     deps += [ "//build/images" ]
163   }
164   if (universe_package_labels != []) {
165     deps += [ "//build/images:updates" ]
166   }
167 }


在多看一级依赖关系,以sdk依赖为例,其位于sdk/BUILD.gn文件中,由group语法定义,内容如下。目标sdk自身又依赖于其文件中的四个target,分别为:core、ddk、images和zircon_sysroot,关于这四个的定义参见文件sdk/BUILD.gn。

 17 # This default target should contain all public or partner SDKs.18 group("sdk") {19   testonly = true20 21   public_deps = [22     ":core",23     ":ddk",24     ":images",25     ":zircon_sysroot",26   ]27 }


使用如下的gn子命令ls,查看sdk目标的所有target列表:

~/fuchsia$ buildtools/gn ls out/default "//sdk:*" 
//sdk:core
//sdk:core_archive
//sdk:core_archive_manifest
//sdk:core_copy
//sdk:core_manifest_verify
//sdk:core_meta
//sdk:core_meta_verify
//sdk:core_molecule
//sdk:core_verify_api
//sdk:ddk
//sdk:ddk_archive
//sdk:ddk_archive_manifest
...
~/fuchsia$ 


如下所示,sdk的所有的target并不是定义在同一个gn文件中。

~/fuchsia$ buildtools/gn ls out/default "//sdk:*"  --as=buildfile
/home/kai/fuchsia/build/compiled_action.gni
/home/kai/fuchsia/build/sdk/sdk.gni
/home/kai/fuchsia/build/sdk/sdk_atom.gni
/home/kai/fuchsia/build/sdk/sdk_molecule.gni
/home/kai/fuchsia/sdk/BUILD.gn
~/fuchsia$ 


如下的gn命令,可参考最终编译生成的可执行文件列表,"//*"代码整个工程。以下以appmgr为例,其为在garnet/bin/appmgr/目录下的BUILD.gn定义的bin目标。

~/fuchsia$ buildtools/gn ls out/default "//*" --type=executable
//examples/hello_world/cpp:bin
//garnet/bin/appmgr:bin


使用了gn的executable语法,输出可执行文件的名称为appmgr。sources指定了源码文件。

executable("bin") {output_name = "appmgr"sources = ["appmgr.cc","appmgr.h","main.cc",]deps = [":lib","//sdk/lib/sys/cpp",]configs += [ "//build/config/fuchsia:static_cpp_standard_library" ]assert_no_deps = [ "//garnet/public/lib/fostr/*" ]
}


如下的编译目录,其中out/default/appmgr为最终编译完成的输出文件。目录out/default/obj/garnet/bin/appmgr/下存放编译appmgr所需的源码文件,以及bin.ninja编译文件。

~/fuchsia$ find out/default -name appmgr
out/default/appmgr
out/default/obj/garnet/bin/appmgr
~/fuchsia$ 

 

END

 

这篇关于Fuchsia编译系统的GN结构的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/511854

相关文章

使用Java实现通用树形结构构建工具类

《使用Java实现通用树形结构构建工具类》这篇文章主要为大家详细介绍了如何使用Java实现通用树形结构构建工具类,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录完整代码一、设计思想与核心功能二、核心实现原理1. 数据结构准备阶段2. 循环依赖检测算法3. 树形结构构建4. 搜索子

利用Python开发Markdown表格结构转换为Excel工具

《利用Python开发Markdown表格结构转换为Excel工具》在数据管理和文档编写过程中,我们经常使用Markdown来记录表格数据,但它没有Excel使用方便,所以本文将使用Python编写一... 目录1.完整代码2. 项目概述3. 代码解析3.1 依赖库3.2 GUI 设计3.3 解析 Mark

mysql通过frm和ibd文件恢复表_mysql5.7根据.frm和.ibd文件恢复表结构和数据

《mysql通过frm和ibd文件恢复表_mysql5.7根据.frm和.ibd文件恢复表结构和数据》文章主要介绍了如何从.frm和.ibd文件恢复MySQLInnoDB表结构和数据,需要的朋友可以参... 目录一、恢复表结构二、恢复表数据补充方法一、恢复表结构(从 .frm 文件)方法 1:使用 mysq

Python中顺序结构和循环结构示例代码

《Python中顺序结构和循环结构示例代码》:本文主要介绍Python中的条件语句和循环语句,条件语句用于根据条件执行不同的代码块,循环语句用于重复执行一段代码,文章还详细说明了range函数的使... 目录一、条件语句(1)条件语句的定义(2)条件语句的语法(a)单分支 if(b)双分支 if-else(

使用Navicat工具比对两个数据库所有表结构的差异案例详解

《使用Navicat工具比对两个数据库所有表结构的差异案例详解》:本文主要介绍如何使用Navicat工具对比两个数据库test_old和test_new,并生成相应的DDLSQL语句,以便将te... 目录概要案例一、如图两个数据库test_old和test_new进行比较:二、开始比较总结概要公司存在多

Java中switch-case结构的使用方法举例详解

《Java中switch-case结构的使用方法举例详解》:本文主要介绍Java中switch-case结构使用的相关资料,switch-case结构是Java中处理多个分支条件的一种有效方式,它... 目录前言一、switch-case结构的基本语法二、使用示例三、注意事项四、总结前言对于Java初学者

结构体和联合体的区别及说明

《结构体和联合体的区别及说明》文章主要介绍了C语言中的结构体和联合体,结构体是一种自定义的复合数据类型,可以包含多个成员,每个成员可以是不同的数据类型,联合体是一种特殊的数据结构,可以在内存中共享同一... 目录结构体和联合体的区别1. 结构体(Struct)2. 联合体(Union)3. 联合体与结构体的

PostgreSQL如何查询表结构和索引信息

《PostgreSQL如何查询表结构和索引信息》文章介绍了在PostgreSQL中查询表结构和索引信息的几种方法,包括使用`d`元命令、系统数据字典查询以及使用可视化工具DBeaver... 目录前言使用\d元命令查看表字段信息和索引信息通过系统数据字典查询表结构通过系统数据字典查询索引信息查询所有的表名可

usaco 1.3 Mixing Milk (结构体排序 qsort) and hdu 2020(sort)

到了这题学会了结构体排序 于是回去修改了 1.2 milking cows 的算法~ 结构体排序核心: 1.结构体定义 struct Milk{int price;int milks;}milk[5000]; 2.自定义的比较函数,若返回值为正,qsort 函数判定a>b ;为负,a<b;为0,a==b; int milkcmp(const void *va,c

自定义类型:结构体(续)

目录 一. 结构体的内存对齐 1.1 为什么存在内存对齐? 1.2 修改默认对齐数 二. 结构体传参 三. 结构体实现位段 一. 结构体的内存对齐 在前面的文章里我们已经讲过一部分的内存对齐的知识,并举出了两个例子,我们再举出两个例子继续说明: struct S3{double a;int b;char c;};int mian(){printf("%zd\n",s