LPT26x-HSF-4MB-Hilink_14.2..../build/script/enviroment.py
2025-05-13 22:00:58 +08:00

464 lines
17 KiB
Python
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
# encoding=utf-8
# =========================================================================
# @brief Config Target Definitions File
# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2022-2022. All rights reserved.
# =========================================================================
import multiprocessing
import os
import sys
import json
import copy
import importlib
from utils.build_utils import fn_get_subdirs, rm_pyc, target_config_path
all_target = {}
all_group = {}
all_target_templates = {}
chip_group_target = {}
chip_copy_target = {}
from target_config.common_config import CommonConfig
from utils.build_utils import exec_shell, root_path, get_platform_name, output_root
rm_pyc(target_config_path)
for name in fn_get_subdirs(target_config_path):
load_fmt = "target_config.%s.target_config" %name
try:
load_mod = importlib.import_module(load_fmt)
except:
print("[WARN] config/target_config/%s/target_config.py is not exist, you can delete it" % name)
continue
all_target_templates.update(load_mod.target_template)
load_fmt = "target_config.%s.config" %name
load_mod = importlib.import_module(load_fmt)
if "target_copy" in load_mod.__dict__:
chip_copy_target[name] = load_mod.target_copy
all_target.update(load_mod.target)
all_group.update(load_mod.target_group)
chip_group_target[name] = list(load_mod.target.keys()) + list(load_mod.target_group.keys())
# 判断key_list中的关键字是否都在string中
def is_list_in_str(key_list, string):
for item in key_list:
if item not in string:
return False
return True
class TargetEnvironment:
def __init__(self, target_name, extra_defines=None):
self.config = {}
self.is_implement_target = False
if extra_defines is None:
extra_defines = []
org_target = copy.deepcopy(all_target[target_name])
# sdk target不需要和template合并
if org_target.get('build_type', None) == 'SDK':
self.config = copy.deepcopy(org_target)
if extra_defines:
self.config['defines'] = extra_defines
return
self.merge_target_config(target_name, extra_defines)
com_config = CommonConfig(self.config['arch'])
self.merge_common_config(com_config)
self.merge_component_set(com_config)
self.merge_defines_set(com_config)
if self.is_enable_hso():
self.config["defines"].append("HSO_SUPPORT")
for key, value in self.config.items():
if isinstance(value, list):
self.deal_with_delete_symbol(key)
self.config["build_platform"] = get_platform_name()
self.config['target_command'] = target_name
if org_target.get('product_type'):
self.config['product_type'] = org_target.get('product_type')
def merge_target_config(self, target_name, extra_defines):
""" 将target_name对应的diff配置同diff配置中base_target_name对应的template配置合并
Args:
target_name: diff配置的key
extra_defines: 从命令-def=XXX,YYY,ZZZ=x中接收的额外宏
"""
org_target = copy.deepcopy(all_target[target_name])
base_target_name = org_target.pop('base_target_name')
if base_target_name in all_target:
temp_target = copy.deepcopy(all_target[base_target_name])
self.is_implement_target = True
org_target = self.merge_dict(temp_target, org_target)
base_target_name = temp_target['base_target_name']
self.config = copy.deepcopy(all_target_templates[base_target_name])
for key, value in org_target.items():
if not isinstance(value, list):
self.config[key] = value
continue
if key == 'defines':
self.merge_defines(value)
continue
self.extend(key, value)
self.merge_defines(extra_defines)
def merge_dict(self, dict1, dict2):
res = copy.deepcopy(dict2)
for key, value in dict1.items():
if not isinstance(value, list):
res[key] = value
continue
if key not in res:
res[key] = []
res[key].extend(value)
return res
def merge_common_config(self, com_config):
""" 将公共配置项合并到config中
Args:
com_config: 公共配置实例
"""
self.pretend('ccflags', com_config.get_ram_ccflags())
self.extend('rom_ccflags', com_config.get_rom_ccflags())
self.extend('linkflags', com_config.get_linkflags())
self.extend('std_libs', com_config.get_std_libs())
self.add('arch_family', com_config.get_arch_family())
def merge_defines(self, defines, extend=True):
"""
将参数defines合并到config的defines项中, 对于XXX=y这种宏会被替换
例:
config的defines项中有:XXX=y
参数defines中有:XXX=z
则合并后config的defines项中:XXX=y => XXX=z
"""
if extend:
self.extend('defines', defines)
special_define = {}
for define in defines:
if '=' in define:
key = define.split('=')[0]
val = define.split('=')[1]
special_define[key] = val
for idx, define in enumerate(self.config['defines']):
if '=' not in define:
continue
key = define.split('=')[0]
if key in special_define:
self.config['defines'][idx] = '%s=%s' % (key, special_define[key])
if extend:
self.config['defines'].extend(defines)
self.config['defines'] = list({}.fromkeys(self.config['defines']).keys())
def merge_component_set(self, com_config):
"""
处理ram/rom_component_set项中的删除标识, 并将其value合并到ram/rom_component中
"""
self.deal_with_delete_symbol('ram_component_set')
self.deal_with_delete_symbol('rom_component_set')
for ram_set in self.config['ram_component_set']:
self.extend('ram_component', com_config.get_component_set(ram_set))
for rom_set in self.config['rom_component_set']:
self.extend('rom_component', com_config.get_component_set(rom_set))
def merge_defines_set(self, com_config):
"""
处理ram/rom_component_set项中的删除标识, 并将其value合并到ram/rom_component中
"""
self.deal_with_delete_symbol('defines_set')
for defines_set in self.config['defines_set']:
self.extend('defines', com_config.get_definse(defines_set))
def deal_with_delete_symbol(self, key):
"""
处理self.config中key项中的删除标识
"""
if key not in self.config:
self.config[key] = []
return
lst = self.config[key]
normal_lst = []
reserve_lst = []
delete_lst = []
define_replace = []
for item in lst:
if item.startswith("[r]"):
reserve_lst.append(item[3:])
continue
if not item.startswith("-:"):
normal_lst.append(item)
continue
if key == 'defines' and "=" in item:
define_replace.append(item[2:])
continue
delete_lst.append(item[2:])
normal_lst = list({}.fromkeys(normal_lst).keys())
for del_item in delete_lst:
if del_item in normal_lst:
normal_lst.remove(del_item)
self.config[key] = normal_lst
self.merge_defines(define_replace, False)
self.config[key].extend(reserve_lst)
def add_component_defines(self):
self.config["target_component_defines"] = []
if 'ram_component' in self.config:
self.config["target_component_defines"].extend(
["SUPPORT_" + x.upper() for x in self.config['ram_component']]
)
if 'rom_component' in self.config:
self.config["target_component_defines"].extend(
["SUPPORT_" + x.upper() for x in self.config['rom_component']]
)
def is_enable_hso(self):
return self.get("hso_enable")
def get_tool_chain(self):
toolchain_dir = os.path.join(root_path, 'build', 'toolchains')
toolchain_file = "%s.cmake" % (self.get('tool_chain'))
return os.path.join(toolchain_dir, toolchain_file)
def get(self, key, cmake_type=True):
"""
返回self.config中item项的值,
若此值为list类型且cmake_type为True则用";"连接为字符串再返回cmake中列表中元素用;隔开)
"""
if key not in self.config:
return None
if isinstance(self.config[key], list) and cmake_type:
return ";".join(self.config[key])
return self.config[key]
def set(self, key, val):
if key not in self.config:
raise f'{key} not in ' + self.config['target_command']
if not isinstance(self.config[key], type(val)):
raise 'type of value is not same with ' + self.config['target_command'] + 'config'
self.config[key] = val
def get_output_path(self):
chip = self.get('chip')
core = self.get('core')
target_name = self.get('target_command')
return os.path.join(output_root, chip, core, target_name)
def get_target_template(self):
if self.is_implement_target:
temp = all_target[self.config['target_command']]['base_target_name']
res = all_target[temp]['base_target_name']
else:
res = all_target[self.config['target_command']]['base_target_name']
return res
def add(self, key, value):
if key in self.config:
raise
self.config[key] = value
def extend(self, key, value):
if not isinstance(value, list):
return
if key not in self.config:
self.config[key] = []
self.config[key].extend(value)
def pretend(self, key, value):
if not isinstance(value, list):
return
if key not in self.config:
self.config[key] = []
value.extend(self.config[key])
self.config[key] = copy.deepcopy(value)
def append(self, key, value):
if key not in self.config:
self.config[key] = []
if not isinstance(self.config[key], list):
return
if value in self.config[key]:
return
self.config[key].append(value)
def remove(self, key, value):
if key not in self.config:
return
if not isinstance(self.config[key], list):
return
if value not in self.config[key]:
return
self.config[key].remove(value)
def dump(self, dump_file=False):
info = json.dumps(self.config, indent=4, ensure_ascii=False)
if not dump_file:
print(info)
return info
with open(os.path.join(self.get_output_path(), "env_config.json"), "w") as f:
f.write(info)
return info
def is_config_refresh(self):
config_file = os.path.join(self.get_output_path(), "env_config.json")
if not os.path.exists(config_file):
return True
with open(config_file, "r") as f:
config = json.load(f)
return config != self.config
class BuildEnvironment:
""" command line param handler
receive param and parse it
"""
def __init__(self, param_list):
self.python_path = sys.executable
param_list = param_list[1:]
self.extr_defines = []
self.thread = multiprocessing.cpu_count()
self.need_clean = False
self.no_symbol_link = False
self.component = []
self.build_level = 'normal'
self.build_as_lib = False
self.build_as_lib_output_file = ''
self.target_names = []
self.group_names = []
self.generator = 'Unix Makefiles'
self.no_hso = False
self.open_kconfig = False
if get_platform_name() == "windows":
self.generator = "Ninja"
self.dump = False
self.build_time = ''
self.parse_cmd(param_list)
def parse_cmd(self, param_list):
""" parse param
"""
keys_of_target_name = []
for param in param_list:
if param.startswith('-j'):
self.thread = int(param[2:])
elif param.startswith('-def='):
self.extr_defines.extend(param[5:].split(','))
elif param.startswith('-build_time='):
self.build_time = param[12:].split(',')[0]
elif param.startswith('-component='):
self.component.extend(param[11:].split(','))
elif param.startswith('-out_libs='):
self.build_as_lib = True
self.build_as_lib_output_file = param[10:]
elif param == '-c':
self.need_clean = True
elif param == '-ninja':
self.generator = 'Ninja'
elif param == '-release' or param == '-debug' or param == '-normal':
self.build_level = param[1:]
elif param == '-dump':
self.dump = True
elif param == '-nhso':
self.no_hso = True
elif param == '-nsymlink':
self.no_symbol_link = True
elif param == 'menuconfig' or param == 'defconfig' or param == 'allyesconfig' or param == 'allnoconfig':
self.open_kconfig = True
self.kconfig_param = param
else:
keys_of_target_name.append(param)
self.match_target_names(keys_of_target_name)
def get_target_names_by_group_name(self, group_name):
targets = []
items = all_group[group_name]
return items
def is_group(self, item):
return item in all_group
def is_target(self, item):
return item in all_target
def is_copy_target(self, item):
for chip in chip_copy_target:
if item in chip_copy_target[chip]:
return True
return False
def get_chip_name(self, item):
for chip, targets in chip_group_target.items():
if item in targets:
return chip
return None
def add_target_names(self, target_name):
if target_name in all_group:
self.group_names.append(target_name)
if target_name in all_target:
self.target_names.append(target_name)
def match_target_names(self, keys_of_target_name):
""" 根据匹配关键字在all_target和all_group中匹配target_name以供选择
"""
if len(keys_of_target_name) == 1:
temp_name = keys_of_target_name[0]
if temp_name in all_group or temp_name in all_target:
self.add_target_names(temp_name)
return
normal_match_list = []
group_match_list = []
for key in all_target:
if is_list_in_str(keys_of_target_name, key):
normal_match_list.append(key)
for key in all_group:
if is_list_in_str(keys_of_target_name, key):
group_match_list.append(key)
all_match_list = normal_match_list + group_match_list
# all_match_list为空, 报错
if not all_match_list:
print("Target_name invalid and No matching target_name exists!")
for item in all_target.keys():
print(item)
sys.exit(1)
# 匹配项只有一个, 无需选择直接返回
if len(all_match_list) == 1:
self.add_target_names(all_match_list[0])
return
# 按序号打印匹配的target_name
print("Target_name invalid")
print("Here are the matching target_names")
cur_index = 0
for index in range(len(normal_match_list)):
print("%-3d : %s" % (cur_index, normal_match_list[index]))
cur_index += 1
print("\nHere are the matching aliases target_name")
for index in range(len(group_match_list)):
print("%-3d : %s" % (cur_index, group_match_list[index]))
cur_index += 1
print("\nDo you want to build them?")
print("Input index numbers for build or q for quit(num/q):", end='')
# 输入序号或q/Q
select_index = input()
if select_index.lower() == 'q':
sys.exit(0)
try:
select_indexes = [int(x) for x in select_index.split()]
for index in select_indexes:
self.add_target_names(all_match_list[index])
except:
print("ERROR INPUT!!")
sys.exit(1)