OpenHarmony源码学习之编译过程

云将东游,过扶摇之枝,而适遭鸿蒙。—《庄子·在宥》


前言

OpenHarmony构建工具由shell(.sh)、python(.py)、gn(.gn/.gni)、ninja(.ninja)、clang/llvm、gcc等构成。编译过程中有大量的python命令都是通过importlib.import_module方式导入(比如hb build/ hb set/ hb clean),对分析编译过程增加了一定的难度。本文以 OpenHarmony-v3.2.4-release为例,附上
OpenHarmony-v3.2.4-release下载链接。

一、编译目标分析

OpenHarmony编译完成后镜像img文件所在的目录out/{product_name}/packages/phone/images。

out/rk3568/packages/phone/images# ls -al
-rw-r--r--  1 root root   67108864 17 10:00 boot_linux.img
-rw-r--r--  1 root root   52428800 17 12:52 chip_prod.img
-rw-r--r--  1 root root       7959 17 10:00 config.cfg
-rw-r--r--  1 root root     455104 17 10:00 MiniLoaderAll.bin
-rw-r--r--  1 root root        655 17 10:00 parameter.txt
-rw-rw-r--  1 root root    2265062 17 12:52 ramdisk.img
-rw-r--r--  1 root root    5639680 17 10:00 resource.img
-rw-r--r--  1 root root   52428800 17 12:52 sys_prod.img
-rw-r--r--  1 root root 1610608640 17 12:52 system.img
-rwxr-xr-x  1 root root    4194304 17 10:00 uboot.img
-rw-rw-r--  1 root root   10323639 17 12:52 updater.img
-rw-r--r--  1 root root 1468006400 17 12:52 userdata.img
-rw-r--r--  1 root root  268431360 17 12:52 vendor.img
镜像名称文件格式文件说明
boot_linux.imgext2linux内核
chip_prod.imgext2芯片相关
MiniLoaderAll.bin二进制二进制镜像
ramdisk.imggzip压缩cpioram disk
resource.img二进制资源文件
sys_prod.imgext2产品相关
system.imgext2系统文件
uboot.img二进制boot
updater.imgext2升级文件
userdata.imgext2用户数据
vendor.imgext2厂商
config.cfg配置文件配置文件
parameter.txt文本格式分区文件

镜像文件格式可以使用file命令进行查看,如果是二进制格式则显示data类型

packages/phone/images# file boot_linux.img chip_prod.img MiniLoaderAll.bin ramdisk.img resource.img sys_prod.img system.img uboot.img updater.img userdata.img vendor.img
boot_linux.img:    Linux rev 0.0 ext2 filesystem data, UUID=00000000-0000-0000-0000-000000000000
chip_prod.img:     Linux rev 1.0 ext2 filesystem data, UUID=9972d61c-2903-4218-b280-c0bc5228266d (extents) (64bit) (large files) (huge files)
MiniLoaderAll.bin: data
ramdisk.img:       gzip compressed data, was "ramdisk.img", last modified: Tue Dec 26 06:16:21 2023, from Unix, original size modulo 2^32 4331520
resource.img:      data
sys_prod.img:      Linux rev 1.0 ext2 filesystem data, UUID=0a2da78c-c4ab-44a7-b1c8-8383098758e4 (extents) (64bit) (large files) (huge files)
system.img:        Linux rev 1.0 ext2 filesystem data, UUID=a2757491-4407-4139-aa26-4cac86a28ec0 (extents) (64bit) (large files) (huge files)
uboot.img:         Device Tree Blob version 17, size=2560, boot CPU=0, string block size=197, DT structure block size=1964
updater.img:       gzip compressed data, was "updater.img", last modified: Tue Dec 26 06:16:21 2023, from Unix, original size modulo 2^32 18057216
userdata.img:      F2FS filesystem, UUID=cf1dd758-c179-4876-9518-54ee72d3f9e9, volume name "/data"
vendor.img:        Linux rev 1.0 ext2 filesystem data, UUID=21ef10b2-6522-4980-bc55-79a54d4a8d0f (extents) (64bit) (large files) (huge files)

boot_linux.img为ext2格式,可以在编译电脑上进行解包,操作命令如下

