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
25
26from datetime import datetime
27from distutils.spawn import find_executable
28from containers.arg import Arg
29from containers.status import throw_exception
30from exceptions.ohos_exception import OHOSException
31from modules.interface.build_module_interface import BuildModuleInterface
32from resources.config import Config
33from resources.global_var import CURRENT_OHOS_ROOT, DEFAULT_BUILD_ARGS
34from resolver.interface.args_resolver_interface import ArgsResolverInterface
35from util.type_check_util import TypeCheckUtil
36from util.io_util import IoUtil
37from util.log_util import LogUtil
38from util.system_util import SystemUtil
39from util.type_check_util import TypeCheckUtil
40from util.component_util import ComponentUtil
41from util.product_util import ProductUtil
42from util.prebuild.patch_process import Patch
43from util.post_build.part_rom_statistics import output_part_rom_status
44from util.post_gn.check_compilation_parameters import check_compilation_parameters
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':
173                    target_set.add(csv_row['repoistory'])
174        return target_set
175
176    @staticmethod
177    def get_tdd_build_target(build_target_arg, build_module: BuildModuleInterface):
178        parts_file = os.path.join(CURRENT_OHOS_ROOT, 'test/testfwk/developer_test/precise_compilation/part_tdd.json')
179        tdd_manifest_file = os.path.join(CURRENT_OHOS_ROOT, '.repo/manifests/matrix_product.csv')
180        parts_data = IoUtil.read_json_file(parts_file)
181        repository_set = BuildArgsResolver.get_tdd_repository(tdd_manifest_file)
182        config = Config()
183        prefix = 'out/{}/build_configs/'.format(config.product)
184        target_name = build_target_arg[len('TDD'):]
185        build_targets = []
186        for target in target_name.split(','):
187            if target not in repository_set:
188                print('{} not find in csv!'.format(target))
189                continue
190            for item in parts_data:
191                if item['name'] == target:
192                    new_targets = [prefix + test_target for test_target in item['buildTarget'].split(',')]
193                    build_targets.extend(new_targets)
194                    break
195            else:
196                build_targets = ['build/ohos/packages:build_all_test_pkg']
197                target_generator = build_module.target_generator
198                target_generator.regist_arg('use_thin_lto', False)
199                break
200        return build_targets
201
202    @staticmethod
203    @throw_exception
204    def resolve_build_target(target_arg: Arg, build_module: BuildModuleInterface):
205        """resolve '--build-target' arg.
206        :param target_arg: arg object which is used to get arg value.
207        :param build_module [maybe unused]: build module object which is used to get other services.
208        :phase: prebuild.
209        :raise OHOSException: when build target not exist in compiling product.
210        """
211        config = Config()
212        build_executor = build_module.target_compiler
213        target_list = []
214        test_target_list = ['build_all_test_pkg', 'package_testcase', 'package_testcase_mlf']
215        if len(target_arg.arg_value):
216            for target_name in target_arg.arg_value:
217                if target_name.endswith('make_test') or target_name.split(':')[-1] in test_target_list:
218                    target_generator = build_module.target_generator
219                    target_generator.regist_arg('use_thin_lto', False)
220                    target_list.append(target_name)
221                elif target_name.startswith('TDD'):
222                    target_list.extend(BuildArgsResolver.get_tdd_build_target(target_name, build_module))
223                else:
224                    target_list.append(target_name)
225        else:
226            if os.getcwd() == CURRENT_OHOS_ROOT:
227                target_list = ['images']
228            elif ComponentUtil.is_in_component_dir(os.getcwd()) and \
229                    ComponentUtil.is_component_in_product(
230                    ComponentUtil.get_component_name(os.getcwd()), Config().product):
231                component_name = ComponentUtil.get_component_name(os.getcwd())
232                LogUtil.write_log(Config().log_path, 'In the component "{}" directory,'
233                                  'this compilation will compile only this component'.format(
234                                      component_name),
235                                  'warning')
236                target_list.append(component_name)
237                target_list.append(component_name + '_test')
238            else:
239                component_name = ComponentUtil.get_component_name(os.getcwd())
240                component_name = os.path.basename(
241                    os.getcwd()) if component_name == '' else component_name
242                raise OHOSException('There is no target component "{}" for the current product "{}"'
243                                    .format(component_name, Config().product), "4001")
244        build_executor.regist_arg('build_target', target_list)
245
246    @staticmethod
247    def resolve_rename_last_log(target_arg: Arg, build_module: BuildModuleInterface):
248        """resolve '--rename-last-log' arg
249        :param target_arg: arg object which is used to get arg value.
250        :param build_module [maybe unused]: build module object which is used to get other services.
251        :phase: prebuild.
252        """
253        if target_arg.arg_value:
254            config = Config()
255            out_path = config.out_path
256            logfile = os.path.join(out_path, 'build.log')
257            if os.path.exists(logfile):
258                mtime = os.stat(logfile).st_mtime
259                rename_file(logfile, '{}/build.{}.log'.format(out_path, mtime))
260
261    @staticmethod
262    def resolve_log_mode(target_arg: Arg, build_module: BuildModuleInterface):
263        """resolve '--log-mode' arg
264        :param target_arg: arg object which is used to get arg value.
265        :param build_module: build module object which is used to get other services.
266        :phase: prebuild.
267        """
268        if target_arg.arg_value:
269            config = Config()
270            config.log_mode = target_arg.arg_value
271
272    @staticmethod
273    def resolve_ccache(target_arg: Arg, build_module: BuildModuleInterface):
274        """resolve '--ccache' arg
275        :param target_arg: arg object which is used to get arg value.
276        :param build_module [maybe unused]: build module object which is used to get other services.
277        :phase: prebuild.
278        """
279        if target_arg.arg_value:
280            config = Config()
281            ccache_path = find_executable('ccache')
282            if ccache_path is None:
283                LogUtil.hb_warning('Failed to find ccache, ccache disabled.')
284                return
285            else:
286                target_generator = build_module.target_generator
287                target_generator.regist_arg(
288                    'ohos_build_enable_ccache', target_arg.arg_value)
289
290            ccache_local_dir = os.environ.get('CCACHE_LOCAL_DIR')
291            ccache_base = os.environ.get('CCACHE_BASE')
292            if not ccache_local_dir:
293                ccache_local_dir = '.ccache'
294            if not ccache_base:
295                ccache_base = os.environ.get('HOME')
296            ccache_base = os.path.join(ccache_base, ccache_local_dir)
297            if not os.path.exists(ccache_base):
298                os.makedirs(ccache_base, exist_ok=True)
299
300            ccache_log_suffix = os.environ.get('CCACHE_LOG_SUFFIX')
301            if ccache_log_suffix:
302                logfile = os.path.join(
303                    ccache_base, "ccache.{}.log".format(ccache_log_suffix))
304            elif os.environ.get('CCACHE_LOGFILE'):
305                logfile = os.environ.get('CCACHE_LOGFILE')
306                if not os.path.exists(os.path.dirname(logfile)):
307                    os.makedirs(os.path.dirname(logfile), exist_ok=True)
308            else:
309                logfile = os.path.join(ccache_base, "ccache.log")
310            if os.path.exists(logfile):
311                oldfile = '{}.old'.format(logfile)
312                if os.path.exists(oldfile):
313                    os.unlink(oldfile)
314                rename_file(logfile, oldfile)
315
316            os.environ['CCACHE_EXEC'] = ccache_path
317            os.environ['CCACHE_LOGFILE'] = logfile
318            os.environ['USE_CCACHE'] = '1'
319            os.environ['CCACHE_DIR'] = ccache_base
320            os.environ['CCACHE_UMASK'] = '002'
321            os.environ['CCACHE_BASEDIR'] = config.root_path
322            ccache_max_size = os.environ.get('CCACHE_MAXSIZE')
323            if not ccache_max_size:
324                ccache_max_size = '100G'
325
326            cmd = ['ccache', '-M', ccache_max_size]
327
328            SystemUtil.exec_command(cmd, log_path=config.log_path)
329
330    @staticmethod
331    def resolve_xcache(target_arg: Arg, build_module: BuildModuleInterface):
332        """resolve '--xcache' arg
333        :param target_arg: arg object which is used to get arg value.
334        :param build_module [maybe unused]: build module object which is used to get other services.
335        :phase: prebuild.
336        """
337        if target_arg.arg_value:
338            config = Config()
339            xcache_path = "/opt/buildtools/nextbuild/xcache"
340            if not os.path.exists(xcache_path):
341                LogUtil.hb_warning('Failed to find xcache, xcache disabled.')
342                return
343            else:
344                target_generator = build_module.target_generator
345                target_generator.regist_arg(
346                    'ohos_build_enable_xcache', target_arg.arg_value)
347                os.environ['XCACHE_EXEC'] = xcache_path
348                os.environ['USE_XCACHE'] = '1'
349
350    @staticmethod
351    def resolve_pycache(target_arg: Arg, build_module: BuildModuleInterface):
352        """resolve '--enable-pycache' arg
353        :param target_arg: arg object which is used to get arg value.
354        :param build_module [maybe unused]: build module object which is used to get other services.
355        :phase: prebuild.
356        """
357        if target_arg.arg_value:
358            config = Config()
359            pycache_dir = os.environ.get('CCACHE_BASE')
360            # The default value is HOME for local users
361            if not pycache_dir:
362                pycache_dir = os.environ.get('HOME')
363            pycache_dir = os.path.join(pycache_dir, '.pycache')
364            os.environ['PYCACHE_DIR'] = pycache_dir
365            pyd_start_cmd = [
366                'python3',
367                '{}/build/scripts/util/pyd.py'.format(config.root_path),
368                '--root',
369                pycache_dir,
370                '--start',
371            ]
372            cmd = ['/bin/bash', '-c', ' '.join(pyd_start_cmd), '&']
373            subprocess.Popen(cmd)
374
375    @staticmethod
376    def resolve_full_compilation(target_arg: Arg, build_module: BuildModuleInterface):
377        """resolve '--full-compilation' arg
378        :param target_arg: arg object which is used to get arg value.
379        :param build_module [maybe unused]: build module object which is used to get other services.
380        :phase: prebuild.
381        """
382        if target_arg.arg_value:
383            build_executor = build_module.target_compiler
384            target_list = build_executor.args_dict.get('build_target', None)
385            if isinstance(target_list, list):
386                target_list.append('make_all')
387                target_list.append('make_test')
388            else:
389                build_executor.regist_arg(
390                    'build_target', ['make_all', 'make_test'])
391            target_generator = build_module.target_generator
392            target_generator.regist_arg('use_thin_lto', False)
393
394    @staticmethod
395    @throw_exception
396    def resolve_gn_args(target_arg: Arg, build_module: BuildModuleInterface):
397        """resolve '--gn-args' arg
398        :param target_arg: arg object which is used to get arg value.
399        :param build_module [maybe unused]: build module object which is used to get other services.
400        :phase: prebuild.
401        :raise OHOSException: when some gn_arg is not in 'key=value' format.
402        """
403        target_generator = build_module.target_generator
404        target_generator.regist_arg(
405            'device_type', build_module.args_dict['device_type'].arg_value)
406        target_generator.regist_arg(
407            'build_variant', build_module.args_dict['build_variant'].arg_value)
408        for gn_args in target_arg.arg_value:
409            try:
410                gn_args_list = gn_args.split()
411                for gn_arg in gn_args_list:
412                    variable, value = gn_arg.split('=')
413                    if TypeCheckUtil.is_bool_type(value):
414                        if str(value).lower() == 'false':
415                            convert_value = False
416                        elif str(value).lower() == 'true':
417                            convert_value = True
418                    elif TypeCheckUtil.is_int_type(value):
419                        convert_value = int(value)
420                    elif isinstance(value, list):
421                        convert_value = list(value)
422                    else:
423                        convert_value = str(value).strip('"')
424                    target_generator.regist_arg(variable, convert_value)
425            except ValueError:
426                raise OHOSException(f'Invalid gn args: {gn_arg}', "0001")
427
428    @staticmethod
429    @throw_exception
430    def resolve_gn_flags(target_arg: Arg, build_module: BuildModuleInterface):
431        """resolve '--gn-flags' arg
432        :param target_arg: arg object which is used to get arg value.
433        :param build_module [maybe unused]: build module object which is used to get other services.
434        :phase: targetGenerate.
435        :raise OHOSException: when some gn_arg is not in 'key=value' format.
436        """
437        target_generator = build_module.target_generator
438        gn_flags_list = []
439        for gn_flags in target_arg.arg_value:
440            gn_flags = re.sub("'", "", gn_flags)
441            gn_flags_list.append(gn_flags)
442        target_generator.regist_flag('gn_flags', gn_flags_list)
443
444    @staticmethod
445    @throw_exception
446    def resolve_ninja_args(target_arg: Arg, build_module: BuildModuleInterface):
447        """resolve '--ninja-args' arg
448        :param target_arg: arg object which is used to get arg value.
449        :param build_module [maybe unused]: build module object which is used to get other services.
450        :phase: prebuild.
451        :raise OHOSException: when the value of the ninja parameter does not use quotation marks.
452        """
453        build_executor = build_module.target_compiler
454        ninja_args_list = []
455        for ninja_arg in target_arg.arg_value:
456            ninja_arg = re.sub("'", "", ninja_arg)
457            ninja_args_list.append(ninja_arg)
458        build_executor.regist_arg('ninja_args', ninja_args_list)
459
460    @staticmethod
461    @throw_exception
462    def resolve_strict_mode(target_arg: Arg, build_module: BuildModuleInterface):
463        """resolve '--strict-mode' 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: load.
467        :raise OHOSException: when preloader or loader results not correct
468        """
469        if target_arg.arg_value:
470            preloader = build_module.preloader
471            loader = build_module.loader
472            if not preloader.outputs.check_outputs():
473                raise OHOSException('Preloader result not correct', "1001")
474            if not loader.outputs.check_outputs():
475                raise OHOSException('Loader result not correct ', "2001")
476
477    @staticmethod
478    def resolve_scalable_build(target_arg: Arg, build_module: BuildModuleInterface):
479        """resolve '--scalable-build' 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: load.
483        """
484        loader = build_module.loader
485        loader.regist_arg("scalable_build", target_arg.arg_value)
486
487    @staticmethod
488    def resolve_build_example(target_arg: Arg, build_module: BuildModuleInterface):
489        """resolve '--build-example' arg.
490        :param target_arg: arg object which is used to get arg value.
491        :param build_module [maybe unused]: build module object which is used to get other services.
492        :phase: load.
493        """
494        loader = build_module.loader
495        loader.regist_arg("build_example", target_arg.arg_value)
496
497    @staticmethod
498    def resolve_build_platform_name(target_arg: Arg, build_module: BuildModuleInterface):
499        """resolve '---build-platform-name' arg
500        :param target_arg: arg object which is used to get arg value.
501        :param build_module [maybe unused]: build module object which is used to get other services.
502        :phase: load.
503        """
504        loader = build_module.loader
505        loader.regist_arg("build_platform_name", target_arg.arg_value)
506
507    @staticmethod
508    def resolve_build_xts(target_arg: Arg, build_module: BuildModuleInterface):
509        """resolve '--build-xts' arg
510        :param target_arg: arg object which is used to get arg value.
511        :param build_module [maybe unused]: build module object which is used to get other services.
512        :phase: load.
513        """
514        loader = build_module.loader
515        loader.regist_arg("build_xts", target_arg.arg_value)
516        for gn_arg in build_module.args_dict['gn_args'].arg_value:
517            if 'pr_path_list' in gn_arg:
518                build_module.args_dict['gn_args'].arg_value.append("precise_xts=true")
519                config = Config()
520                variable, value = gn_arg.split('=')
521                pyd_start_cmd = [
522                    'python3',
523                    '{}/test/xts/acts/get_dependency.py'.format(config.root_path),
524                    value,
525                ]
526                subprocess.call(pyd_start_cmd)
527            if 'build_xts' in gn_arg:
528                variable, value = gn_arg.split('=')
529                if str(value).lower() == 'false':
530                    value = False
531                elif str(value).lower() == 'true':
532                    value = True
533                loader.regist_arg(variable, value)
534
535    @staticmethod
536    def resolve_ignore_api_check(target_arg: Arg, build_module: BuildModuleInterface):
537        """resolve '--ignore-api-check' arg
538        :param target_arg: arg object which is used to get arg value.
539        :param build_module [maybe unused]: build module object which is used to get other services.
540        :phase: load.
541        """
542        loader = build_module.loader
543        if len(target_arg.arg_value):
544            loader.regist_arg("ignore_api_check", target_arg.arg_value)
545        else:
546            loader.regist_arg("ignore_api_check", [
547                              'xts', 'common', 'testfwk'])
548
549    @staticmethod
550    def resolve_load_test_config(target_arg: Arg, build_module: BuildModuleInterface):
551        """resolve '--load-test-config' arg
552        :param target_arg: arg object which is used to get arg value.
553        :param build_module [maybe unused]: build module object which is used to get other services.
554        :phase: load.
555        """
556        loader = build_module.loader
557        loader.regist_arg("load_test_config", target_arg.arg_value)
558
559    @staticmethod
560    @throw_exception
561    def resolve_export_para(target_arg: Arg, build_module: BuildModuleInterface):
562        """resolve '--export-para' arg
563        :param target_arg: arg object which is used to get arg value.
564        :param build_module [maybe unused]: build module object which is used to get other services.
565        :phase: targetGenerate.
566        """
567        target_generator = build_module.target_generator
568        for gn_arg in target_arg.arg_value:
569            try:
570                variable, value = gn_arg.split(':')
571                if TypeCheckUtil.is_bool_type(value):
572                    if str(value).lower() == 'false':
573                        value = False
574                    elif str(value).lower() == 'true':
575                        value = True
576                elif TypeCheckUtil.is_int_type(value):
577                    value = int(value)
578                else:
579                    value = str(value)
580                target_generator.regist_arg(variable, value)
581            except ValueError:
582                raise OHOSException(f'Invalid gn args: {gn_arg}', "0001")
583
584    @staticmethod
585    def resolve_log_level(target_arg: Arg, build_module: BuildModuleInterface):
586        """resolve '--log-level' arg.
587        :param target_arg: arg object which is used to get arg value.
588        :param build_module [maybe unused]: build module object which is used to get other services.
589        :phase: targetGenerate.
590        """
591        if target_arg.arg_value == 'debug':
592            target_generator = build_module.target_generator
593            target_compiler = build_module.target_compiler
594            target_generator.regist_flag('-v', ''),
595            target_generator.regist_flag(
596                '--tracelog', '{}/gn_trace.log'.format(Config().out_path))
597            target_generator.regist_flag('--ide', 'json')
598            target_compiler.regist_arg('-v', '')
599
600    @staticmethod
601    @throw_exception
602    def resolve_test(target_arg: Arg, build_module: BuildModuleInterface):
603        """resolve '--test' arg
604        :param target_arg: arg object which is used to get arg value.
605        :param build_module [maybe unused]: build module object which is used to get other services.
606        :phase: targetGenerate.
607        """
608        if len(target_arg.arg_value) > 1:
609            target_generator = build_module.target_generator
610            # TODO: Ask sternly why the xts subsystem passes parameters in this way?
611            if 'notest' in target_arg.arg_value:
612                target_generator.regist_arg('ohos_test_args', 'notest')
613            elif 'xts' in target_arg.arg_value:
614                test_target_index = 1
615                if target_arg.arg_value.index('xts') == 1:
616                    test_target_index = 0
617                target_generator.regist_arg(
618                    'ohos_xts_test_args', target_arg.arg_value[test_target_index])
619            else:
620                raise OHOSException('Test type value "{}" is not support'
621                                    .format(target_arg.arg_value), "0002")
622
623    @staticmethod
624    def resolve_build_type(target_arg: Arg, build_module: BuildModuleInterface):
625        """resolve '--build-type' arg
626        :param target_arg: arg object which is used to get arg value.
627        :param build_module [maybe unused]: build module object which is used to get other services.
628        :phase: targetGenerate.
629        """
630        target_generator = build_module.target_generator
631        if target_arg.arg_value == 'debug':
632            target_generator.regist_arg('is_debug', True)
633        elif target_arg.arg_value == 'profile':
634            target_generator.regist_arg('is_profile', True)
635        # For historical reasons, this value must be debug
636        target_generator.regist_arg('ohos_build_type', 'debug')
637
638    @staticmethod
639    def resolve_root_perf_main(target_arg: Arg, build_module: BuildModuleInterface):
640        """resolve '--root-perf-main' arg
641        :param target_arg: arg object which is used to get arg value.
642        :param build_module [maybe unused]: build module object which is used to get other services.
643        :phase: targetGenerate.
644        """
645        target_generator = build_module.target_generator
646        target_generator.regist_arg('root_perf_main', target_arg.arg_value)
647
648    @staticmethod
649    def resolve_runtime_mode(target_arg: Arg, build_module: BuildModuleInterface):
650        """resolve '--runtime-mode' arg
651        :param target_arg: arg object which is used to get arg value.
652        :param build_module [maybe unused]: build module object which is used to get other services.
653        :phase: targetGenerate.
654        """
655        target_generator = build_module.target_generator
656        target_generator.regist_arg('runtime_mode', target_arg.arg_value)
657
658    @staticmethod
659    def resolve_check_compilation_parameters(target_arg: Arg, build_module: BuildModuleInterface):
660        """resolve '--check-compilation-parameters' arg
661        :param target_arg: arg object which is used to get arg value.
662        :param build_module [maybe unused]: build module object which is used to get other services.
663        :phase: postTargetGenerate.
664        """
665        if target_arg.arg_value:
666            check_compilation_parameters(CURRENT_OHOS_ROOT)
667
668    @staticmethod
669    def resolve_keep_ninja_going(target_arg: Arg, build_module: BuildModuleInterface):
670        """resolve '--keep-ninja-going' arg
671        :param target_arg: arg object which is used to get arg value.
672        :param build_module [maybe unused]: build module object which is used to get other services.
673        :phase: targetCompilation.
674        """
675        if target_arg.arg_value:
676            target_compiler = build_module.target_compiler
677            target_compiler.regist_arg('-k1000000', '')
678
679    @staticmethod
680    def resolve_build_variant(target_arg: Arg, build_module: BuildModuleInterface):
681        """resolve '--build-variant' arg
682        :param target_arg: arg object which is used to get arg value.
683        :param build_module [maybe unused]: build module object which is used to get other services.
684        :phase: postTargetCompilation.
685        """
686        pass
687
688    @staticmethod
689    def resolve_device_type(target_arg: Arg, build_module: BuildModuleInterface):
690        """resolve '--device-type' arg
691        :param target_arg: arg object which is used to get arg value.
692        :param build_module [maybe unused]: build module object which is used to get other services.
693        :phase: postTargetCompilation.
694        """
695        config = Config()
696        ohos_para_data = []
697        ohos_para_file_path = os.path.join(
698            config.out_path, 'packages/phone/system/etc/param/ohos.para')
699        if target_arg.arg_value != 'default':
700            with os.fdopen(os.open(ohos_para_file_path,
701                                   os.O_RDWR | os.O_CREAT, stat.S_IWUSR | stat.S_IRUSR),
702                           'r', encoding='utf-8') as ohos_para_file:
703                for line in ohos_para_file:
704                    ohos_para_data.append(line)
705            for i, line in enumerate(ohos_para_data):
706                if ohos_para_data[i].__contains__('const.build.characteristics'):
707                    ohos_para_data[i] = 'const.build.characteristics=' + \
708                        target_arg.arg_value + '\n'
709                    break
710            data = ''
711            for line in ohos_para_data:
712                data += line
713            with os.fdopen(os.open(ohos_para_file_path,
714                                   os.O_RDWR | os.O_CREAT, stat.S_IWUSR | stat.S_IRUSR),
715                           'w', encoding='utf-8') as ohos_para_file:
716                ohos_para_file.write(data)
717
718    @staticmethod
719    def resolve_archive_image(target_arg: Arg, build_module: BuildModuleInterface):
720        """resolve '--archive-image' arg
721        :param target_arg: arg object which is used to get arg value.
722        :param build_module [maybe unused]: build module object which is used to get other services.
723        :phase: postTargetCompilation
724        """
725        if target_arg.arg_value:
726            config = Config()
727            image_path = os.path.join(
728                config.out_path, 'packages', 'phone', 'images')
729            if os.path.exists(image_path):
730                packaged_file_path = os.path.join(
731                    config.out_path, 'images.tar.gz')
732                cmd = ['tar', '-zcvf', packaged_file_path, image_path]
733                SystemUtil.exec_command(cmd, log_path=config.out_path)
734            else:
735                LogUtil.hb_info(
736                    '"--archive-image" option not work, cause the currently compiled product is not a standard product')
737
738    @staticmethod
739    def resolve_patch(target_arg: Arg, build_module: BuildModuleInterface):
740        """resolve '--patch' arg
741        :param target_arg: arg object which is used to get arg value.
742        :param build_module [maybe unused]: build module object which is used to get other services.
743        :phase: postTargetCompilation
744        """
745        if target_arg.arg_value:
746            patch_obj = Patch()
747            patch_obj.patch_make()
748
749    @staticmethod
750    def resolve_rom_size_statistics(target_arg: Arg, build_module: BuildModuleInterface):
751        """resolve '--rom-size-statistics' arg
752        :param target_arg: arg object which is used to get arg value.
753        :param build_module [maybe unused]: build module object which is used to get other services.
754        :phase: postTargetCompilation
755        """
756        if target_arg.arg_value:
757            output_part_rom_status(CURRENT_OHOS_ROOT)
758
759    @staticmethod
760    def resolve_stat_ccache(target_arg: Arg, build_module: BuildModuleInterface):
761        """resolve "--stat-ccache' arg
762        :param target_arg: arg object which is used to get arg value.
763        :param build_module [maybe unused]: build module object which is used to get other services.
764        :phase: postTargetCompilation
765        """
766        if target_arg.arg_value:
767            config = Config()
768            ccache_path = find_executable('ccache')
769            if ccache_path is None:
770                LogUtil.hb_warning('Failed to find ccache, ccache disabled.')
771                return
772            ccache_log_suffix = os.environ.get('CCACHE_LOG_SUFFIX')
773            if ccache_log_suffix:
774                logfile = "ccache.{}.log".format(ccache_log_suffix)
775            else:
776                logfile = "ccache.log"
777            ccache_local_dir = os.environ.get('CCACHE_LOCAL_DIR')
778            if not ccache_local_dir:
779                ccache_local_dir = '.ccache'
780            ccache_base = os.environ.get('CCACHE_BASE')
781
782            # The default value is HOME for local users
783            if not ccache_base:
784                ccache_base = os.environ.get('HOME')
785            ccache_base = os.path.join(ccache_base, ccache_local_dir)
786            if os.environ.get('CCACHE_LOGFILE'):
787                logfile = os.environ.get('CCACHE_LOGFILE')
788            else:
789                logfile = os.path.join(ccache_base, logfile)
790            cmd = [
791                'python3', '{}/build/scripts/summary_ccache_hitrate.py'.format(
792                    config.root_path), logfile
793            ]
794            if os.path.isfile(logfile):
795                SystemUtil.exec_command(cmd, log_path=config.log_path)
796
797    @staticmethod
798    def resolve_get_warning_list(target_arg: Arg, build_module: BuildModuleInterface):
799        """resolve "--get-warning-list' arg
800        :param target_arg: arg object which is used to get arg value.
801        :param build_module [maybe unused]: build module object which is used to get other services.
802        :phase: postTargetCompilation
803        """
804        if target_arg.arg_value:
805            config = Config()
806            cmd = [
807                'python3',
808                '{}/build/scripts/get_warnings.py'.format(config.root_path),
809                '--build-log-file',
810                '{}/build.log'.format(config.out_path),
811                '--warning-out-file',
812                '{}/packages/WarningList.txt'.format(config.out_path),
813            ]
814            SystemUtil.exec_command(cmd, log_path=config.log_path)
815
816    @staticmethod
817    def resolve_generate_ninja_trace(target_arg: Arg, build_module: BuildModuleInterface):
818        """resolve "--generate-ninja-trace' arg
819        :param target_arg: arg object which is used to get arg value.
820        :param build_module [maybe unused]: build module object which is used to get other services.
821        :phase: postTargetCompilation
822        """
823        if target_arg.arg_value:
824            config = Config()
825            epoch = datetime.utcfromtimestamp(0)
826            unixtime = '%f' % (
827                (build_module.target_compiler._start_time - epoch).total_seconds() * 10**9)
828            cmd = [
829                'python3',
830                '{}/build/scripts/ninja2trace.py'.format(config.root_path),
831                '--ninja-log',
832                '{}/.ninja_log'.format(config.out_path),
833                "--trace-file",
834                "{}/build.trace".format(config.out_path),
835                "--ninja-start-time",
836                str(unixtime),
837                "--duration-file",
838                "{}/sorted_action_duration.txt".format(config.out_path),
839            ]
840            SystemUtil.exec_command(cmd, log_path=config.log_path)
841
842    @staticmethod
843    def resolve_compute_overlap_rate(target_arg: Arg, build_module: BuildModuleInterface):
844        """resolve "--compute-overlap-rate' arg
845        :param target_arg: arg object which is used to get arg value.
846        :param build_module [maybe unused]: build module object which is used to get other services.
847        :phase: postTargetCompilation
848        """
849        if target_arg.arg_value:
850            config = Config()
851            subsystem_config_overlay_path = os.path.join(config.product_path,
852                                                         'subsystem_config_overlay.json')
853            if os.path.isfile(subsystem_config_overlay_path):
854                cmd = [
855                    'python3',
856                    '{}/build/ohos/statistics/build_overlap_statistics.py'.format(
857                        config.root_path), "--build-out-dir", config.out_path,
858                    "--subsystem-config-file",
859                    "{}/build/subsystem_config.json".format(config.root_path),
860                    "--subsystem-config-overlay-file",
861                    "{}/subsystem_config_overlay.json".format(
862                        config.product_path),
863                    "--root-source-dir", config.root_path
864                ]
865            else:
866                cmd = [
867                    'python3',
868                    '{}/build/ohos/statistics/build_overlap_statistics.py'.format(
869                        config.root_path), "--build-out-dir", config.out_path,
870                    "--subsystem-config-file",
871                    "{}/build/subsystem_config.json".format(config.root_path),
872                    "--root-source-dir", config.root_path
873                ]
874            SystemUtil.exec_command(cmd, log_path=config.log_path)
875
876    @staticmethod
877    def resolve_deps_guard(target_arg: Arg, build_module: BuildModuleInterface):
878        """resolve '--deps-guard' arg
879        :param target_arg: arg object which is used to get arg value.
880        :param build_module [maybe unused]: build module object which is used to get other services.
881        :phase: postbuild
882        """
883        if target_arg.arg_value:
884            config = Config()
885            if config.os_level == "standard":
886                sys.path.append(os.path.join(
887                    config.root_path, "developtools/integration_verification/tools/deps_guard"))
888                from deps_guard import deps_guard
889                deps_guard(config.out_path, config.target_cpu)
890
891    @staticmethod
892    def resolve_skip_partlist_check(target_arg: Arg, build_module: BuildModuleInterface):
893        """resolve '--skip-partlist-check' arg
894        :param target_arg: arg object which is used to get arg value.
895        :param build_module [maybe unused]: build module object which is used to get other services.
896        :phase: load.
897        """
898        loader = build_module.loader
899        loader.regist_arg("skip_partlist_check", target_arg.arg_value)
900
901    @staticmethod
902    def resolve_clean_args(target_arg: Arg, build_module: BuildModuleInterface):
903        """resolve '--clean-args' arg
904        :param target_arg: arg object which is used to get arg value.
905        :param build_module [maybe unused]: build module object which is used to get other services.
906        :phase: postbuild
907        """
908        if target_arg.arg_value:
909            Arg.clean_args_file()
910
911    # PlaceHolder
912    @staticmethod
913    def resolve_compiler(target_arg: Arg, build_module: BuildModuleInterface):
914        return
915
916    # PlaceHolder
917    @staticmethod
918    def resolve_jobs(target_arg: Arg, build_module: BuildModuleInterface):
919        return
920
921    # PlaceHolder
922    @staticmethod
923    def resolve_disable_part_of_post_build(target_arg: Arg, build_module: BuildModuleInterface):
924        return
925
926    # PlaceHolder
927    @staticmethod
928    def resolve_disable_package_image(target_arg: Arg, build_module: BuildModuleInterface):
929        return
930
931    # PlaceHolder
932    @staticmethod
933    def resolve_disable_post_build(target_arg: Arg, build_module: BuildModuleInterface):
934        return
935
936    # PlaceHolder
937    @staticmethod
938    def resolve_build_only_load(target_arg: Arg, build_module: BuildModuleInterface):
939        return
940
941    # PlaceHolder
942    @staticmethod
943    def resolve_build_only_gn(target_arg: Arg, build_module: BuildModuleInterface):
944        return
945
946    # PlaceHolder
947    @staticmethod
948    def resolve_fast_rebuild(target_arg: Arg, build_module: BuildModuleInterface):
949        return
950