• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3
4#
5# Copyright (c) 2024 Huawei Device Co., Ltd.
6# Licensed under the Apache License, Version 2.0 (the "License");
7# you may not use this file except in compliance with the License.
8# You may obtain a copy of the License at
9#
10#     http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS,
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15# See the License for the specific language governing permissions and
16# limitations under the License.
17#
18
19import os
20import re
21import sys
22import stat
23import subprocess
24import csv
25from concurrent.futures import ThreadPoolExecutor
26
27from datetime import datetime
28from distutils.spawn import find_executable
29from containers.arg import Arg
30from containers.status import throw_exception
31from exceptions.ohos_exception import OHOSException
32from modules.interface.build_module_interface import BuildModuleInterface
33from resources.config import Config
34from resources.global_var import CURRENT_OHOS_ROOT, DEFAULT_BUILD_ARGS
35from resolver.interface.args_resolver_interface import ArgsResolverInterface
36from util.type_check_util import TypeCheckUtil
37from util.io_util import IoUtil
38from util.log_util import LogUtil
39from util.system_util import SystemUtil
40from util.type_check_util import TypeCheckUtil
41from util.component_util import ComponentUtil
42from util.product_util import ProductUtil
43from util.prebuild.patch_process import Patch
44from util.post_build.part_rom_statistics import output_part_rom_status
45
46
47def rename_file(source_file, target_file):
48    try:
49        os.rename(source_file, target_file)
50    except FileNotFoundError as rename_error:
51        LogUtil.hb_warning(rename_error)
52
53
54class BuildArgsResolver(ArgsResolverInterface):
55
56    def __init__(self, args_dict: dict):
57        super().__init__(args_dict)
58
59    @staticmethod
60    def resolve_product(target_arg: Arg, build_module: BuildModuleInterface):
61        """resolve '--product-name' arg.
62        :param target_arg: arg object which is used to get arg value.
63        :param build_module [maybe unused]: build module object which is used to get other services.
64        :phase: prebuild.
65        """
66        config = Config()
67        target_generator = build_module.target_generator
68        target_generator.regist_arg('product_name', config.product)
69        target_generator.regist_arg('product_path', config.product_path)
70        target_generator.regist_arg(
71            'product_config_path', config.product_config_path)
72
73        target_generator.regist_arg('device_name', config.board)
74        target_generator.regist_arg('device_path', config.device_path)
75        target_generator.regist_arg('device_company', config.device_company)
76        target_generator.regist_arg(
77            'device_config_path', config.device_config_path)
78
79        target_generator.regist_arg('target_cpu', config.target_cpu)
80        target_generator.regist_arg('precise_branch', config.precise_branch)
81        target_generator.regist_arg(
82            'is_{}_system'.format(config.os_level), True)
83
84        target_generator.regist_arg('ohos_kernel_type', config.kernel)
85        target_generator.regist_arg('ohos_build_compiler_specified',
86                                    ProductUtil.get_compiler(config.device_path))
87
88        target_generator.regist_arg('ohos_build_time',
89                                    SystemUtil.get_current_time(time_type='timestamp'))
90        target_generator.regist_arg('ohos_build_datetime',
91                                    SystemUtil.get_current_time(time_type='datetime'))
92
93        features_dict = ProductUtil.get_features_dict(config.product_json)
94        for key, value in features_dict.items():
95            target_generator.regist_arg(key, value)
96
97        if ProductUtil.get_compiler(config.device_path) == 'clang':
98            target_generator.regist_arg(
99                'ohos_build_compiler_dir', config.clang_path)
100
101        if target_arg.arg_value == 'ohos-sdk':
102            target_generator = build_module.target_generator
103            target_generator.regist_arg('build_ohos_sdk', True)
104            target_generator.regist_arg('build_ohos_ndk', True)
105            target_generator.regist_arg('enable_enhanced_opt', False)
106            if len(build_module.args_dict['build_target'].arg_value) == 0:
107                build_module.args_dict['build_target'].arg_value = [
108                    'build_ohos_sdk']
109            build_module.args_dict['target_cpu'].arg_value = 'arm64'
110        elif target_arg.arg_value == 'arkui-x':
111            target_generator = build_module.target_generator
112            target_generator.regist_arg('is_arkui_x', True)
113            target_generator.regist_arg('enable_ng_build', True)
114            target_generator.regist_arg('is_component_build', False)
115            target_generator.regist_arg('use_musl', False)
116            target_generator.regist_arg('is_use_check_deps', False)
117            if len(build_module.args_dict['build_target'].arg_value) == 0:
118                build_module.args_dict['build_target'].arg_value = [
119                    'arkui_targets']
120
121    @staticmethod
122    def resolve_target_cpu(target_arg: Arg, build_module: BuildModuleInterface):
123        """resolve '--target-cpu' arg.
124        :param target_arg: arg object which is used to get arg value.
125        :param build_module [maybe unused]: build module object which is used to get other services.
126        :phase: prebuild.
127        """
128        config = Config()
129        default_build_args = IoUtil.read_json_file(DEFAULT_BUILD_ARGS)
130        if config.target_cpu == "":
131            config.target_cpu = target_arg.arg_value
132        elif target_arg.arg_value != default_build_args.get("target_cpu").get("argDefault"):
133            config.target_cpu = target_arg.arg_value
134
135    @staticmethod
136    def resolve_target_os(target_arg: Arg, build_module: BuildModuleInterface):
137        """resolve '--target-os' arg.
138        :param target_arg: arg object which is used to get arg value.
139        :param build_module [maybe unused]: build module object which is used to get other services.
140        :phase: prebuild.
141        """
142        config = Config()
143        default_build_args = IoUtil.read_json_file(DEFAULT_BUILD_ARGS)
144        if config.target_os == "":
145            config.target_os = target_arg.arg_value
146        elif target_arg.arg_value != default_build_args.get("target_os").get("argDefault"):
147            config.target_os = target_arg.arg_value
148
149    @staticmethod
150    def resolve_precise_branch(target_arg: Arg, build_module: BuildModuleInterface):
151        """resolve '--precise-branch' arg.
152        :param target_arg: arg object which is used to get arg value.
153        :param build_module [maybe unused]: build module object which is used to get other services.
154        :phase: prebuild.
155        """
156        config = Config()
157        default_build_args = IoUtil.read_json_file(DEFAULT_BUILD_ARGS)
158        if config.precise_branch == "":
159            config.precise_branch = target_arg.arg_value
160        elif target_arg.arg_value != default_build_args.get("precise_branch").get("argDefault"):
161            config.precise_branch = target_arg.arg_value
162
163    @staticmethod
164    def get_tdd_repository(input_file):
165        if not os.path.isfile(input_file):
166            raise OHOSException(f'{input_file} not found')
167        config = Config()
168        target_set = set()
169        with open(input_file, 'r') as input_f:
170            data = csv.DictReader(input_f)
171            for csv_row in data:
172                if csv_row.get(config.precise_branch) == 'Y' or csv_row.get('dayu200_tdd') == 'Y':
173                    target_set.add(csv_row['repoistory'])
174        return target_set
175
176    @staticmethod
177    def is_self_build(target, build_module: BuildModuleInterface):
178        change_info_file = 'change_info.json'
179        if not os.path.exists(change_info_file):
180            return True
181        change_info = IoUtil.read_json_file(change_info_file)
182        change_files = []
183        file_operations = {
184            "added": lambda x: x,
185            "rename": lambda x: [item for pair in x for item in pair],
186            "modified": lambda x: x,
187            "deleted": lambda x: x
188        }
189
190        for value in change_info.values():
191            if value.get("name") != target:
192                continue
193            changed_files = value.get("changed_file_list", {})
194            for op, processor in file_operations.items():
195                if op not in changed_files:
196                    continue
197                if any("include" in f or "interface" in f for f in processor(changed_files[op])):
198                    print(processor(changed_files[op]))
199                    return False
200        return True
201
202    @staticmethod
203    def get_tdd_build_target(build_target_arg, build_module: BuildModuleInterface):
204        parts_file = os.path.join(CURRENT_OHOS_ROOT, 'test/testfwk/developer_test/precise_compilation/part_tdd.json')
205        tdd_manifest_file = os.path.join(CURRENT_OHOS_ROOT, '.repo/manifests/matrix_product.csv')
206        parts_data = IoUtil.read_json_file(parts_file)
207        repository_set = BuildArgsResolver.get_tdd_repository(tdd_manifest_file)
208        config = Config()
209        prefix = 'out/{}/build_configs/'.format(config.product)
210        target_name = build_target_arg[len('TDD'):]
211        build_targets = []
212        for target in target_name.split(','):
213            if target not in repository_set:
214                print('{} not find in csv!'.format(target))
215                continue
216            for item in parts_data:
217                if item['name'] == target:
218                    new_targets = ([prefix + test_target for test_target in item['selfTarget'].split(',')]
219                                   if BuildArgsResolver.is_self_build(target, build_module)
220                                   else [prefix + test_target for test_target in item['buildTarget'].split(',')])
221                    build_targets.extend(new_targets)
222                    break
223            else:
224                build_targets = ['build/ohos/packages:build_all_test_pkg']
225                target_generator = build_module.target_generator
226                target_generator.regist_arg('use_thin_lto', False)
227                break
228        return build_targets
229
230    @staticmethod
231    @throw_exception
232    def resolve_build_target(target_arg: Arg, build_module: BuildModuleInterface):
233        """resolve '--build-target' arg.
234        :param target_arg: arg object which is used to get arg value.
235        :param build_module [maybe unused]: build module object which is used to get other services.
236        :phase: prebuild.
237        :raise OHOSException: when build target not exist in compiling product.
238        """
239        config = Config()
240        build_executor = build_module.target_compiler
241        target_list = []
242        test_target_list = ['build_all_test_pkg', 'package_testcase', 'package_testcase_mlf']
243        if len(target_arg.arg_value):
244            for target_name in target_arg.arg_value:
245                if target_name.endswith('make_test') or target_name.split(':')[-1] in test_target_list:
246                    target_generator = build_module.target_generator
247                    target_generator.regist_arg('use_thin_lto', False)
248                    target_list.append(target_name)
249                elif target_name.startswith('TDD'):
250                    target_list.extend(BuildArgsResolver.get_tdd_build_target(target_name, build_module))
251                else:
252                    target_list.append(target_name)
253        else:
254            if os.getcwd() == CURRENT_OHOS_ROOT:
255                target_list = ['images']
256            elif ComponentUtil.is_in_component_dir(os.getcwd()) and \
257                    ComponentUtil.is_component_in_product(
258                    ComponentUtil.get_component_name(os.getcwd()), Config().product):
259                component_name = ComponentUtil.get_component_name(os.getcwd())
260                LogUtil.write_log(Config().log_path, 'In the component "{}" directory,'
261                                  'this compilation will compile only this component'.format(
262                                      component_name),
263                                  'warning')
264                target_list.append(component_name)
265                target_list.append(component_name + '_test')
266            else:
267                component_name = ComponentUtil.get_component_name(os.getcwd())
268                component_name = os.path.basename(
269                    os.getcwd()) if component_name == '' else component_name
270                raise OHOSException('There is no target component "{}" for the current product "{}"'
271                                    .format(component_name, Config().product), "4001")
272        build_executor.regist_arg('build_target', target_list)
273
274    @staticmethod
275    def resolve_rename_last_log(target_arg: Arg, build_module: BuildModuleInterface):
276        """resolve '--rename-last-log' arg
277        :param target_arg: arg object which is used to get arg value.
278        :param build_module [maybe unused]: build module object which is used to get other services.
279        :phase: prebuild.
280        """
281        if target_arg.arg_value:
282            config = Config()
283            out_path = config.out_path
284            logfile = os.path.join(out_path, 'build.log')
285            if os.path.exists(logfile):
286                mtime = os.stat(logfile).st_mtime
287                rename_file(logfile, '{}/build.{}.log'.format(out_path, mtime))
288
289    @staticmethod
290    def resolve_log_mode(target_arg: Arg, build_module: BuildModuleInterface):
291        """resolve '--log-mode' arg
292        :param target_arg: arg object which is used to get arg value.
293        :param build_module: build module object which is used to get other services.
294        :phase: prebuild.
295        """
296        if target_arg.arg_value:
297            config = Config()
298            config.log_mode = target_arg.arg_value
299
300    @staticmethod
301    def resolve_ccache(target_arg: Arg, build_module: BuildModuleInterface):
302        """resolve '--ccache' arg
303        :param target_arg: arg object which is used to get arg value.
304        :param build_module [maybe unused]: build module object which is used to get other services.
305        :phase: prebuild.
306        """
307        if target_arg.arg_value:
308            config = Config()
309            ccache_path = find_executable('ccache')
310            if ccache_path is None:
311                LogUtil.hb_warning('Failed to find ccache, ccache disabled.')
312                return
313            else:
314                target_generator = build_module.target_generator
315                target_generator.regist_arg(
316                    'ohos_build_enable_ccache', target_arg.arg_value)
317
318            ccache_local_dir = os.environ.get('CCACHE_LOCAL_DIR')
319            ccache_base = os.environ.get('CCACHE_BASE')
320            if not ccache_local_dir:
321                ccache_local_dir = '.ccache'
322            if not ccache_base:
323                ccache_base = os.environ.get('HOME')
324            ccache_base = os.path.join(ccache_base, ccache_local_dir)
325            if not os.path.exists(ccache_base):
326                os.makedirs(ccache_base, exist_ok=True)
327
328            ccache_log_suffix = os.environ.get('CCACHE_LOG_SUFFIX')
329            if ccache_log_suffix:
330                logfile = os.path.join(
331                    ccache_base, "ccache.{}.log".format(ccache_log_suffix))
332            elif os.environ.get('CCACHE_LOGFILE'):
333                logfile = os.environ.get('CCACHE_LOGFILE')
334                if not os.path.exists(os.path.dirname(logfile)):
335                    os.makedirs(os.path.dirname(logfile), exist_ok=True)
336            else:
337                logfile = os.path.join(ccache_base, "ccache.log")
338            if os.path.exists(logfile):
339                oldfile = '{}.old'.format(logfile)
340                if os.path.exists(oldfile):
341                    os.unlink(oldfile)
342                rename_file(logfile, oldfile)
343
344            os.environ['CCACHE_EXEC'] = ccache_path
345            os.environ['CCACHE_LOGFILE'] = logfile
346            os.environ['USE_CCACHE'] = '1'
347            os.environ['CCACHE_DIR'] = ccache_base
348            os.environ['CCACHE_UMASK'] = '002'
349            os.environ['CCACHE_BASEDIR'] = config.root_path
350            ccache_max_size = os.environ.get('CCACHE_MAXSIZE')
351            if not ccache_max_size:
352                ccache_max_size = '100G'
353
354            cmd = ['ccache', '-M', ccache_max_size]
355
356            SystemUtil.exec_command(cmd, log_path=config.log_path)
357
358    @staticmethod
359    def resolve_xcache(target_arg: Arg, build_module: BuildModuleInterface):
360        """resolve '--xcache' arg
361        :param target_arg: arg object which is used to get arg value.
362        :param build_module [maybe unused]: build module object which is used to get other services.
363        :phase: prebuild.
364        """
365        if target_arg.arg_value:
366            config = Config()
367            xcache_path = "/opt/buildtools/nextbuild/xcache"
368            if not os.path.exists(xcache_path):
369                LogUtil.hb_warning('Failed to find xcache, xcache disabled.')
370                return
371            else:
372                target_generator = build_module.target_generator
373                target_generator.regist_arg(
374                    'ohos_build_enable_xcache', target_arg.arg_value)
375                os.environ['XCACHE_EXEC'] = xcache_path
376                os.environ['USE_XCACHE'] = '1'
377
378    @staticmethod
379    def resolve_pycache(target_arg: Arg, build_module: BuildModuleInterface):
380        """resolve '--enable-pycache' arg
381        :param target_arg: arg object which is used to get arg value.
382        :param build_module [maybe unused]: build module object which is used to get other services.
383        :phase: prebuild.
384        """
385        if target_arg.arg_value:
386            config = Config()
387            pycache_dir = os.environ.get('CCACHE_BASE')
388            # The default value is HOME for local users
389            if not pycache_dir:
390                pycache_dir = os.environ.get('HOME')
391            pycache_dir = os.path.join(pycache_dir, '.pycache')
392            os.environ['PYCACHE_DIR'] = pycache_dir
393            pyd_start_cmd = [
394                'python3',
395                '{}/build/scripts/util/pyd.py'.format(config.root_path),
396                '--root',
397                pycache_dir,
398                '--start',
399            ]
400            cmd = ['/bin/bash', '-c', ' '.join(pyd_start_cmd), '&']
401            subprocess.Popen(cmd)
402
403    @staticmethod
404    def resolve_full_compilation(target_arg: Arg, build_module: BuildModuleInterface):
405        """resolve '--full-compilation' arg
406        :param target_arg: arg object which is used to get arg value.
407        :param build_module [maybe unused]: build module object which is used to get other services.
408        :phase: prebuild.
409        """
410        if target_arg.arg_value:
411            build_executor = build_module.target_compiler
412            target_list = build_executor.args_dict.get('build_target', None)
413            if isinstance(target_list, list):
414                target_list.append('make_all')
415                target_list.append('make_test')
416            else:
417                build_executor.regist_arg(
418                    'build_target', ['make_all', 'make_test'])
419            target_generator = build_module.target_generator
420            target_generator.regist_arg('use_thin_lto', False)
421
422    @staticmethod
423    @throw_exception
424    def resolve_gn_args(target_arg: Arg, build_module: BuildModuleInterface):
425        """resolve '--gn-args' arg
426        :param target_arg: arg object which is used to get arg value.
427        :param build_module [maybe unused]: build module object which is used to get other services.
428        :phase: prebuild.
429        :raise OHOSException: when some gn_arg is not in 'key=value' format.
430        """
431        target_generator = build_module.target_generator
432        target_generator.regist_arg(
433            'device_type', build_module.args_dict['device_type'].arg_value)
434        target_generator.regist_arg(
435            'build_variant', build_module.args_dict['build_variant'].arg_value)
436        if target_generator.args_dict['product_name'] == 'rk3568' and not build_module.loader.args_dict['build_xts']:
437            target_generator.regist_arg('ohos_components_checktype', 4)
438            target_generator.regist_arg('ohos_interception_rule_switch', 1023)
439
440        for gn_args in target_arg.arg_value:
441            try:
442                gn_args_list = gn_args.split()
443                for gn_arg in gn_args_list:
444                    variable, value = gn_arg.split('=')
445                    if TypeCheckUtil.is_bool_type(value):
446                        if str(value).lower() == 'false':
447                            convert_value = False
448                        elif str(value).lower() == 'true':
449                            convert_value = True
450                    elif TypeCheckUtil.is_int_type(value):
451                        convert_value = int(value)
452                    elif isinstance(value, list):
453                        convert_value = list(value)
454                    else:
455                        convert_value = str(value).strip('"')
456                    target_generator.regist_arg(variable, convert_value)
457            except ValueError:
458                raise OHOSException(f'Invalid gn args: {gn_arg}', "0001")
459
460    @staticmethod
461    @throw_exception
462    def resolve_gn_flags(target_arg: Arg, build_module: BuildModuleInterface):
463        """resolve '--gn-flags' arg
464        :param target_arg: arg object which is used to get arg value.
465        :param build_module [maybe unused]: build module object which is used to get other services.
466        :phase: targetGenerate.
467        :raise OHOSException: when some gn_arg is not in 'key=value' format.
468        """
469        target_generator = build_module.target_generator
470        gn_flags_list = []
471        for gn_flags in target_arg.arg_value:
472            gn_flags = re.sub("'", "", gn_flags)
473            gn_flags_list.append(gn_flags)
474        target_generator.regist_flag('gn_flags', gn_flags_list)
475
476    @staticmethod
477    @throw_exception
478    def resolve_ninja_args(target_arg: Arg, build_module: BuildModuleInterface):
479        """resolve '--ninja-args' arg
480        :param target_arg: arg object which is used to get arg value.
481        :param build_module [maybe unused]: build module object which is used to get other services.
482        :phase: prebuild.
483        :raise OHOSException: when the value of the ninja parameter does not use quotation marks.
484        """
485        build_executor = build_module.target_compiler
486        ninja_args_list = []
487        for ninja_arg in target_arg.arg_value:
488            ninja_arg = re.sub("'", "", ninja_arg)
489            ninja_args_list.append(ninja_arg)
490        build_executor.regist_arg('ninja_args', ninja_args_list)
491
492    @staticmethod
493    @throw_exception
494    def resolve_strict_mode(target_arg: Arg, build_module: BuildModuleInterface):
495        """resolve '--strict-mode' arg.
496        :param target_arg: arg object which is used to get arg value.
497        :param build_module [maybe unused]: build module object which is used to get other services.
498        :phase: load.
499        :raise OHOSException: when preloader or loader results not correct
500        """
501        if target_arg.arg_value:
502            preloader = build_module.preloader
503            loader = build_module.loader
504            if not preloader.outputs.check_outputs():
505                raise OHOSException('Preloader result not correct', "1001")
506            if not loader.outputs.check_outputs():
507                raise OHOSException('Loader result not correct ', "2001")
508
509    @staticmethod
510    def resolve_scalable_build(target_arg: Arg, build_module: BuildModuleInterface):
511        """resolve '--scalable-build' arg.
512        :param target_arg: arg object which is used to get arg value.
513        :param build_module [maybe unused]: build module object which is used to get other services.
514        :phase: load.
515        """
516        loader = build_module.loader
517        loader.regist_arg("scalable_build", target_arg.arg_value)
518
519    @staticmethod
520    def resolve_build_example(target_arg: Arg, build_module: BuildModuleInterface):
521        """resolve '--build-example' arg.
522        :param target_arg: arg object which is used to get arg value.
523        :param build_module [maybe unused]: build module object which is used to get other services.
524        :phase: load.
525        """
526        loader = build_module.loader
527        loader.regist_arg("build_example", target_arg.arg_value)
528
529    @staticmethod
530    def resolve_build_platform_name(target_arg: Arg, build_module: BuildModuleInterface):
531        """resolve '---build-platform-name' arg
532        :param target_arg: arg object which is used to get arg value.
533        :param build_module [maybe unused]: build module object which is used to get other services.
534        :phase: load.
535        """
536        loader = build_module.loader
537        loader.regist_arg("build_platform_name", target_arg.arg_value)
538
539    @staticmethod
540    def resolve_build_xts(target_arg: Arg, build_module: BuildModuleInterface):
541        """resolve '--build-xts' arg
542        :param target_arg: arg object which is used to get arg value.
543        :param build_module [maybe unused]: build module object which is used to get other services.
544        :phase: load.
545        """
546        loader = build_module.loader
547        loader.regist_arg("build_xts", target_arg.arg_value)
548        for gn_arg in build_module.args_dict['gn_args'].arg_value:
549            if 'pr_path_list' in gn_arg:
550                build_module.args_dict['gn_args'].arg_value.append("precise_xts=true")
551                config = Config()
552                variable, value = gn_arg.split('=')
553                pyd_start_cmd = [
554                    'python3',
555                    '{}/test/xts/acts/get_dependency.py'.format(config.root_path),
556                    value,
557                ]
558                subprocess.call(pyd_start_cmd)
559            if 'build_xts' in gn_arg:
560                variable, value = gn_arg.split('=')
561                if str(value).lower() == 'false':
562                    value = False
563                elif str(value).lower() == 'true':
564                    value = True
565                loader.regist_arg(variable, value)
566
567    @staticmethod
568    def resolve_ignore_api_check(target_arg: Arg, build_module: BuildModuleInterface):
569        """resolve '--ignore-api-check' arg
570        :param target_arg: arg object which is used to get arg value.
571        :param build_module [maybe unused]: build module object which is used to get other services.
572        :phase: load.
573        """
574        loader = build_module.loader
575        if len(target_arg.arg_value):
576            loader.regist_arg("ignore_api_check", target_arg.arg_value)
577        else:
578            loader.regist_arg("ignore_api_check", [
579                              'xts', 'common', 'testfwk'])
580
581    @staticmethod
582    def resolve_load_test_config(target_arg: Arg, build_module: BuildModuleInterface):
583        """resolve '--load-test-config' arg
584        :param target_arg: arg object which is used to get arg value.
585        :param build_module [maybe unused]: build module object which is used to get other services.
586        :phase: load.
587        """
588        loader = build_module.loader
589        loader.regist_arg("load_test_config", target_arg.arg_value)
590
591    @staticmethod
592    @throw_exception
593    def resolve_export_para(target_arg: Arg, build_module: BuildModuleInterface):
594        """resolve '--export-para' arg
595        :param target_arg: arg object which is used to get arg value.
596        :param build_module [maybe unused]: build module object which is used to get other services.
597        :phase: targetGenerate.
598        """
599        target_generator = build_module.target_generator
600        for gn_arg in target_arg.arg_value:
601            try:
602                variable, value = gn_arg.split(':')
603                if TypeCheckUtil.is_bool_type(value):
604                    if str(value).lower() == 'false':
605                        value = False
606                    elif str(value).lower() == 'true':
607                        value = True
608                elif TypeCheckUtil.is_int_type(value):
609                    value = int(value)
610                else:
611                    value = str(value)
612                target_generator.regist_arg(variable, value)
613            except ValueError:
614                raise OHOSException(f'Invalid gn args: {gn_arg}', "0001")
615
616    @staticmethod
617    def resolve_log_level(target_arg: Arg, build_module: BuildModuleInterface):
618        """resolve '--log-level' arg.
619        :param target_arg: arg object which is used to get arg value.
620        :param build_module [maybe unused]: build module object which is used to get other services.
621        :phase: targetGenerate.
622        """
623        if target_arg.arg_value == 'debug':
624            target_generator = build_module.target_generator
625            target_compiler = build_module.target_compiler
626            target_generator.regist_flag('-v', ''),
627            target_generator.regist_flag(
628                '--tracelog', '{}/gn_trace.log'.format(Config().out_path))
629            target_generator.regist_flag('--ide', 'json')
630            target_compiler.regist_arg('-v', '')
631
632    @staticmethod
633    @throw_exception
634    def resolve_test(target_arg: Arg, build_module: BuildModuleInterface):
635        """resolve '--test' arg
636        :param target_arg: arg object which is used to get arg value.
637        :param build_module [maybe unused]: build module object which is used to get other services.
638        :phase: targetGenerate.
639        """
640        if len(target_arg.arg_value) > 1:
641            target_generator = build_module.target_generator
642            # TODO: Ask sternly why the xts subsystem passes parameters in this way?
643            if 'notest' in target_arg.arg_value:
644                target_generator.regist_arg('ohos_test_args', 'notest')
645            elif 'xts' in target_arg.arg_value:
646                test_target_index = 1
647                if target_arg.arg_value.index('xts') == 1:
648                    test_target_index = 0
649                target_generator.regist_arg(
650                    'ohos_xts_test_args', target_arg.arg_value[test_target_index])
651            else:
652                raise OHOSException('Test type value "{}" is not support'
653                                    .format(target_arg.arg_value), "0002")
654
655    @staticmethod
656    def resolve_build_type(target_arg: Arg, build_module: BuildModuleInterface):
657        """resolve '--build-type' arg
658        :param target_arg: arg object which is used to get arg value.
659        :param build_module [maybe unused]: build module object which is used to get other services.
660        :phase: targetGenerate.
661        """
662        target_generator = build_module.target_generator
663        if target_arg.arg_value == 'debug':
664            target_generator.regist_arg('is_debug', True)
665        elif target_arg.arg_value == 'profile':
666            target_generator.regist_arg('is_profile', True)
667        # For historical reasons, this value must be debug
668        target_generator.regist_arg('ohos_build_type', 'debug')
669
670    @staticmethod
671    def resolve_root_perf_main(target_arg: Arg, build_module: BuildModuleInterface):
672        """resolve '--root-perf-main' arg
673        :param target_arg: arg object which is used to get arg value.
674        :param build_module [maybe unused]: build module object which is used to get other services.
675        :phase: targetGenerate.
676        """
677        target_generator = build_module.target_generator
678        target_generator.regist_arg('root_perf_main', target_arg.arg_value)
679
680    @staticmethod
681    def resolve_runtime_mode(target_arg: Arg, build_module: BuildModuleInterface):
682        """resolve '--runtime-mode' arg
683        :param target_arg: arg object which is used to get arg value.
684        :param build_module [maybe unused]: build module object which is used to get other services.
685        :phase: targetGenerate.
686        """
687        target_generator = build_module.target_generator
688        target_generator.regist_arg('runtime_mode', target_arg.arg_value)
689
690    @staticmethod
691    def resolve_keep_ninja_going(target_arg: Arg, build_module: BuildModuleInterface):
692        """resolve '--keep-ninja-going' arg
693        :param target_arg: arg object which is used to get arg value.
694        :param build_module [maybe unused]: build module object which is used to get other services.
695        :phase: targetCompilation.
696        """
697        if target_arg.arg_value:
698            target_compiler = build_module.target_compiler
699            target_compiler.regist_arg('-k1000000', '')
700
701    @staticmethod
702    def resolve_build_variant(target_arg: Arg, build_module: BuildModuleInterface):
703        """resolve '--build-variant' arg
704        :param target_arg: arg object which is used to get arg value.
705        :param build_module [maybe unused]: build module object which is used to get other services.
706        :phase: postTargetCompilation.
707        """
708        pass
709
710    @staticmethod
711    def resolve_device_type(target_arg: Arg, build_module: BuildModuleInterface):
712        """resolve '--device-type' arg
713        :param target_arg: arg object which is used to get arg value.
714        :param build_module [maybe unused]: build module object which is used to get other services.
715        :phase: postTargetCompilation.
716        """
717        config = Config()
718        ohos_para_data = []
719        ohos_para_file_path = os.path.join(
720            config.out_path, 'packages/phone/system/etc/param/ohos.para')
721        if target_arg.arg_value != 'default':
722            with os.fdopen(os.open(ohos_para_file_path,
723                                   os.O_RDWR | os.O_CREAT, stat.S_IWUSR | stat.S_IRUSR),
724                           'r', encoding='utf-8') as ohos_para_file:
725                for line in ohos_para_file:
726                    ohos_para_data.append(line)
727            for i, line in enumerate(ohos_para_data):
728                if ohos_para_data[i].__contains__('const.build.characteristics'):
729                    ohos_para_data[i] = 'const.build.characteristics=' + \
730                        target_arg.arg_value + '\n'
731                    break
732            data = ''
733            for line in ohos_para_data:
734                data += line
735            with os.fdopen(os.open(ohos_para_file_path,
736                                   os.O_RDWR | os.O_CREAT, stat.S_IWUSR | stat.S_IRUSR),
737                           'w', encoding='utf-8') as ohos_para_file:
738                ohos_para_file.write(data)
739
740    @staticmethod
741    def resolve_archive_image(target_arg: Arg, build_module: BuildModuleInterface):
742        """resolve '--archive-image' arg
743        :param target_arg: arg object which is used to get arg value.
744        :param build_module [maybe unused]: build module object which is used to get other services.
745        :phase: postTargetCompilation
746        """
747        if target_arg.arg_value:
748            config = Config()
749            image_path = os.path.join(
750                config.out_path, 'packages', 'phone', 'images')
751            if os.path.exists(image_path):
752                packaged_file_path = os.path.join(
753                    config.out_path, 'images.tar.gz')
754                cmd = ['tar', '-zcvf', packaged_file_path, image_path]
755                SystemUtil.exec_command(cmd, log_path=config.out_path)
756            else:
757                LogUtil.hb_info(
758                    '"--archive-image" option not work, cause the currently compiled product is not a standard product')
759
760    @staticmethod
761    def resolve_patch(target_arg: Arg, build_module: BuildModuleInterface):
762        """resolve '--patch' arg
763        :param target_arg: arg object which is used to get arg value.
764        :param build_module [maybe unused]: build module object which is used to get other services.
765        :phase: postTargetCompilation
766        """
767        if target_arg.arg_value:
768            patch_obj = Patch()
769            patch_obj.patch_make()
770
771    @staticmethod
772    def resolve_rom_size_statistics(target_arg: Arg, build_module: BuildModuleInterface):
773        """resolve '--rom-size-statistics' arg
774        :param target_arg: arg object which is used to get arg value.
775        :param build_module [maybe unused]: build module object which is used to get other services.
776        :phase: postTargetCompilation
777        """
778        if target_arg.arg_value:
779            output_part_rom_status(CURRENT_OHOS_ROOT)
780
781    @staticmethod
782    def resolve_stat_ccache(target_arg: Arg, build_module: BuildModuleInterface):
783        """resolve "--stat-ccache' arg
784        :param target_arg: arg object which is used to get arg value.
785        :param build_module [maybe unused]: build module object which is used to get other services.
786        :phase: postTargetCompilation
787        """
788        if target_arg.arg_value:
789            config = Config()
790            ccache_path = find_executable('ccache')
791            if ccache_path is None:
792                LogUtil.hb_warning('Failed to find ccache, ccache disabled.')
793                return
794            ccache_log_suffix = os.environ.get('CCACHE_LOG_SUFFIX')
795            if ccache_log_suffix:
796                logfile = "ccache.{}.log".format(ccache_log_suffix)
797            else:
798                logfile = "ccache.log"
799            ccache_local_dir = os.environ.get('CCACHE_LOCAL_DIR')
800            if not ccache_local_dir:
801                ccache_local_dir = '.ccache'
802            ccache_base = os.environ.get('CCACHE_BASE')
803
804            # The default value is HOME for local users
805            if not ccache_base:
806                ccache_base = os.environ.get('HOME')
807            ccache_base = os.path.join(ccache_base, ccache_local_dir)
808            if os.environ.get('CCACHE_LOGFILE'):
809                logfile = os.environ.get('CCACHE_LOGFILE')
810            else:
811                logfile = os.path.join(ccache_base, logfile)
812            cmd = [
813                'python3', '{}/build/scripts/summary_ccache_hitrate.py'.format(
814                    config.root_path), logfile
815            ]
816            if os.path.isfile(logfile):
817                SystemUtil.exec_command(cmd, log_path=config.log_path, log_stage="[POSTBUILD]")
818
819    @staticmethod
820    def resolve_get_warning_list(target_arg: Arg, build_module: BuildModuleInterface):
821        """resolve "--get-warning-list' arg
822        :param target_arg: arg object which is used to get arg value.
823        :param build_module [maybe unused]: build module object which is used to get other services.
824        :phase: postTargetCompilation
825        """
826        if target_arg.arg_value:
827            config = Config()
828            cmd = [
829                'python3',
830                '{}/build/scripts/get_warnings.py'.format(config.root_path),
831                '--build-log-file',
832                '{}/build.log'.format(config.out_path),
833                '--warning-out-file',
834                '{}/packages/WarningList.txt'.format(config.out_path),
835            ]
836            SystemUtil.exec_command(cmd, log_path=config.log_path, log_stage="[POSTBUILD]")
837
838    @staticmethod
839    def resolve_generate_ninja_trace(target_arg: Arg, build_module: BuildModuleInterface):
840        """resolve "--generate-ninja-trace' arg
841        :param target_arg: arg object which is used to get arg value.
842        :param build_module [maybe unused]: build module object which is used to get other services.
843        :phase: postTargetCompilation
844        """
845        if target_arg.arg_value:
846            config = Config()
847            # 中国标准时间与UTC标准时间差8h, _start_time记录为中国标准时间
848            epoch = datetime.utcfromtimestamp(28800)
849            unixtime = '%f' % (
850                (build_module.target_compiler._start_time - epoch).total_seconds() * 10**9)
851            cmd = [
852                'python3',
853                '{}/build/scripts/ninja2trace.py'.format(config.root_path),
854                '--ninja-log',
855                '{}/.ninja_log'.format(config.out_path),
856                "--trace-file",
857                "{}/build.trace".format(config.out_path),
858                "--ninja-start-time",
859                str(unixtime),
860                "--duration-file",
861                "{}/sorted_action_duration.txt".format(config.out_path),
862            ]
863            SystemUtil.exec_command(cmd, log_path=config.log_path, log_stage="[POSTBUILD]")
864
865    @staticmethod
866    def resolve_compute_overlap_rate(target_arg: Arg, build_module: BuildModuleInterface):
867        """resolve "--compute-overlap-rate' arg
868        :param target_arg: arg object which is used to get arg value.
869        :param build_module [maybe unused]: build module object which is used to get other services.
870        :phase: postTargetCompilation
871        """
872        if target_arg.arg_value:
873            config = Config()
874            subsystem_config_overlay_path = os.path.join(config.product_path,
875                                                         'subsystem_config_overlay.json')
876            if os.path.isfile(subsystem_config_overlay_path):
877                cmd = [
878                    'python3',
879                    '{}/build/ohos/statistics/build_overlap_statistics.py'.format(
880                        config.root_path), "--build-out-dir", config.out_path,
881                    "--subsystem-config-file",
882                    "{}/build/subsystem_config.json".format(config.root_path),
883                    "--subsystem-config-overlay-file",
884                    "{}/subsystem_config_overlay.json".format(
885                        config.product_path),
886                    "--root-source-dir", config.root_path
887                ]
888            else:
889                cmd = [
890                    'python3',
891                    '{}/build/ohos/statistics/build_overlap_statistics.py'.format(
892                        config.root_path), "--build-out-dir", config.out_path,
893                    "--subsystem-config-file",
894                    "{}/build/subsystem_config.json".format(config.root_path),
895                    "--root-source-dir", config.root_path
896                ]
897            SystemUtil.exec_command(cmd, log_path=config.log_path, log_stage="[POSTBUILD]")
898
899    @staticmethod
900    def resolve_deps_guard(target_arg: Arg, build_module: BuildModuleInterface):
901        """resolve '--deps-guard' arg
902        :param target_arg: arg object which is used to get arg value.
903        :param build_module [maybe unused]: build module object which is used to get other services.
904        :phase: postbuild
905        """
906        if target_arg.arg_value:
907            config = Config()
908            if config.os_level == "standard":
909                sys.path.append(os.path.join(
910                    config.root_path, "developtools/integration_verification/tools/deps_guard"))
911                from deps_guard import deps_guard
912                deps_guard(config.out_path, config.target_cpu)
913
914    @staticmethod
915    def resolve_skip_partlist_check(target_arg: Arg, build_module: BuildModuleInterface):
916        """resolve '--skip-partlist-check' arg
917        :param target_arg: arg object which is used to get arg value.
918        :param build_module [maybe unused]: build module object which is used to get other services.
919        :phase: load.
920        """
921        loader = build_module.loader
922        loader.regist_arg("skip_partlist_check", target_arg.arg_value)
923
924    @staticmethod
925    def resolve_clean_args(target_arg: Arg, build_module: BuildModuleInterface):
926        """resolve '--clean-args' arg
927        :param target_arg: arg object which is used to get arg value.
928        :param build_module [maybe unused]: build module object which is used to get other services.
929        :phase: postbuild
930        """
931        if target_arg.arg_value:
932            Arg.clean_args_file()
933
934    @staticmethod
935    def resolve_sbom(target_arg: Arg, build_module: BuildModuleInterface):
936        """resolve '--sbom' arg
937        :param target_arg: arg object which is used to get arg value.
938        :param build_module [maybe unused]: build module object which is used to get other services.
939        :phase: postTargetGenerate.
940        """
941        if target_arg.arg_value:
942            config = Config()
943            cmd = [
944                'python3',
945                '{}/build/ohos/sbom/generate_sbom.py'.format(
946                    config.root_path),
947                "--source-root-dir", config.root_path,
948                "--out-dir", config.out_path,
949                "--product", config.product,
950                "--platform", config.platform
951            ]
952            executor = ThreadPoolExecutor(max_workers=1)
953            executor.submit(SystemUtil.exec_command, cmd, log_path=config.log_path, log_stage='[postTargetGenerate]')
954            executor.shutdown(wait=False)
955
956    # PlaceHolder
957    @staticmethod
958    def resolve_compiler(target_arg: Arg, build_module: BuildModuleInterface):
959        return
960
961    # PlaceHolder
962    @staticmethod
963    def resolve_jobs(target_arg: Arg, build_module: BuildModuleInterface):
964        return
965
966    # PlaceHolder
967    @staticmethod
968    def resolve_disable_part_of_post_build(target_arg: Arg, build_module: BuildModuleInterface):
969        return
970
971    # PlaceHolder
972    @staticmethod
973    def resolve_disable_package_image(target_arg: Arg, build_module: BuildModuleInterface):
974        return
975
976    # PlaceHolder
977    @staticmethod
978    def resolve_disable_post_build(target_arg: Arg, build_module: BuildModuleInterface):
979        return
980
981    # PlaceHolder
982    @staticmethod
983    def resolve_build_only_load(target_arg: Arg, build_module: BuildModuleInterface):
984        return
985
986    # PlaceHolder
987    @staticmethod
988    def resolve_build_only_gn(target_arg: Arg, build_module: BuildModuleInterface):
989        return
990
991    # PlaceHolder
992    @staticmethod
993    def resolve_fast_rebuild(target_arg: Arg, build_module: BuildModuleInterface):
994        return
995