/out/rk3568/packages/phone/images# mkdir boot_linux
/out/rk3568/packages/phone/images# mount -o loop boot_linux.img boot_linux
/out/rk3568/packages/phone/images# cd boot_linux
/out/rk3568/packages/phone/images/boot_linux# ls -al
total 8708
drwxr-xr-x 4 root root    4096 1216 13:57 .
drwxr-xr-x 3 root root    4096 1227 10:51 ..
drwxr-xr-x 2 root root    4096 1216 13:57 extlinux
-rwxr-xr-x 1 root root 2764854 1216 13:57 logo.bmp
-rwxr-xr-x 1 root root 2764854 1216 13:57 logo_kernel.bmp
drwx------ 2 root root 3354624 1216 13:57 lost+found

system.img为ext2格式,可以在编译电脑上进行解包,操作命令如下

/out/rk3568/packages/phone/images# mkdir system
/out/rk3568/packages/phone/images# mount -o loop system.img system
/out/rk3568/packages/phone/images# cd system
/out/rk3568/packages/phone/images/system# ls -al
total 76
drwxr-xr-x. 16 root root  4096 1226 14:16 .
drwxr-xr-x   4 root root  4096 1227 10:54 ..
lrw-r--r--.  1 root root    11 1226 14:16 bin -> /system/bin
drwxr-xr-x.  2 2000 root  4096 1226 14:16 chip_prod
lrw-r--r--.  1 root root     7 1226 14:16 chipset -> /vendor
dr-xr-xr-x.  2 root root  4096 1226 14:16 config
drwxrwx--x.  2 hxd  root  4096 1226 14:16 data
drwxr-xr-x.  2 root root  4096 1226 14:16 dev
lrw-r--r--.  1 root root    11 1226 14:16 etc -> /system/etc
lrw-r--r--.  1 root root    16 1226 14:16 init -> /system/bin/init
lrw-r--r--.  1 root root    11 1226 14:16 lib -> /system/lib
drwx------.  2 root root 16384 1226 14:16 lost+found
drwxr-xr-x.  2 hxd  root  4096 1226 14:16 mnt
drwxr-xr-x.  2 root root  4096 1226 14:16 proc
drwxr-xr-x.  2 root root  4096 1226 14:16 storage
drwxr-xr-x.  2 root root  4096 1226 14:16 sys
drwxr-xr-x.  2 2000 root  4096 1226 14:16 sys_prod
drwxr-xr-x.  9 root root  4096 1226 14:16 system
drwxr-xr-x.  2 root root  4096 1226 14:16 tmp
drwxr-xr-x.  2 root root  4096 1226 14:16 updater
drwxr-xr-x.  2 2000 root  4096 1226 14:16 vendor

ramdisk.img为压缩的cpio格式,先使用gzip进行解压缩,然后使用cpio进行挂载,操作如下

/out/rk3568/packages/phone/images# cp ramdisk.img ramdisk.img.gz //加上.gz后缀
/out/rk3568/packages/phone/images# mv ramdisk.img ramdisk.img.compile //备份原始镜像
/out/rk3568/packages/phone/images# gzip -d ramdisk.img.gz //解压缩镜像
/out/rk3568/packages/phone/images# file ramdisk.img //查看镜像格式
ramdisk.img: ASCII cpio archive (SVR4 with no CRC)
/out/rk3568/packages/phone/images# cp ramdisk.img ramdisk
/out/rk3568/packages/phone/images# cd ramdisk
/out/rk3568/packages/phone/images# mkdir ramdisk
/out/rk3568/packages/phone/images/ramdisk# cpio -idmv < ramdisk.img 
.
lib
lib/libc.so
lib/libinit_module_engine.so
lib/libclang_rt.asan.so
lib/libselinux.z.so
sys
dev
storage
mnt
usr
init
system
etc
bin
bin/mknod
proc

二、编译过程分析

当在源代码目录下输入./build.sh --product-name rk3568 --ccache都发生了什么?整个编译过程又是怎样的?本章将为您进行详细分析。源码目录下build.sh为软链接,其真实文件为./build/build_scripts/build.sh。

//build.sh --product-name rk3568 --ccache

#检查工具链脚本build/scripts/tools_checker.py
${PYTHON3} ${source_root_dir}/build/scripts/tools_checker.py

