暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

OpenHarmony3.0编译构建流程!

鸿蒙技术社区 2021-12-01
737

早就打算研究下 OH3.0 的编译框架了,最近一直在搞移植,总算有点进展了,抽个空来分析下 3.0 的编译框架。


大体看了下和 2.0 的差别不是特别大:《OpenHarmony 2.0 Canary编译构建流程》。


OHOS3.0 的打包镜像脚本由原来 2.0 的 build\adapter\build_image.sh,全部修改替换为 build\ohos\images\build_image.py,将打包 image 镜像的部分制作成 build_target。


以前是通过 shell 脚本来调用,现在是通过 gn 和 ninja 来调用。主要文件在 build\ohos\images 这个文件夹下。


没有修改的部分就不说了,有需要的可以看我之前的帖子 这篇主要说下不一样的地方,看 OH3.0 是如何将编译好的文件打包成镜像的。


增加编译参数


3.0 之后在 build\build_scripts\build_common.sh 增加了 build_cmd+=" build_target=images"。


这句的意思约等于在执行默认编译命令 ./build.sh --product-name Hi3516DV300 会有个默认的参数 --build-target images。


具体流程是这样的:

build\build_scripts\build_common.sh→build\core\gn\BUILD.gn→build\ohos\images\BUILD.gn
action_with_pydeps("${_platform}_${_image_name}_image") {
    script = "//build/ohos/images/build_image.py"
    depfile = "$target_gen_dir/$target_name.d"
    deps = [ "//build/ohos/packages:${_platform}_install_modules" ]

    image_config_file =
    "//build/ohos/images/mkimage/${_image_name}_image_conf.txt"
    output_image_file = "$current_platform_dir/images/${_image_name}.img"

    image_input_path = "$current_platform_dir/${_image_name}"
    if (_image_name == "userdata") {
        image_input_path = "$current_platform_dir/data"
    }

    sources = [
        image_config_file,
        system_module_info_list,
        system_modules_list,
    ]
    outputs = [ output_image_file ]
    args = [
        "--depfile",
        rebase_path(depfile, root_build_dir),
        "--image-name",
        _image_name,
        "--input-path",
        rebase_path(image_input_path, root_build_dir),
        "--image-config-file",
        rebase_path(image_config_file, root_build_dir),
        "--output-image",
        rebase_path(output_image_file, root_build_dir),
        "--build-image-tools-path",
        rebase_path(build_image_tools_path, root_build_dir),
    ]
    if (sparse_image) {
        args += [ "--sparse-image" ]
    }
}


通常情况下,gn 会使用 action 运行一个脚本来生成一个文件,但是这里使用的是 action_with_pydeps,应该也是内置的目标类型。查看官方手册是这么说明的:


输入和文件,将操作读取(或执行)的所有文件列为 inputs:

  • 仅按从属目标列出输入是不够的。它们必须由使用它们的目标直接列出,或者由 depfile 添加。

  • 非系统 Python 导入是输入!对于导入此类模块的脚本,请使用 action_with_pydeps 来确保将所有依赖的 Python 文件捕获为输入。


前面还定义了一个 image_list,然后使用 foreach 执行 action_with_pydeps,要生成几个 img 文件,就执行几次 action_with_pydeps。
  image_list = [
    "system",
    "vendor",
    "userdata",
    "updater",
  ]
  foreach(_image_name, image_list) {... ...}


调用 python 脚本


既然知道了 img 镜像是由 build\ohos\images\build_image.py 来创建的,那就来分析下这个 python 脚本。
    if os.path.exists(args.output_image_path):
        os.remove(args.output_image_path)            # 删除之前生成的镜像文件夹
    if args.image_name == 'userdata':
        _prepare_userdata(args.input_path)            # 准备好 userdata.img 需要的文件
    if os.path.isdir(args.input_path):
        _make_image(args)
        _dep_files = []
        for _root, _, _files in os.walk(args.input_path):
            for _file in _files:
                _dep_files.append(os.path.join(_root, _file))
        build_utils.write_depfile(args.depfile,
                                  args.output_image_path,
                                  _dep_files,
                                  add_pydeps=False)
===================================================================
def _make_image(args):
    if args.image_name == 'system':
        _prepare_root(args.input_path)                # 准备好 system.img 需要的文件
    elif args.image_name == 'updater':
        _prepare_updater(args.input_path)            # 准备好 updater.img 需要的文件
    image_type = "raw"
    if args.sparse_image:
        image_type = "sparse"
    mk_image_args = [
        args.input_path, args.image_config_file, args.output_image_path,
        image_type
    ]
    env_path = "../../build/ohos/images/mkimage"
    if args.build_image_tools_path:
        env_path = '{}:{}'.format(env_path, args.build_image_tools_path)
    os.environ['PATH'] = '{}:{}'.format(env_path, os.environ.get('PATH'))
    mkimages.mk_images(mk_image_args)            # 而真正制作镜像使用的下面的函数
===================================================================
# build\ohos\images\mkimage\mkimages.py
def mk_images(args):
    ... ...
    if "system.img" in device:
        src_dir = build_rootdir(src_dir)
    mkfs_tools, mk_configs = load_config(config_file)
    mk_configs = src_dir + " " + device + " " + mk_configs

    res = run_cmd(mkfs_tools + " " + mk_configs)    # 制作镜像命令使用的是mkfs_tools
===================================================================
    if "ext4" in mk_configs:
        fs_type = "ext4"
        mkfs_tools = "mkextimage.py"                # 而mkfs_tools根据文件系统类型,分别调用对应的python脚本
    elif "f2fs" in mk_configs:
        mkfs_tools = "mkf2fsimage.py"
        fs_type = "f2fs"
===================================================================
# build\ohos\images\mkimage\mkextimage.py # 制作ext4文件系统
def build_run_mke2fs(args):
    .. ...
    blocks = int(int(args.fs_size) / BLOCKSIZE)
    mke2fs_cmd += ("mke2fs " + str(mke2fs_opts) + " -t " + FS_TYPE + " -b "
                   + str(BLOCKSIZE) + " " + args.device + " " + str(blocks))
    res = run_cmd(mke2fs_cmd)        # mke2fs:制作文件系统
===================================================================
def build_run_e2fsdroid(args):
    ... ...
    e2fsdroid_cmd += ("e2fsdroid" + e2fsdroid_opts + " -f " +
                      args.src_dir + " -a " + args.mount_point +
                      " " + args.device)
    res = run_cmd(e2fsdroid_cmd)    # e2fsdroid:制作镜像文件  


无论前面执行了什么操作,最终都是为了执行 mke2fs、e2fsdroid。


关于这两个命令:

  • mke2fs:Linux 下的命令,用于建立 ext 文件系统。

  • e2fsdroid:来自三方库,third_party\e2fsprogs。


详情可以参考:

http://e2fsprogs.sourceforge.net 

👇扫码报名今晚的鸿蒙直播课👇

👇点击关注鸿蒙技术社区👇

了解鸿蒙一手资讯


求分享

求点赞

求在看

文章转载自鸿蒙技术社区,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论