You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
473 lines
20 KiB
473 lines
20 KiB
#!/usr/bin/env python3
|
|
import json
|
|
import sys
|
|
from itertools import combinations
|
|
import math
|
|
import os
|
|
import re
|
|
import subprocess
|
|
import shutil
|
|
class ConfigManager:
|
|
def __init__(self, file_path, required_vars, second_person, amp_config_env):
|
|
self.file_path = file_path
|
|
self.required_vars = required_vars
|
|
self.combined_data = second_person["configs"][amp_config_env][1]
|
|
self.bootstrap = second_person["configs"][amp_config_env][0]["bootstrap"]
|
|
self.overlap_code = None
|
|
self.config_file_path = None
|
|
|
|
def prase_and_check_configs(self):
|
|
|
|
# 基于 `self.required_vars` 中指定的必需变量比较配置。
|
|
# 此方法检查不同路径中的配置是否对所需变量有一致的设置。
|
|
config_manager.compare_configs()
|
|
|
|
# 检查配置参数 "CONFIG_IMAGE_LOAD_ADDRESS" 和 "CONFIG_IMAGE_MAX_LENGTH" 是否存在重叠。
|
|
# 此方法确保这些参数在不同配置中没有重叠的值,这可能导致冲突。
|
|
overlap_code = config_manager.check_overlap()
|
|
|
|
# 检查引导地址是否在有效范围内。
|
|
# 此方法验证配置中指定的引导地址是否没有超出预期的内存范围。
|
|
config_manager.check_bootstrap_in_range()
|
|
|
|
# 检索配置文件的路径。
|
|
# 此方法提取并返回配置文件所在的路径。
|
|
config_file_path = config_manager.configs_path_get()
|
|
|
|
# 从配置文件中提取值。
|
|
# 此方法读取指定的配置文件并提取关键值,特别是那些用于引导适应的必需值。
|
|
config_values = config_manager.extract_config_values()
|
|
|
|
# 返回一个元组,包含组合配置数据、重叠状态、配置文件路径和提取的配置值。
|
|
# 这些返回数据封装了该方法执行的各种检查和解析操作的结果。
|
|
return overlap_code, config_file_path, config_values
|
|
|
|
def read_config_values(self, file_path, variables, para):
|
|
values = {}
|
|
with open(file_path, 'r') as file:
|
|
for line in file:
|
|
for var in variables:
|
|
if line.startswith(var):
|
|
if para == 16:
|
|
values[var] = int(line.strip().split('=')[1], 16)
|
|
else:
|
|
values[var] = line.strip().split('=')[1]
|
|
break
|
|
return values
|
|
|
|
def compare_configs(self):
|
|
"""
|
|
比较指定路径下的配置文件。
|
|
|
|
对每一对配置文件,比较它们是否在所有必需的变量(required_vars)上具有相同的值。
|
|
如果所有对比的文件在所有必需的变量上值都相同,则认为它们匹配。
|
|
|
|
参数:
|
|
self.required_vars (list): 需要比较的变量名列表。
|
|
|
|
返回:
|
|
tuple: 包含比较结果的字典和所有文件是否匹配的布尔值。
|
|
"""
|
|
# 存储每个配置文件中的变量值
|
|
config_values = {}
|
|
|
|
# 读取每个配置文件中的变量值
|
|
for name, data in self.combined_data.items():
|
|
path = data[0]
|
|
file = data[3]
|
|
full_path = os.path.join(path, 'configs/'+file)
|
|
config_values[full_path] = self.read_config_values(full_path, self.required_vars, None)
|
|
|
|
# 比较变量值
|
|
comparison_result = {}
|
|
all_match = True
|
|
|
|
for file1, file2 in combinations(config_values.keys(), 2):
|
|
mismatches = {}
|
|
for var in self.required_vars:
|
|
if config_values[file1].get(var) != config_values[file2].get(var):
|
|
mismatches[var] = (config_values[file1].get(var), config_values[file2].get(var))
|
|
all_match = False
|
|
|
|
if mismatches:
|
|
comparison_result[(file1, file2)] = mismatches
|
|
else:
|
|
comparison_result[(file1, file2)] = "Match"
|
|
|
|
# 配置文件检查
|
|
|
|
if all_match:
|
|
print('比较成功')
|
|
pass
|
|
else:
|
|
print(self.format_comparison_result(all_match,comparison_result))
|
|
sys.exit("error: 参数对比失败 (Error: Parameter comparison failed)")
|
|
|
|
return comparison_result ,all_match
|
|
|
|
def format_comparison_result(self,all_match, comparison_result):
|
|
if all_match:
|
|
return "所有配置文件完全匹配。"
|
|
|
|
formatted_output = ["配置文件比较结果:\n"]
|
|
for file, result in comparison_result.items():
|
|
if result == "Base file for comparison":
|
|
formatted_output.append(f"基准文件: {file}")
|
|
else:
|
|
formatted_output.append(f"文件: {file}")
|
|
if result == "Match":
|
|
formatted_output.append(" 匹配基准文件")
|
|
else:
|
|
for var, (val1, val2) in result.items():
|
|
formatted_output.append(f" 变量不匹配: {var} (基准值: {val1}, 当前文件值: {val2})")
|
|
|
|
return '\n'.join(formatted_output)
|
|
|
|
def check_overlap(self):
|
|
"""
|
|
检查配置文件中指定的内存范围是否存在重叠。
|
|
|
|
此方法遍历所有提供的配置文件,并检查它们的 'CONFIG_IMAGE_LOAD_ADDRESS' 和
|
|
'CONFIG_IMAGE_MAX_LENGTH' 变量以确定内存地址范围。它检查这些范围是否
|
|
在任何配置文件对中重叠。
|
|
|
|
参数:
|
|
config_files (dict): 包含配置文件路径和文件名的字典。
|
|
|
|
返回:
|
|
tuple: 包含重叠检查结果的布尔值和解析出的配置值字典。
|
|
"""
|
|
config_values = {}
|
|
|
|
# 读取每个配置文件中的变量值
|
|
for name, data in self.combined_data.items():
|
|
path = data[0]
|
|
file = data[3]
|
|
full_path = os.path.join(path, 'configs/'+file)
|
|
# 处理关心的["CONFIG_IMAGE_LOAD_ADDRESS", "CONFIG_IMAGE_MAX_LENGTH"]
|
|
config_values[full_path] = self.read_config_values(full_path, ["CONFIG_IMAGE_LOAD_ADDRESS", "CONFIG_IMAGE_MAX_LENGTH"],16)
|
|
|
|
overlap_check = True
|
|
file_paths = list(config_values.keys())
|
|
for i in range(len(file_paths) - 1):
|
|
for j in range(i + 1, len(file_paths)):
|
|
load_addr1, max_length1 = config_values[file_paths[i]].values()
|
|
load_addr2, max_length2 = config_values[file_paths[j]].values()
|
|
if not (load_addr1 + max_length1 <= load_addr2 or load_addr2 + max_length2 <= load_addr1):
|
|
overlap_check = False
|
|
|
|
print(config_manager.format_overlap_result(config_values, overlap_check))
|
|
|
|
if not overlap_check :
|
|
sys.exit("error: 配置范围存在重叠 (Error: Configuration range overlaps)")
|
|
self.overlap_code = config_values
|
|
return config_values
|
|
|
|
|
|
def format_overlap_result(self,config_values, overlap_check):
|
|
formatted_output = ["配置文件范围比较结果:\n"]
|
|
for file, values in config_values.items():
|
|
load_address = values["CONFIG_IMAGE_LOAD_ADDRESS"]
|
|
max_length = values["CONFIG_IMAGE_MAX_LENGTH"]
|
|
formatted_output.append(f"文件: {file}")
|
|
formatted_output.append(f" LOAD_ADDRESS: {hex(load_address)}, MAX_LENGTH: {hex(max_length)}")
|
|
|
|
if overlap_check:
|
|
formatted_output.append("\n所有配置文件的范围均不重叠。")
|
|
else:
|
|
formatted_output.append("\n存在范围重叠。请调整以下参数以避免重叠:")
|
|
formatted_output.append(" 1. CONFIG_IMAGE_LOAD_ADDRESS")
|
|
formatted_output.append(" 2. CONFIG_IMAGE_MAX_LENGTH")
|
|
formatted_output.append("确保两个配置文件中的LOAD_ADDRESS + MAX_LENGTH范围不重叠。")
|
|
|
|
return '\n'.join(formatted_output)
|
|
|
|
def check_bootstrap_in_range(self):
|
|
bootstrap_address = self.bootstrap
|
|
config_values = self.overlap_code
|
|
# 将bootstrap地址从十六进制字符串转换为整数
|
|
bootstrap_int = int(bootstrap_address, 16)
|
|
bootstrap_check = True
|
|
# 检查bootstrap地址是否在任何配置文件指定的范围内
|
|
for values in config_values.values():
|
|
load_address = values["CONFIG_IMAGE_LOAD_ADDRESS"]
|
|
max_length = values["CONFIG_IMAGE_MAX_LENGTH"]
|
|
if load_address <= bootstrap_int < (load_address + max_length):
|
|
bootstrap_check = False
|
|
|
|
print("Bootstrap地址是否在范围外:", bootstrap_check)
|
|
|
|
print(config_manager.format_bootstrap_check(bootstrap_address,config_values,bootstrap_check))
|
|
|
|
if bootstrap_check!= True:
|
|
sys.exit("error: boot 加载地址非法")
|
|
|
|
return True
|
|
|
|
|
|
def format_bootstrap_check(self,bootstrap_address, config_values, bootstrap_check):
|
|
formatted_output = ["Bootstrap 检查结果:"]
|
|
bootstrap_int = int(bootstrap_address, 16)
|
|
|
|
formatted_output.append(f"地址:{bootstrap_address} ({bootstrap_int})")
|
|
|
|
for file, values in config_values.items():
|
|
load_address = values["CONFIG_IMAGE_LOAD_ADDRESS"]
|
|
max_length = values["CONFIG_IMAGE_MAX_LENGTH"]
|
|
end_address = load_address + max_length
|
|
formatted_output.append(f"文件: {file}")
|
|
formatted_output.append(f" 范围: {hex(load_address)} - {hex(end_address)}")
|
|
|
|
if load_address <= bootstrap_int < end_address:
|
|
formatted_output.append(" 结果: Bootstrap 地址位于此范围内")
|
|
else:
|
|
# formatted_output.append(" 结果: Bootstrap 地址不在此范围内")
|
|
pass
|
|
|
|
if bootstrap_check:
|
|
pass
|
|
# formatted_output.append("\n结论: Bootstrap 地址不与任何配置文件的范围重叠。")
|
|
else:
|
|
formatted_output.append("\n结论: Bootstrap 地址与至少一个配置文件的范围重叠。")
|
|
|
|
return '\n'.join(formatted_output)
|
|
|
|
|
|
def configs_path_get(self):
|
|
# 读取每个配置文件中的变量值
|
|
for name, data in self.combined_data.items():
|
|
path = data[0]
|
|
file = data[3]
|
|
full_path = os.path.join(path, 'configs/'+file)
|
|
self.config_file_path = full_path
|
|
return full_path
|
|
|
|
def extract_config_values(self):
|
|
file_path = self.config_file_path
|
|
variables = self.required_vars
|
|
values = {}
|
|
with open(file_path, 'r') as file:
|
|
for line in file:
|
|
for var in variables:
|
|
if line.startswith(var):
|
|
key, value = line.strip().split('=', 1)
|
|
values[key] = value
|
|
break
|
|
values["CONFIG_IMAGE_LOAD_ADDRESS"] = self.bootstrap
|
|
# 返回值为最终用于boot 自适应配置的值
|
|
return values
|
|
|
|
|
|
#*****************************************************************************************************
|
|
def execute_make_commands(combined_configs, configs_key, additional_config):
|
|
if configs_key in combined_configs:
|
|
combined_data = combined_configs[configs_key][1]
|
|
for name, data in combined_data.items():
|
|
path = data[0]
|
|
core = data[1]
|
|
reserve = 0
|
|
file = data[3]
|
|
|
|
config_name = file.replace('.config', '')
|
|
|
|
commands = [
|
|
"make clean",
|
|
f"make load_kconfig LOAD_CONFIG_NAME={config_name}"
|
|
]
|
|
|
|
# 执行命令并检查结果
|
|
for command in commands:
|
|
result = subprocess.call(command, shell=True, cwd=path)
|
|
if result != 0:
|
|
print(f"Error: Command '{command}' failed with exit code {result}", file=sys.stderr)
|
|
sys.exit(result)
|
|
|
|
# 特定处理逻辑
|
|
if additional_config.get('CONFIG_ARCH_EXECUTION_STATE') == '"aarch32"':
|
|
print("CONFIG_USE_AARCH64_L1_TO_AARCH32=y is remove")
|
|
remove_config_line(path, "CONFIG_USE_AARCH64_L1_TO_AARCH32=y","sdkconfig")
|
|
result = subprocess.call("make gen_kconfig", shell=True, cwd=path)
|
|
if result != 0:
|
|
print(f"Error: Command 'make gen_kconfig' failed with exit code {result}", file=sys.stderr)
|
|
sys.exit(result)
|
|
|
|
# 继续执行 make all
|
|
cmd = [f"make all -j BUILD_IMAGE_CORE_NUM={core} BUILD_IMAGE_DELAY_NUM={reserve} BUILD_AMP_CORE=y"]
|
|
result = subprocess.call(cmd, shell=True, cwd=path)
|
|
if result != 0:
|
|
print(f"Error: Command 'make all -j' failed with exit code {result}", file=sys.stderr)
|
|
sys.exit(result)
|
|
|
|
else:
|
|
print(f"未找到配置项 {configs_key}")
|
|
|
|
def remove_config_line(path, line_to_remove,file_name):
|
|
config_file_path = os.path.join(path, file_name)
|
|
print(config_file_path)
|
|
with open(config_file_path, 'r') as file:
|
|
lines = file.readlines()
|
|
with open(config_file_path, 'w') as file:
|
|
for line in lines:
|
|
if line.strip() != line_to_remove:
|
|
file.write(line)
|
|
|
|
|
|
def find_elf_files(config_data, configs_key):
|
|
elf_files = []
|
|
combined_data = combined_configs[configs_key][1]
|
|
for name, data in combined_data.items():
|
|
path = data[0]
|
|
file = data[3]
|
|
|
|
# 检查每个路径下的所有文件
|
|
full_path = os.path.abspath(path)
|
|
if os.path.isdir(full_path):
|
|
for file in os.listdir(full_path):
|
|
if file.endswith('.elf'):
|
|
elf_file_path = os.path.join(full_path, file)
|
|
elf_files.append(elf_file_path)
|
|
else:
|
|
sys.exit(f"错误:路径 {full_path} 不存在。")
|
|
|
|
if not elf_files:
|
|
sys.exit(f"错误:在{name}:{path} 中未找到任何 .elf 文件。")
|
|
|
|
return elf_files
|
|
|
|
def pack_elf_files(elf_files, output_file='packed.bin'):
|
|
with open(output_file, 'wb') as packed:
|
|
for elf_file in elf_files:
|
|
with open(elf_file, 'rb') as file:
|
|
packed.write(file.read())
|
|
print(f"{elf_file} 已添加到 {output_file}。")
|
|
|
|
|
|
|
|
def replace_config_values(config_path, config_data):
|
|
# 读取配置文件
|
|
try:
|
|
with open(config_path, 'r') as file:
|
|
lines = file.readlines()
|
|
except IOError:
|
|
print(f"无法打开文件 {config_path}")
|
|
return
|
|
existing_keys = set()
|
|
# 替换配置值
|
|
updated_lines = []
|
|
|
|
# 替换已存在的配置值
|
|
for line in lines:
|
|
for key in config_data.keys():
|
|
if line.startswith(key + "="):
|
|
line = f"{key}={config_data[key]}\n"
|
|
existing_keys.add(key)
|
|
break
|
|
updated_lines.append(line)
|
|
|
|
for key, value in config_data.items():
|
|
if key not in existing_keys:
|
|
updated_lines.append(f"{key}={value}\n")
|
|
|
|
# 写回配置文件
|
|
try:
|
|
with open(config_path, 'w') as file:
|
|
file.writelines(updated_lines)
|
|
print(f"配置文件 {config_path} 已更新。")
|
|
except IOError:
|
|
print(f"无法写入文件 {config_path}")
|
|
|
|
def select_and_replace_config(data, user_path,outpath):
|
|
# 确定要选择的配置文件
|
|
config_file_name = "default_aarch32.config" if data.get('CONFIG_ARCH_EXECUTION_STATE') == '"aarch32"' else "default_aarch64.config"
|
|
|
|
# 检查配置文件是否存在于用户指定的路径
|
|
config_file_path = os.path.join(user_path, config_file_name)
|
|
if not os.path.isfile(config_file_path):
|
|
print(f"错误:在路径 {user_path} 下未找到文件 {config_file_name}。")
|
|
return
|
|
|
|
# 复制配置文件为 current_config.config
|
|
current_config_path = os.path.join(outpath, "sdkconfig")
|
|
shutil.copy(config_file_path, current_config_path)
|
|
print(f"已将 {config_file_name} 复制为 current_config.config。")
|
|
|
|
|
|
replace_config_values(current_config_path,data)
|
|
|
|
print("已更新 current_config.config 文件。")
|
|
|
|
|
|
def make_clean_commands(config_data, configs_key):
|
|
if configs_key in config_data:
|
|
configs = config_data[configs_key]['configs']
|
|
|
|
for path, config_files in configs.items():
|
|
#执行 make clean
|
|
result = subprocess.call("make clean", shell=True, cwd=path)
|
|
if result != 0:
|
|
print(f"Error: Command 'make clean' failed with exit code {result}", file=sys.stderr)
|
|
sys.exit(result)
|
|
else:
|
|
print(f"Success clean {path}.")
|
|
else:
|
|
print(f"未找到配置项 {configs_key}")
|
|
|
|
#****************
|
|
|
|
def check_amp_config_in_json(second_person, amp_config_env):
|
|
if amp_config_env in second_person["configs"]:
|
|
return second_person["configs"][amp_config_env]
|
|
return None
|
|
|
|
if __name__ == "__main__":
|
|
file_path = './amp_config.json'
|
|
|
|
# 检查amp_config.json是否存在
|
|
if not os.path.exists(file_path):
|
|
sys.exit("amp_config.json 文件不存在。")
|
|
|
|
# 打开文件并加载 JSON 数据
|
|
with open(file_path, 'r') as file:
|
|
data = json.load(file)
|
|
# 获取第二个对象,第一个对象为配置举例
|
|
second_person = data[1]
|
|
|
|
# 检查环境变量AMP_CONFIG
|
|
amp_config_env = os.environ.get('AMP_CONFIG')
|
|
|
|
if amp_config_env:
|
|
print(f"找到环境变量AMP_CONFIG: {amp_config_env} (Found environment variable AMP_CONFIG: {amp_config_env})")
|
|
config_line = check_amp_config_in_json(second_person, amp_config_env)
|
|
if config_line:
|
|
# ... 继续其他逻辑 ...
|
|
print("********************************************************* 配置如下 ***********************************************************************")
|
|
|
|
print(f"{amp_config_env}:",config_line)
|
|
print("************************************************************************************************************************************************")
|
|
pass
|
|
else:
|
|
sys.exit("请检查amp_config.json中的配置项。请使用 make amp_make AMP_CONFIG=config<num> (Please check the configuration items in amp_config.json. Use make amp_make AMP_CONFIG=config<num>)")
|
|
else:
|
|
print("打印amp_config.json中的config<num>配置:(Printing config<num> configurations from amp_config.json:)")
|
|
for config in second_person["configs"]:
|
|
print(f"{config}:",second_person["configs"][config])
|
|
sys.exit("error: 环境变量AMP_CONFIG不存在。请使用 make amp_make AMP_CONFIG=config<num> (Error: The AMP_CONFIG environment variable does not exist. Use make amp_make AMP_CONFIG=config<num>)")
|
|
|
|
|
|
# 配置文件解析
|
|
# 需要对比提取的规则
|
|
required_vars = ["CONFIG_ARCH_NAME", "CONFIG_BOARD_NAME", "CONFIG_ARCH_EXECUTION_STATE", "CONFIG_SOC_NAME", "CONFIG_TARGET_TYPE_NAME","CONFIG_SOC_CORE_NUM"]
|
|
config_manager = ConfigManager(file_path, required_vars, second_person, amp_config_env)
|
|
overlap_code,config_file_path,config_values = config_manager.prase_and_check_configs()
|
|
combined_configs = second_person["configs"]
|
|
## 开始根据 中对应的配置进行逐个加载与编译进行
|
|
execute_make_commands(combined_configs,amp_config_env,config_values)
|
|
|
|
## 开始对已经生成elf文件进行打包
|
|
elf_files = find_elf_files(combined_configs, amp_config_env)
|
|
print(elf_files)
|
|
pack_elf_files(elf_files)
|
|
|
|
sdk_path = os.environ.get('SDK_DIR')
|
|
select_and_replace_config(config_values,sdk_path + f'/tools/build/new_boot_code/configs',sdk_path + f'/tools/build/new_boot_code')
|
|
|