#启动编译build/scripts/entry.py
${PYTHON3} ${source_root_dir}/build/scripts/entry.py --source-root-dir ${source_root_dir} $@
#上面命令替换成如下
#//build/scripts/entry.py --source-root-dir /usr/src/openharmony/OpenHarmony-v3.2.4-Release/OpenHarmony --product-name rk3568 --ccache

#执行结果判断
if [[ "$?" -ne 0 ]]; then #如果上条命令(build/scripts/entry.py)的返回值非0
    echo -e "\033[31m=====build ${product_name} error=====\033[0m" #输出编译错误提示,\033[31m 用于控制输出显示字符颜色为红色
    exit 1 #退出
fi
echo -e "\033[32m=====build ${product_name} successful=====\033[0m" #输出编译成功提示,\033[32m 用于控制输出显示字符颜色为绿色

//build/scripts/entry.py --source-root-dir /usr/src/openharmony/OpenHarmony-v3.2.4-Release/OpenHarmony --product-name rk3568 --ccache

def check_output(cmd, **kwargs):
    process = subprocess.Popen(cmd, #启动子进程
                               stdout=subprocess.PIPE, #子进程标准输出到管道
                               stderr=subprocess.STDOUT, #子进程错误输出到显示器                           
                               universal_newlines=True,
                               **kwargs)
    #父进程继续执行下面代码,通过iter循环读取子进程输出,写入标准输出即显示器。iter循环结束条件是缓冲区为空
    for line in iter(process.stdout.readline, ''):#父进程循环读取子进程管道输出
        sys.stdout.write(line) #父将子进程输出写入到标准输出
        sys.stdout.flush()     #父将子进程输出刷新到标准输出         
        
    process.wait() #等待子进程结束
    return process.returncode

def do_build(args):
    build_py = os.path.join(args.source_root_dir, 'build.py')
    cmd = [
        'python3',
        build_py,
        '-p',
        args.product_name,
    ]
   
    if args.disable_part_of_post_build:
        ...
    try:
        #cmd=['python3', '/usr/src/openharmony/OpenHarmony-v3.2.4-Release/OpenHarmony/build.py', '-p', 'rk3568', '--device-type=default', '--build-variant=root']
        return check_output(cmd) #调用check_output
        
def main():
    .....
    return do_build(args) #调用do_build
        
if __name__ == '__main__': #判断结果为真
    sys.exit(main()) #调用main函数

//build.py -p rk3568 --device-type=default --build-variant=root

def check_output(cmd, **kwargs):
    process = subprocess.Popen(cmd, #启动子进程
                               stdout=subprocess.PIPE, #子进程标准输出到管道
                               stderr=subprocess.STDOUT, #子进程错误输出到显示器                           
                               universal_newlines=True,
                               **kwargs)
    #父进程继续执行下面代码,通过iter循环读取子进程输出,写入标准输出即显示器。iter循环结束条件是缓冲区为空
    for line in iter(process.stdout.readline, ''):#父进程循环读取子进程管道输出
        sys.stdout.write(line) #父将子进程输出写入到标准输出
        sys.stdout.flush()     #父将子进程输出刷新到标准输出         
        
    process.wait() #等待子进程结束
    ret_code = process.returncode
    return ret_code
    
def set_root_path(path):
    sys.path.insert(0, os.path.join(path, 'build/lite'))
    module = importlib.import_module('hb_internal.set.set') #导入build/lite/hb_internal/set/set.py
    return module.set_root_path(root_path=path)

def build(path, args_list):
    python_executable = get_python()
    cmd = [python_executable, 'build/lite/hb/__main__.py', 'build'] + args_list
    #cmd=['/usr/src/openharmony/OpenHarmony-v3.2.4-Release/OpenHarmony/prebuilts/python/linux-x86/3.9.2/bin/python3', 'build/lite/hb/__main__.py', 'build', '-p', 'rk3568', '--device-type=default', '--build-variant=root']    
    return check_output(cmd, cwd=path) #调用check_output函数

def main():
    root_path = os.path.dirname(os.path.abspath(__file__))
    ret_code = set_root_path(root_path) #调用set_root_path函数
    if ret_code != 0:
        return ret_code
    return build(root_path, sys.argv[1:]) #调用build函数

