本篇关键词:、、、

下载 >> 离线文档.鸿蒙内核源码分析(百篇博客分析.挖透鸿蒙内核).pdf

编译运行相关篇为:

构建的必要性

  • 前端开发有构建工具:GruntGulpWebpack
  • 后台开发有构建工具: MavenAntGradle

构建工具重要性不言而喻,它描述了整个工程的如何编译、连接,打包等规则,其中包括:工程中的哪些源文件需要编译以及如何编译、需要创建那些库文件以及如何创建这些库文件、如何最后输出我们想要的文件。

鸿蒙轻内核(L1/liteos)的编译构建工具是hbhbohos-build的简称, 而ohos又是openharmony os的简称。

hb | ohos-build

hb通过以下命令安装,是用 python写的一个构建工具。

python3 -m pip install --user ohos-build
1

其源码在 ./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                   # 编译工具链配置,包括:编译器路径、编译选项、链接选项等
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

构建组成

鸿蒙构建系统由 pythongnninjamakefile几个部分组成,每个部分都有自己的使命,干自己最擅长的活。

  • 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'
    
    1
    2
    3
    4
    5

    图为绕过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
        },
    ]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

构建流程

编译构建流程图所示,主要分设置和编译两步:

本篇调试图中的 hb set | hb build 两个命令

hb set | 选择项目

源码见于: ./build/lite/hb/set/set.py hb set执行的大致流程是这样的:

  • 你可以在任何目录下执行hb set, 它尝试读取当前目录下的 ohos_config.json配置文件,如果没有会让你输入代码的路径

    [OHOS INFO] Input code path: 
    
    1

    也就是源码根目录, 生成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
    
    1
    2
    3
    4
    5
    6
    7
    8

    图为断点调试现场

  • 最后生成的配置文件如下:

      {
      "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
      }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9

    有了这些路径就为后续 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

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.bin  bin          build.ninja             config     etc             libs              obj               server.map  test_info             userfs
        #OHOS_Image      OHOS_Image.map  bm_tool.map  build.ninja.d           data       foundation.map  liteos.bin        rootfs.tar        suites      toggleButtonTest.map  userfs_jffs2.img
        #OHOS_Image.asm  args.gn         build.log    bundle_daemon_tool.map  dev_tools  gen             media_server.map  rootfs_jffs2.img  test        toolchain.ninja       vendor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

exec_command | utils.py

gn_buildninja_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[0])
            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))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

图为断点调试现场

百文说内核 | 抓住主脉络

  • 百文相当于摸出内核的肌肉和器官系统,让人开始丰满有立体感,因是直接从注释源码起步,在加注释过程中,每每有心得处就整理,慢慢形成了以下文章。内容立足源码,常以生活场景打比方尽可能多的将内核知识点置入某种场景,具有画面感,容易理解记忆。说别人能听得懂的话很重要! 百篇博客绝不是百度教条式的在说一堆诘屈聱牙的概念,那没什么意思。更希望让内核变得栩栩如生,倍感亲切。
  • 与代码需不断debug一样,文章内容会存在不少错漏之处,请多包涵,但会反复修正,持续更新,v**.xx 代表文章序号和修改的次数,精雕细琢,言简意赅,力求打造精品内容。
  • 百文在 < 鸿蒙研究站 | 开源中国 | 博客园 | 51cto | csdn | 知乎 | 掘金 > 站点发布,百篇博客系列目录如下。

按功能模块:

基础知识 进程管理 任务管理 内存管理
双向链表
内核概念
源码结构
地址空间
计时单位
优雅的宏
钩子框架
位图管理
POSIX
main函数
调度故事
进程控制块
进程空间
线性区
红黑树
进程管理
Fork进程
进程回收
Shell编辑
Shell解析
任务控制块
并发并行
就绪队列
调度机制
任务管理
用栈方式
软件定时器
控制台
远程登录
协议栈
内存规则
物理内存
内存概念
虚实映射
页表管理
静态分配
TLFS算法
内存池管理
原子操作
圆整对齐
通讯机制 文件系统 硬件架构 内核汇编
通讯总览
自旋锁
互斥锁
快锁使用
快锁实现
读写锁
信号量
事件机制
信号生产
信号消费
消息队列
消息封装
消息映射
共享内存
文件概念
文件故事
索引节点
VFS
文件句柄
根文件系统
挂载机制
管道文件
文件映射
写时拷贝
芯片模式
ARM架构
指令集
协处理器
工作模式
寄存器
多核管理
中断概念
中断管理
编码方式
汇编基础
汇编传参
链接脚本
内核启动
进程切换
任务切换
中断切换
异常接管
缺页中断
编译运行 调测工具
编译过程
编译构建
GN语法
忍者无敌
ELF格式
ELF解析
静态链接
重定位
动态链接
进程映像
应用启动
系统调用
VDSO
模块监控
日志跟踪
系统安全
测试用例

百万注源码 | 处处扣细节

  • 百万汉字注解内核目的是要看清楚其毛细血管,细胞结构,等于在拿放大镜看内核。内核并不神秘,带着问题去源码中找答案是很容易上瘾的,你会发现很多文章对一些问题的解读是错误的,或者说不深刻难以自圆其说,你会慢慢形成自己新的解读,而新的解读又会碰到新的问题,如此层层递进,滚滚向前,拿着放大镜根本不愿意放手。

  • < gitee | github | coding | gitcode > 四大码仓推送 | 同步官方源码。

关注不迷路 | 代码即人生

  • 互联网从业十五年,计算机硕士,技术副总裁
  • 关注我,持续更新四十年,即聊技术也聊人生
  • 交有趣靠谱的人;做难而正确的事
  • 不做作,不炒作,只唯真
  • 不唯上,不唯书,只唯实

>> 捐助名单

据说喜欢 点赞 + 分享 的,后来都成了大神。😃