绝代码农 发表于 2021-7-20 15:42:08

鸿蒙内核源码分析(构建工具篇) | 顺瓜摸藤调试鸿蒙构建过程 | 百篇博客分析HarmonyOS源码 | v59.01

OpenHarmony | 鸿蒙研究站 | WeHarmony < 国内 | 国外 >

百篇博客系列篇.本篇为:
v59.xx 鸿蒙内核源码分析(构建工具篇) | 顺瓜摸藤调试鸿蒙构建过程| 51 .c .h .o
编译模块相关篇为:

[*]v58.xx 鸿蒙内核源码分析(环境脚本篇) | 如何防编译环境中的牛皮癣| 51 .c .h .o
[*]v57.xx 鸿蒙内核源码分析(编译过程篇) | 简单案例窥视GCC编译全过程| 51 .c .h .o
[*]v50.xx 鸿蒙内核源码分析(编译环境篇) | docker编译鸿蒙真的很香| 51 .c .h .o
构建的必要性


[*]前端开发有构建工具:Grunt、Gulp、Webpack
[*]后台开发有构建工具: Maven、Ant、Gradle
构建工具重要性不言而喻,它描述了整个工程的如何编译、连接,打包等规则,其中包括:工程中的哪些源文件需要编译以及如何编译、需要创建那些库文件以及如何创建这些库文件、如何最后输出我们想要的文件。
鸿蒙轻内核(L1/liteos)的编译构建工具是hb,hb是ohos-build的简称, 而ohos又是openharmony os的简称.
hb | ohos-build
hb通过以下命令安装,是用 python写的一个构建工具.
python3 -m pip install --user ohos-build
其源码在 ./build/lite 目录下,含义如下:
build/lite
├── components                  # 组件描述文件
├── figures                     # readme中的图片
├── hb                        # hb pip安装包源码
│   ├── build                   # hb build 命令实现
│   ├── clean                   # hb clean 命令实现
│   ├── common                  # 通用类, 提供 Device,Config,Product,utils 类
│   ├── cts                     # hb cts 命令实现
│   ├── deps                  # hb deps 命令实现
│   ├── env                     # hb env 命令实现
│   ├── set                     # hb set 命令实现
├── make_rootfs               # 文件系统镜像制作脚本
├── config                      # 编译配置项
│   ├── component               # 组件相关的模板定义
│   ├── kernel                  # 内核相关的编译配置
│   └── subsystem               # 子系统编译配置
├── platform                  # ld脚本
├── testfwk                     # 测试编译框架
└── toolchain                   # 编译工具链配置,包括:编译器路径、编译选项、链接选项等
构建组成
鸿蒙构建系统由 python, gn, ninja, makefile几个部分组成,每个部分都有自己的使命,干自己最擅长的活.

[*]python : 胶水语言,最擅长的是对参数,环境变量,文件操作,它任务是做好编译前的准备工作和为gn收集命令参数.不用python直接用gn行不行? 也行,但很麻烦.比如:直接使用下面的命令行也可以生成 .ninja文件,最后的效果是一样的.但相比只使用 hb build 哪个更香, hb build也会生成下面这一坨坨, 但怎么来是python的强项. /home/tools/gn gen /home/openharmony/code-v1.1.1-LTS/out/hispark_aries/ipcamera_hispark_aries \
--root=/home/openharmony/code-v1.1.1-LTS \
--dotfile=/home/openharmony/code-v1.1.1-LTS/build/lite/.gn \
--script-executable=python3 \
'--args=ohos_build_type="debug" ohos_build_compiler_specified="clang" ohos_build_compiler_dir="/home/tools/llvm" product_path="/home/openharmony/code-v1.1.1-LTS/vendor/hisilicon/hispark_aries" device_path="/home/openharmony/code-v1.1.1-LTS/device/hisilicon/hispark_aries/sdk_liteos" ohos_kernel_type="liteos_a" enable_ohos_appexecfwk_feature_ability = false ohos_full_compile=true'
图为绕过hb python部分直接执行gn gen 的结果:   
[*]gn : 类似构建界的高级语言,gn和ninja的关系有点像C和汇编语言的关系,与它对标的是cmake,它的作用是生成.ninja文件,不用gn直接用ninja行不行? 也行,但更麻烦.就跟全用汇编写鸿蒙系统一样,理论上可行,可谁会这么去干呢.
[*]ninja:类似构建界的汇编语言,与它对标的是make,由它完成对编译器clang,链接器ld的使用.
[*]makefile:鸿蒙有些模块用的还是make编译, 听说后面会统一使用ninja,是不是以后就看不到make文件了,目前是还有大量的make存在.
如何调试 hb
推荐使用vscode来调试,在调试面板点击 create a launch.json file创建调试文件,复制以下内容就可以调试hb了.
{
    "version": "0.2.0",
    "configurations": [
      {// hb set
            "name": "hb set",
            "type": "python",
            "request": "launch",
            "program": "./build/lite/hb/__main__.py",
            "console": "integratedTerminal",
            "args": ["set"],
            "stopOnEntry": true
      },
      {//hb build
            "name": "hb build debug",
            "type": "python",
            "request": "launch",
            "program": "./build/lite/hb/__main__.py",
            "console": "integratedTerminal",
            "args": ["build"],
            "stopOnEntry": true
      },
      {//hb clean
            "name": "hb clean",
            "type": "python",
            "request": "launch",
            "program": "./build/lite/hb/__main__.py",
            "console": "integratedTerminal",
            "args": ["clean"],
            "stopOnEntry": true
      },
    ]
}
构建流程
编译构建流程图所示,主要分设置和编译两步:
本篇调试图中的 hb set | hb build 两个命令
hb set | 选择项目
源码见于: ./build/lite/hb/set/set.py hb set执行的大致流程是这样的:

[*]你可以在任何目录下执行hb set, 它尝试读取当前目录下的 ohos_config.json配置文件,如果没有会让你输入代码的路径
Input code path:
也就是源码根目录, 生成ohos_config.json配置文件,配置内容项是固定的,由Config类管理.

[*]可以在以下位置打上断点调试 set命令,跟踪整个过程.
def exec_command(args):
    if args.root_path is not None:
      return set_root_path(root_path=args.root_path)

    if args.product:
      return set_product()

    return set_root_path() == 0 and set_product() == 0
图为断点调试现场


[*]最后生成的配置文件如下:
{
"root_path": "/home/openharmony/code-v1.1.1-LTS",
"board": "hispark_aries",
"kernel": "liteos_a",
"product": "ipcamera_hispark_aries",
"product_path": "/home/openharmony/code-v1.1.1-LTS/vendor/hisilicon/hispark_aries",
"device_path": "/home/openharmony/code-v1.1.1-LTS/device/hisilicon/hispark_aries/sdk_liteos",
"patch_cache": null
}
有了这些路径就为后续 hb build 铺好了路.

hb build | 编译项目
源码见于: ./build/lite/hb/build/*.py 建议大家去调试下源码,非常有意思,能看清楚所有的细节.本篇将编译工具中重要代码都加上了注解. 也可以前往 weharmony | 注解鸿蒙编译工具 查看对其的代码注释工程.
总体步骤是分两步:

[*]调用 gn_build 使用 gn gen生成 *.ninja 文件
[*]调用 ninja_build 使用 ninja -w dupbuild=warn -C 生成 *.o *.so *.bin 等最后的文件
gn_build 关于gn的资料可以前往 GN参考手册查看. 具体gn是如何生成.ninja文件的,后续有篇幅详细介绍其语法及在鸿蒙中的使用.
    #执行gn编译
    def gn_build(self, cmd_args):
      # Clean out path
      remove_path(self.config.out_path) #先删除out目录
      makedirs(self.config.out_path)    #创建out目录

      # Gn cmd init and execute ,生成 build.ninja, args.gn
      gn_path = self.config.gn_path
      gn_args = cmd_args.get('gn', [])
      gn_cmd = [gn_path,#gn的安装路径 ~/gn
                  'gen',
                  self.config.out_path, #/home/openharmony/out/hispark_aries/ipcamera_hispark_aries
                  '--root={}'.format(self.config.root_path), #项目的根例如:/home/openharmony
                  '--dotfile={}/.gn'.format(self.config.build_path),#/home/openharmony/build/lite/.gn -> root = "//build/lite"
                  f'--script-executable={sys.executable}',#python3
                  '--args={}'.format(" ".join(self._args_list))] + gn_args         
      #   ohos_build_type="debug"
      #   ohos_build_compiler_specified="clang"
      #   ohos_build_compiler_dir="/root/llvm"
      #   product_path="/home/openharmony/vendor/hisilicon/hispark_aries"
      #   device_path="/home/openharmony/device/hisilicon/hispark_aries/sdk_liteos"
      #   ohos_kernel_type="liteos_a"
      #   enable_ohos_appexecfwk_feature_ability = false
      #   ohos_full_compile=true'
      #   这些参数也将在exec_command后保存在 args.gn文件中
      exec_command(gn_cmd, log_path=self.config.log_path)#执行 gn gen .. 命令,在./out/hispark_aries/ipcamera_hispark_aries目录下生成如下文件
      #   obj 子编译项生成的 ninja文件目录,例如:obj/base/global/resmgr_lite/frameworks/resmgr_lite/global_resmgr.ninja
      #   args.gn 各种参数, ohos_build_type="debug" ...
      #   build.ninja 子编译项 例如: build aa: phony dev_tools/bin/aa
      #   build.ninja.d 由那些模块产生的子编译项 例如:../../../base/global/resmgr_lite/frameworks/resmgr_lite/BUILD.gn
      #   toolchain.ninja 工具链 放置了各种编译/链接规则 rule cxx rule alink
ninja_build 关于ninja 的资料可以前往 ninja 参考手册查看. 具体ninja是如何运行的,后续有篇幅详细介绍其语法及在鸿蒙中的使用.
    # ninja 编译过程
    def ninja_build(self, cmd_args):
      ninja_path = self.config.ninja_path

      ninja_args = cmd_args.get('ninja', [])
      ninja_cmd = [ninja_path,
                     '-w',
                     'dupbuild=warn',
                     '-C',
                     self.config.out_path] + ninja_args
      # ninja -w dupbuild=warn -C /home/openharmony/out/hispark_aries/ipcamera_hispark_aries
      # 将读取gn生成的文件,完成编译的第二步,最终编译成 .o .bin 文件
      exec_command(ninja_cmd, log_path=self.config.log_path, log_filter=True)
      #生成以下部分文件
      #NOTICE_FILE   OHOS_Image.binbin          build.ninja             config   etc             libs            obj               server.maptest_info             userfs
      #OHOS_Image      OHOS_Image.mapbm_tool.mapbuild.ninja.d         data       foundation.mapliteos.bin      rootfs.tar      suites      toggleButtonTest.mapuserfs_jffs2.img
      #OHOS_Image.asmargs.gn         build.log    bundle_daemon_tool.mapdev_toolsgen             media_server.maprootfs_jffs2.imgtest      toolchain.ninja       vendor
exec_command | utils.py
gn_build 和 ninja_build 最后都会调用 exec_command来执行命令,exec_command是个通用方法,见于 build/lite/hb/common/utils.py,调试时建议在这里打断点,顺瓜摸藤,跟踪相关函数的实现细节.
def exec_command(cmd, log_path='out/build.log', **kwargs):
    useful_info_pattern = re.compile(r'\[\d+/\d+\].+')
    is_log_filter = kwargs.pop('log_filter', False)

    with open(log_path, 'at', encoding='utf-8') as log_file:
      process = subprocess.Popen(cmd,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE,
                                 encoding='utf-8',
                                 **kwargs)
      for line in iter(process.stdout.readline, ''):
            if is_log_filter:
                info = re.findall(useful_info_pattern, line)
                if len(info):
                  hb_info(info)
            else:
                hb_info(line)
            log_file.write(line)

    process.wait()
    ret_code = process.returncode

    if ret_code != 0:
      with open(log_path, 'at', encoding='utf-8') as log_file:
            for line in iter(process.stderr.readline, ''):
                if 'ninja: warning' in line:
                  log_file.write(line)
                  continue
                hb_error(line)
                log_file.write(line)

      if is_log_filter:
            get_failed_log(log_path)

      hb_error('you can check build log in {}'.format(log_path))
      if isinstance(cmd, list):
            cmd = ' '.join(cmd)
      raise Exception("{} failed, return code is {}".format(cmd, ret_code))
图为断点调试现场

百篇博客.往期回顾
在加注过程中,整理出以下文章。内容立足源码,常以生活场景打比方尽可能多的将内核知识点置入某种场景,具有画面感,容易理解记忆。说别人能听得懂的话很重要! 百篇博客绝不是百度教条式的在说一堆诘屈聱牙的概念,那没什么意思。更希望让内核变得栩栩如生,倍感亲切.确实有难度,自不量力,但已经出发,回头已是不可能的了。:P
与代码有bug需不断debug一样,文章和注解内容会存在不少错漏之处,请多包涵,但会反复修正,持续更新,.xx代表修改的次数,精雕细琢,言简意赅,力求打造精品内容。

[*]v59.xx 鸿蒙内核源码分析(构建工具篇) | 顺瓜摸藤调试鸿蒙构建过程| 51 .c .h .o

[*]v58.xx 鸿蒙内核源码分析(环境脚本篇) | 如何防编译环境中的牛皮癣| 51 .c .h .o

[*]v57.xx 鸿蒙内核源码分析(编译过程篇) | 简单案例窥视GCC编译全过程| 51 .c .h .o

[*]v56.xx 鸿蒙内核源码分析(进程映像篇) | ELF是如何被加载运行的?| 51 .c .h .o

[*]v55.xx 鸿蒙内核源码分析(重定位篇) | 与国际接轨的对外部发言人| 51 .c .h .o

[*]v54.xx 鸿蒙内核源码分析(静态链接篇) | 完整小项目看透静态链接过程| 51 .c .h .o

[*]v53.xx 鸿蒙内核源码分析(ELF解析篇) | 你要忘了她姐俩你就不是银| 51 .c .h .o

[*]v52.xx 鸿蒙内核源码分析(静态站点篇) | 五一哪也没去就干了这事| 51 .c .h .o

[*]v51.xx 鸿蒙内核源码分析(ELF格式篇) | 应用程序入口并不是main| 51 .c .h .o

[*]v50.xx 鸿蒙内核源码分析(编译环境篇) | docker编译鸿蒙真的很香| 51 .c .h.o

[*]v49.xx 鸿蒙内核源码分析(信号消费篇) | 谁让CPU连续四次换栈运行| 51 .c .h.o

[*]v48.xx 鸿蒙内核源码分析(信号生产篇) | 年过半百,依然活力十足| 51 .c .h.o

[*]v47.xx 鸿蒙内核源码分析(进程回收篇) | 临终前如何向老祖宗托孤| 51 .c .h.o

[*]v46.xx 鸿蒙内核源码分析(特殊进程篇) | 龙生龙凤生凤老鼠生儿会打洞| 51 .c .h.o

[*]v45.xx 鸿蒙内核源码分析(Fork篇) | 一次调用,两次返回| 51 .c .h.o

[*]v44.xx 鸿蒙内核源码分析(中断管理篇) | 江湖从此不再怕中断| 51 .c .h.o

[*]v43.xx 鸿蒙内核源码分析(中断概念篇) | 海公公的日常工作| 51 .c .h.o

[*]v42.xx 鸿蒙内核源码分析(中断切换篇) | 系统因中断活力四射 | 51 .c .h.o

[*]v41.xx 鸿蒙内核源码分析(任务切换篇) | 看汇编如何切换任务| 51 .c .h.o

[*]v40.xx 鸿蒙内核源码分析(汇编汇总篇) | 汇编可爱如邻家女孩| 51 .c .h.o

[*]v39.xx 鸿蒙内核源码分析(异常接管篇) | 社会很单纯,复杂的是人| 51 .c .h.o

[*]v38.xx 鸿蒙内核源码分析(寄存器篇) | 小强乃宇宙最忙存储器| 51 .c .h.o

[*]v37.xx 鸿蒙内核源码分析(系统调用篇) | 开发者永远的口头禅| 51 .c .h.o

[*]v36.xx 鸿蒙内核源码分析(工作模式篇) | CPU是韦小宝,七个老婆| 51 .c .h.o

[*]v35.xx 鸿蒙内核源码分析(时间管理篇) | 谁是内核基本时间单位| 51 .c .h.o

[*]v34.xx 鸿蒙内核源码分析(原子操作篇) | 谁在为原子操作保驾护航| 51 .c .h.o

[*]v33.xx 鸿蒙内核源码分析(消息队列篇) | 进程间如何异步传递大数据| 51 .c .h.o

[*]v32.xx 鸿蒙内核源码分析(CPU篇) | 整个内核就是一个死循环| 51 .c .h.o

[*]v31.xx 鸿蒙内核源码分析(定时器篇) | 哪个任务的优先级最高| 51 .c .h.o

[*]v30.xx 鸿蒙内核源码分析(事件控制篇) | 任务间多对多的同步方案| 51 .c .h.o

[*]v29.xx 鸿蒙内核源码分析(信号量篇) | 谁在负责解决任务的同步| 51 .c .h.o

[*]v28.xx 鸿蒙内核源码分析(进程通讯篇) | 九种进程间通讯方式速揽| 51 .c .h.o

[*]v27.xx 鸿蒙内核源码分析(互斥锁篇) | 比自旋锁丰满的互斥锁| 51 .c .h.o

[*]v26.xx 鸿蒙内核源码分析(自旋锁篇) | 自旋锁当立贞节牌坊| 51 .c .h.o

[*]v25.xx 鸿蒙内核源码分析(并发并行篇) | 听过无数遍的两个概念| 51 .c .h.o

[*]v24.xx 鸿蒙内核源码分析(进程概念篇) | 进程在管理哪些资源| 51 .c .h.o

[*]v23.xx 鸿蒙内核源码分析(汇编传参篇) | 如何传递复杂的参数| 51 .c .h.o

[*]v22.xx 鸿蒙内核源码分析(汇编基础篇) | CPU在哪里打卡上班| 51 .c .h.o

[*]v21.xx 鸿蒙内核源码分析(线程概念篇) | 是谁在不断的折腾CPU| 51 .c .h.o

[*]v20.xx 鸿蒙内核源码分析(用栈方式篇) | 程序运行场地由谁提供| 51 .c .h.o

[*]v19.xx 鸿蒙内核源码分析(位图管理篇) | 谁能一分钱分两半花| 51 .c .h.o

[*]v18.xx 鸿蒙内核源码分析(源码结构篇) | 内核每个文件的含义| 51 .c .h.o

[*]v17.xx 鸿蒙内核源码分析(物理内存篇) | 怎么管理物理内存| 51 .c .h.o

[*]v16.xx 鸿蒙内核源码分析(内存规则篇) | 内存管理到底在管什么| 51 .c .h.o

[*]v15.xx 鸿蒙内核源码分析(内存映射篇) | 虚拟内存虚在哪里| 51 .c .h.o

[*]v14.xx 鸿蒙内核源码分析(内存汇编篇) | 谁是虚拟内存实现的基础| 51 .c .h.o

[*]v13.xx 鸿蒙内核源码分析(源码注释篇) | 鸿蒙必定成功,也必然成功| 51 .c .h.o

[*]v12.xx 鸿蒙内核源码分析(内存管理篇) | 虚拟内存全景图是怎样的| 51 .c .h.o

[*]v11.xx 鸿蒙内核源码分析(内存分配篇) | 内存有哪些分配方式| 51 .c .h.o

[*]v10.xx 鸿蒙内核源码分析(内存主奴篇) | 皇上和奴才如何相处| 51 .c .h.o

[*]v09.xx 鸿蒙内核源码分析(调度故事篇) | 用故事说内核调度过程| 51 .c .h.o

[*]v08.xx 鸿蒙内核源码分析(总目录) | 百万汉字注解 百篇博客分析| 51 .c .h.o

[*]v07.xx 鸿蒙内核源码分析(调度机制篇) | 任务是如何被调度执行的| 51 .c .h.o

[*]v06.xx 鸿蒙内核源码分析(调度队列篇) | 内核有多少个调度队列| 51 .c .h.o

[*]v05.xx 鸿蒙内核源码分析(任务管理篇) | 任务池是如何管理的| 51 .c .h.o

[*]v04.xx 鸿蒙内核源码分析(任务调度篇) | 任务是内核调度的单元| 51 .c .h.o

[*]v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调度谁的贡献最大| 51 .c .h.o

[*]v02.xx 鸿蒙内核源码分析(进程管理篇) | 谁在管理内核资源| 51 .c .h.o

[*]v01.xx 鸿蒙内核源码分析(双向链表篇) | 谁是内核最重要结构体| 51 .c .h.o

关于 51 .c .h .o
看系列篇文章会常看到 51 .c .h .o,希望这对大家阅读不会造成影响. 分别对应以下四个站点的首个字符,感谢这些站点一直以来对系列篇的支持和推荐,尤其是 oschina gitee ,很喜欢它的界面风格,简洁大方,让人感觉到开源的伟大!

[*]51cto
[*]csdn
[*]harmony
[*]oschina
而巧合的是.c .h .o是C语言的头/源/目标文件,这就很有意思了,冥冥之中似有天数,将这四个宝贝以这种方式融合在一起. 51 .c .h .o , 我要CHO ,嗯嗯,hin 顺口 : )
百万汉字注解.百篇博客分析
百万汉字注解 >> 精读鸿蒙源码,中文注解分析, 深挖地基工程,大脑永久记忆,四大码仓每日同步更新< gitee | github | csdn | coding >
百篇博客分析 >> 故事说内核,问答式导读,生活式比喻,表格化说明,图形化展示,主流站点定期更新中< 51cto | csdn | harmony| osc >
关注不迷路.代码即人生

热爱是所有的理由和答案 - turing
原创不易,欢迎转载,但麻烦请注明出处.

文档来源:开源中国社区https://my.oschina.net/weharmony/blog/5135157
页: [1]
查看完整版本: 鸿蒙内核源码分析(构建工具篇) | 顺瓜摸藤调试鸿蒙构建过程 | 百篇博客分析HarmonyOS源码 | v59.01