LPT26x-HSF-4MB-Hilink_14.2..../build/script/enviroment.py

464 lines
17 KiB
Python
Raw Permalink Normal View History

2025-05-13 22:00:58 +08:00
#!/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)