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