if __name__ == "__main__":
    sys.exit(main())

//build/lite/hb/__main__.py build -p rk3568 -device-type=default --build-variant=root

EXECV_FRAGMENT = """
import sys
import importlib

sys.path.append(sys.argv.pop())
entry = importlib.import_module("__entry__") #导入模块
sys.exit(entry.main())
"""

def main():
    try:
        topdir = find_top()
    except Exception as ex:
        return print("hb_error: Please call hb utilities inside source root directory")
    python_base_dir = os.path.join(topdir, 'prebuilts/python')
    if os.path.exists(python_base_dir):
        python_dir = search(python_base_dir, 'python3')
        python_executable = os.path.join(python_dir, 'python3')
        lite_dir = os.path.join(topdir, 'build/lite')
        hb_dir = search(lite_dir, '__entry__.py')
        param_list = ["python3", "-c", EXECV_FRAGMENT]
        for arg in sys.argv[1:]:
            param_list.append(arg)
        param_list.append(hb_dir)
        os.environ['PATH'] = python_dir + ":" + os.getenv('PATH')
        #/usr/src/openharmony/OpenHarmony-v3.2.4-Release/OpenHarmony/prebuilts/python/linux-x86/3.9.2/bin/python3 ['python3', '-c', '\nimport sys\nimport importlib\n\nsys.path.append(sys.argv.pop())\nentry = importlib.import_module("__entry__")\nsys.exit(entry.main())\n', 'build', '-p', 'rk3568', '--device-type=default', '--build-variant=root', '/usr/src/openharmony/OpenHarmony-v3.2.4-Release/OpenHarmony/build/lite/hb']
        os.execv(python_executable, param_list) #第一个参数表示执行程序的路径,第二个参数为列表格式,不定长度,为想要执行程序的system argument参数,自动忽略列表中第一个参数,-c从第二个参数开始

if __name__ == "__main__": #判断结果为真
    sys.exit(main()) #调用main函数

build/lite/hb/entry.py

def main():
    try:
        topdir = find_top()
    except Exception as ex:
        return print("hb_error: Please call hb utilities inside source root directory")
    sys.path.insert(0, os.path.join(topdir, 'build/lite'))
    parser = argparse.ArgumentParser(description='OHOS Build System '
                                     f'version {VERSION}')
    parser.add_argument('-v',
                        '--version',
                        action='version',
                        version=f'[OHOS INFO] hb version {VERSION}')

    subparsers = parser.add_subparsers()
    parser_list = []

    command_set = get_hb_commands(os.path.join(topdir, 'build/lite/hb_internal/hb_command_set.json')) #json存储需要导入命令列表和命令对应的描述
    for key, val in command_set.items():
        parser_list.append({'name': key, 'help': val})

    for each in parser_list:
        module_parser = subparsers.add_parser(name=each.get('name'),
                                              help=each.get('help'))
        module = importlib.import_module('hb_internal.{0}.{0}'.format(
            each.get('name'))) #将hb_internal文件夹下的build、set、env、clear、tool命令一一导入
        module.add_options(module_parser)
        module_parser.set_defaults(parser=module_parser,
                                   command=module.exec_command)

    args = parser.parse_known_args()

    module = importlib.import_module('hb_internal.common.utils')
    hb_error = getattr(module, 'hb_error')
    hb_warning = getattr(module, 'hb_warning')
    ohos_exception = getattr(module, 'OHOSException')
    try:
        if args[0].parser.prog == 'hb set' and 'root_path' in vars(args[0]):
            # Root_path is topdir.
            args[0].root_path = topdir
        if "tool" in args[0].parser.prog:
            status = args[0].command(args)
        else:
            #args[0]=Namespace(component=[], build_type=['debug'], compiler=['clang'], test=None, target_cpu='', compile_config=False, dmverity=False, tee=False, product=['rk3568'], full=False, ndk=False, target=[], verbose=False, sign_haps_by_server=False, patch=False, compact_mode=True, gn_args='', keep_ninja_going=False, build_only_gn=False, log_level='info', fast_rebuild=False, disable_package_image=False, disable_post_build=False, disable_part_of_post_build=[], device_type='default', build_variant='root', share_ccache='', parser=ArgumentParser(prog='-c build', usage=None, description=None, formatter_class=<class 'argparse.HelpFormatter'>, conflict_handler='error', add_help=True), command=<function exec_command at 0x7f2e6c9ec160>)
            status = args[0].command(args[0]) #执行build/lite/hb/hb_internal/build/build.py参数如上
    except KeyboardInterrupt:
        hb_warning('User Abort')
        status = -1
    except ohos_exception as exception:
        hb_error(exception.args[0])
        status = -1
    except Exception as exception:
        if not hasattr(args[0], 'command'):
            parser.print_help()
        else:
            hb_error(traceback.format_exc())
            hb_error(f'Unhandled error: {exception}')
        status = -1

    return status

if __name__ == "__main__": #importlib 调用次文件,判断为false
    sys.exit(main())

build/lite/hb/hb_internal/build/build.py Namespace(component=[], build_type=[‘debug’], compiler=[‘clang’], test=None, target_cpu=‘’, compile_config=False, dmverity=False, tee=False, product=[‘rk3568’], full=False, ndk=False, target=[], verbose=False, sign_haps_by_server=False, patch=False, compact_mode=True, gn_args=‘’, keep_ninja_going=False, build_only_gn=False, log_level=‘info’, fast_rebuild=False, disable_package_image=False, disable_post_build=False, disable_part_of_post_build=[], device_type=‘default’, build_variant=‘root’, share_ccache=‘’, parser=ArgumentParser(prog=‘-c build’, usage=None, description=None, formatter_class=<class ‘argparse.HelpFormatter’>, conflict_handler=‘error’, add_help=True), command=<function exec_command at 0x7f2e6c9ec160>)

def exec_command(args):
    if len(args.product):
        if '@' in args.product[0]:
            product, company = args.product[0].split('@')
        else:
            product = args.product[0]
            company = None
        set_product(product_name=product, company=company)

    build = Build(args.component, args.compact_mode) #创建Build类build对象
    ....
    return build.build(args.full,
                       patch=args.patch,
                       cmd_args=cmd_args,
                       ninja=ninja)

build/lite/hb/hb_internal/build/build_process.py
build_process.py是编译核心流程包含:PreBuild、Patch、Preloader、self.gn_build
、self.ninja_build

class Build():
    ........
    def build(self, full_compile, patch=False, ninja=True, cmd_args=None):
        
        cmd_list = self.get_cmd(full_compile, patch, ninja, cmd_args)//获取编译列表
        
        if cmd_args.get('disable_part_of_post_build'):
            disable_post_build_args = cmd_args['disable_part_of_post_build']
        else:
            disable_post_build_args = []
        try:
            for exec_cmd in cmd_list:
                print("\033[93m build_process.py line 153 {0}--{1} \033[0m".format
                exec_cmd(cmd_args) #遍历执行命令列表
        except OHOSException:
            raise
        except Exception:
            raise
        else:
            if not cmd_args.get('disable_post_build'):
                print("\033[93m build_process.py line 161 start postbuild\033[0m")
                post_build = PostBuild(self.config)
                if not cmd_args.get('disable_package_image'):
                    print("\033[93m build_process.py line 165 start package_image\033[0m")
                    post_build.package_image()
                if not disable_post_build_args or 'output_part_rom_status' not in disable_post_build_args:
                    print("\033[93m build_process.py line 168 start romstatus\033[0m")
                    output_part_rom_status(self.config.root_path)
        finally:
            if not cmd_args.get('disable_post_build'):
                if 'post_build' not in locals():
                    print("\033[93m build_process.py line 172 start postbuild\033[0m")
                    post_build = PostBuild(self.config)
                print("\033[93m build_process.py line 174 start clean \033[0m")
                post_build.clean(self.start_time, disable_post_build_args)

        hb_info(f'{os.path.basename(self.config.out_path)} build success')
        hb_info(f'cost time: {self.build_time}')
        return 0

    def get_cmd(self, full_compile, patch, ninja, cmd_args):
        cmd_list = []
        if not cmd_args.get('fast_rebuild'):
            pre_build = PreBuild(self.config)
            cmd_list.append(pre_build.prepare)

        if patch:
            patch = Patch()
            cmd_list.append(patch.patch_make)

        if not cmd_args.get('fast_rebuild'):
            preloader = Preloader(self.config)
            cmd_list.append(preloader.run)

        # if full_compile is set, remove out and do full build
        # if build_only_gn is set, only do gn parse
        # else do incremental build.
        if full_compile:
            remove_path(self.config.out_path)
            makedirs(self.config.out_path, exist_ok=True)
            if not cmd_args.get('fast_rebuild'):
                cmd_list.append(self.gn_build)
            cmd_list.append(self.ninja_build)
        elif not ninja:
            makedirs(self.config.out_path, exist_ok=True)
            if not cmd_args.get('fast_rebuild'):
                cmd_list.append(self.gn_build)
            return cmd_list
        else:
            makedirs(self.config.out_path, exist_ok=True)
            if not cmd_args.get('fast_rebuild'):
                cmd_list.append(self.gn_build)
            cmd_list.append(self.ninja_build)

        return cmd_list

    def gn_build(self, cmd_args):
        # Gn cmd init and execute
        ......
        print("\033[93mbuild_process.py line 259 {0}--{1}--{2}\033[0m".format(gn_cmd, self.config.log_path,self.env()))
        exec_command(gn_cmd, log_path=self.config.log_path, env=self.env())

    def ninja_build(self, cmd_args):
        .......
        print("\033[93mbuild_process.py line 290 {0}--{1}--{2}\033[0m".format(ninja_cmd, self.config.log_path,self.env()))
        exec_command(ninja_cmd,
                     log_path=self.config.log_path,
                     log_filter=True,
                     env=self.env())

以上注释部分打印如下

build_process.py line 153 <bound method PreBuild.prepare of <hb_internal.common.misc.PreBuild object at 0x7f3fb12ed1f0>>--defaultdict(None, {'gn': [], 'ninja': {'default_target': 'packages'}, 'log_level': 'info', 'device_type': 'default', 'build_variant': 'root'}) 

build_process.py line 153 <bound method Preloader.run of <hb_internal.preloader.preloader.Preloader object at 0x7f3fb12ed550>>--defaultdict(None, {'gn': [], 'ninja': {'default_target': 'packages'}, 'log_level': 'info', 'device_type': 'default', 'build_variant': 'root'}) 
 
build_process.py line 153 <bound method Build.gn_build of <hb_internal.build.build_process.Build object at 0x7f3fafbde1c0>>--defaultdict(None, {'gn': [], 'ninja': {'default_target': 'packages'}, 'log_level': 'info', 'device_type': 'default', 'build_variant': 'root'}) 
 
build_process.py line 259 ['gn', 'gen', '--args=product_path="/usr/src/openharmony/OpenHarmony-v3.2.4-Release/OpenHarmony/vendor/hihope/rk3568" product_name="rk3568" device_name="rk3568" target_cpu="arm" is_standard_system=true device_path="/usr/src/openharmony/OpenHarmony-v3.2.4-Release/OpenHarmony/device/board/rockchip/rk3568" device_config_path="/usr/src/openharmony/OpenHarmony-v3.2.4-Release/OpenHarmony/device/board/rockchip/rk3568" product_config_path="/usr/src/openharmony/OpenHarmony-v3.2.4-Release/OpenHarmony/vendor/hihope/rk3568" ace_engine_feature_enable_accessibility=true ace_engine_feature_enable_web=true enable_ohos_startup_init_feature_ab_partition=true enable_ohos_startup_init_feature_loader=true dsoftbus_feature_conn_p2p=true dsoftbus_feature_disc_ble=true dsoftbus_feature_conn_br=true dsoftbus_feature_conn_ble=true dsoftbus_feature_trans_udp_stream=true graphic_standard_feature_ace_enable_gpu=true input_feature_combination_key=true input_feature_pointer_drawing=true input_feature_interceptor=true input_feature_monitor=true input_feature_keyboard=true input_feature_mouse=true input_feature_touchscreen=true input_feature_input_device=true wpa_supplicant_driver_nl80211=true drivers_peripheral_input_feature_model=true drivers_peripheral_sensor_feature_model=true drivers_peripheral_audio_full_test_suite=true drivers_peripheral_audio_alsa_lib=false drivers_peripheral_light_feature_model=true drivers_peripheral_vibrator_feature_model=true ohos_build_type="debug" ohos_build_time="1704430722501" ohos_build_datetime="2024-01-05 20:58:42" ohos_build_enable_ccache=true build_variant="root" device_type="default"', '/usr/src/openharmony/OpenHarmony-v3.2.4-Release/OpenHarmony/out/rk3568']--/usr/src/openharmony/OpenHarmony-v3.2.4-Release/OpenHarmony/out/rk3568/build.log
 
build_process.py line 153 <bound method Build.ninja_build of <hb_internal.build.build_process.Build object at 0x7f7e0561f190>>--defaultdict(None, {'gn': [], 'ninja': {'default_target': 'packages'}, 'log_level': 'info', 'device_type': 'default', 'build_variant': 'root'}) 

build_process.py line 290 ['ninja', '-w', 'dupbuild=warn', '-C', '/usr/src/openharmony/OpenHarmony-v3.2.4-Release/OpenHarmony/out/rk3568', 'images']--/usr/src/openharmony/OpenHarmony-v3.2.4-Release/OpenHarmony/out/rk3568/build.log
def exec_command(cmd, log_path='out/build.log', **kwargs):
    useful_info_pattern = re.compile(r'\[\d+/\d+\].+') #设置log过滤
    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.STDOUT,
                                   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信息,即[OHOS INFO]开头的log
            log_file.write(line)

    process.wait()
    ret_code = process.returncode

    if ret_code != 0:
        if is_log_filter:
            get_failed_log(log_path)

        raise OHOSException('Please check build log in {}'.format(log_path))

exec_command(‘gn’, ‘gen’, ‘–args=product_path=“/usr/src/openharmony/OpenHarmony-v3.2.4-Release/OpenHarmony/vendor/hihope/rk3568” product_name=“rk3568” device_name=“rk3568” target_cpu=“arm” is_standard_system=true device_path=“/usr/src/openharmony/OpenHarmony-v3.2.4-Release/OpenHarmony/device/board/rockchip/rk3568” device_config_path=“/usr/src/openharmony/OpenHarmony-v3.2.4-Release/OpenHarmony/device/board/rockchip/rk3568” product_config_path=“/usr/src/openharmony/OpenHarmony-v3.2.4-Release/OpenHarmony/vendor/hihope/rk3568” ace_engine_feature_enable_accessibility=true ace_engine_feature_enable_web=true enable_ohos_startup_init_feature_ab_partition=true enable_ohos_startup_init_feature_loader=true dsoftbus_feature_conn_p2p=true dsoftbus_feature_disc_ble=true dsoftbus_feature_conn_br=true dsoftbus_feature_conn_ble=true dsoftbus_feature_trans_udp_stream=true graphic_standard_feature_ace_enable_gpu=true input_feature_combination_key=true input_feature_pointer_drawing=true input_feature_interceptor=true input_feature_monitor=true input_feature_keyboard=true input_feature_mouse=true input_feature_touchscreen=true input_feature_input_device=true wpa_supplicant_driver_nl80211=true drivers_peripheral_input_feature_model=true drivers_peripheral_sensor_feature_model=true drivers_peripheral_audio_full_test_suite=true drivers_peripheral_audio_alsa_lib=false drivers_peripheral_light_feature_model=true drivers_peripheral_vibrator_feature_model=true ohos_build_type=“debug” ohos_build_time=“1704430722501” ohos_build_datetime=“2024-01-05 20:58:42” ohos_build_enable_ccache=true build_variant=“root” device_type=“default”’, ‘/usr/src/openharmony/OpenHarmony-v3.2.4-Release/OpenHarmony/out/rk3568’],/usr/src/openharmony/OpenHarmony-v3.2.4-Release/OpenHarmony/out/rk3568/build.log,…)
上述命令exec_command会启动进程执行gn,gn会到根目录下寻找.gn文件,并从根.gn文件开始执行/.gn为软链接,真正文件位于//build/core/gn/dotfile.gn 内容如下,

buildconfig = "//build/config/BUILDCONFIG.gn"

# The source root location.
root = "//build/core/gn" #切换资源gn根目录为//build/core/gn,自动会执行根目录下BUILD.gn
# The executable used to execute scripts in action and exec_script.
script_executable = "/usr/bin/env"

//build/core/gn/BUILD.gn 内容如下,

print("root_out_dir=$root_out_dir")       //编译log中的打印[OHOS INFO]
print("root_build_dir=$root_build_dir")
print("root_gen_dir=$root_gen_dir")
print("current_toolchain=$current_toolchain")
print("host_toolchain=$host_toolchain")

# run loader
import("//build/core/gn/loader.gni")

# gn target defined
if (product_name == "ohos-sdk") {
  group("build_ohos_sdk") {
    deps = [
      "//build/ohos/ndk:ohos_ndk",
      "//build/ohos/sdk:ohos_sdk",
    ]
  }
} else {
  group("make_all") {
    deps = [
      ":make_inner_kits",
      ":packages",
    ]
    if (is_standard_system) {
      # Lite system uses different packaging scheme, which is called in hb.
      # So skip images for lite system since it's the mkimage
      # action for standard system.
      deps += [ ":images" ]
    }
  }

  group("images") {
    deps = [ "//build/ohos/images:make_images" ]
  }

  group("packages") {
    deps = [ "//build/ohos/packages:make_packages" ]
  }

  group("make_inner_kits") {
    deps = [ "$root_build_dir/build_configs:inner_kits" ]
  }

  group("build_all_test_pkg") {
    testonly = true
    deps = [
      "$root_build_dir/build_configs:parts_test",
      "//test/testfwk/developer_test:make_temp_test",
    ]
  }

  group("make_test") {
    testonly = true
    deps = [
      "//build/ohos/packages:build_all_test_pkg",
      "//build/ohos/packages:package_testcase",
      "//build/ohos/packages:package_testcase_mlf",
    ]
    if (archive_component) {
      deps += [ "//build/ohos/testfwk:archive_testcase" ]
    }
  }
}

命令行打印log如下
[OHOS INFO] root_out_dir=//out/rk3568
[OHOS INFO] root_build_dir=//out/rk3568
[OHOS INFO] root_gen_dir=//out/rk3568/gen
[OHOS INFO] current_toolchain=//build/toolchain/ohos:ohos_clang_arm
[OHOS INFO] host_toolchain=//build/toolchain/linux:clang_x64

完整脚本调用过程如下

./build.sh --product-name rk3568 --ccache #--ccache可以不带,默认使用ccache加速编译
  build/scripts/tools_checker.py
  build/scripts/entry.py --source-root-dir /usr/src/openharmony/OpenHarmony-v3.2.4-Release/OpenHarmony --product-name rk3568 --ccache
    build.py -p rk3568 --device-type=default --build-variant=root
       build/lite/hb/__main__.py build -p rk3568 -device-type=default --build-variant=root
         build/lite/hb/__entry__.py 
           build/lite/hb/hb_internal/build/build.py
             build/lite/hb/hb_internal/build/build_process.py
               PreBuild #hb_internal.common.misc.PreBuild,1.设置ccache大小;2.备份上次编译log build.log->build.<上次修改时间>.log
               #并在屏幕输出第一行以[OHOS INFO]开头的log,为执行ccache -M 100GB命令自动输出
               #[OHOS INFO] Set cache size limit to 100.0 GB 
               Patch #默认不执行,代码路径build/lite/hb/hb_internal/build/patch_process.py
               Preloader #hb_internal.preloader.preloader.Preloader
               #创建out/preloader/rk3568文件夹,生成syscap.json,SystemCapability.json,part.json,part_config.json,feature.json,build_gnargs.prop,exclusion_module.json,build.prob,platforms.build, 创建system文件夹生成对应文件
               self.gn_build #hb_internal.build.build_process.Build
               self.ninja_build #hb_internal.build.build_process.Build
               PostBuild #packiamge执行镜像打包
               out_put_part_rom_status #统计各部件大小
               clean #统计ccache命中率信息、ninja trace、计算c语言代码覆盖率         

总结

OpenHarmony编译过程已经分析完毕,如果想了解编译框架,可以看我的另一篇文章《OpenHarmony源码学习之编译构建》。

  • 26
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值