472 lines
20 KiB
Python
472 lines
20 KiB
Python
|
#!/usr/bin/env python3
|
||
|
# coding=utf-8
|
||
|
# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2022-2022. All rights reserved.
|
||
|
|
||
|
import os
|
||
|
import shutil
|
||
|
import sys
|
||
|
import time
|
||
|
import re
|
||
|
|
||
|
from utils.build_utils import exec_shell, root_path, output_root, sdk_output_path, pkg_tools_path
|
||
|
from utils.build_utils import compare_bin
|
||
|
from enviroment import TargetEnvironment, BuildEnvironment
|
||
|
from pack_tool import packTool
|
||
|
from sdk_generator.sdk_generator import SdkGenerator
|
||
|
from rom_ram_callback.gen_rom_ram_callback import gen_rom_ram_callback
|
||
|
from rom_ram_callback.strip_undef_symbols import strip_undefined_symbols
|
||
|
from usr_config import mconfig
|
||
|
from custom_cmd import run_custom_cmd
|
||
|
from target_config.common_config import CommonConfig
|
||
|
def copy_file(src, dst):
|
||
|
try:
|
||
|
shutil.copy2(src, dst)
|
||
|
except FileNotFoundError:
|
||
|
print(f"error 01") #文件不存在
|
||
|
except PermissionError:
|
||
|
print(f"error 02") #没有权限复制
|
||
|
except Exception as e:
|
||
|
print(f"error 03 [{e}]") #复制文件时发生错误
|
||
|
|
||
|
class CMakeBuilder(BuildEnvironment):
|
||
|
""" cmake builder, 接收并解析参数,启动构建
|
||
|
"""
|
||
|
def __init__(self, param_list):
|
||
|
super(CMakeBuilder, self).__init__(param_list)
|
||
|
self.cmake_cmd = []
|
||
|
self.sdk = None
|
||
|
self.pack_tool = None
|
||
|
|
||
|
def get_component(self, env):
|
||
|
com_config = CommonConfig(env.get('arch'))
|
||
|
components = []
|
||
|
if env.get('just_build_components', False):
|
||
|
just_build_components = env.get('just_build_components', False)
|
||
|
else:
|
||
|
just_build_components = self.component
|
||
|
for component in just_build_components:
|
||
|
if component in env.get('ram_component', False):
|
||
|
components.append(component)
|
||
|
continue
|
||
|
if component not in env.get('ram_component_set', False):
|
||
|
continue
|
||
|
for comm in com_config.get_component_set(component):
|
||
|
if comm in env.get('ram_component', False):
|
||
|
components.append(comm)
|
||
|
return components
|
||
|
|
||
|
def get_build_cmd(self, env):
|
||
|
ext_cmd = []
|
||
|
components = self.get_component(env)
|
||
|
ext_cmd.extend(components)
|
||
|
if self.generator == 'Ninja':
|
||
|
return ['ninja'] + ext_cmd + ['-j%d' % self.thread]
|
||
|
else:
|
||
|
return ['make'] + ext_cmd + ['-j%d' % self.thread]
|
||
|
|
||
|
def build(self):
|
||
|
"""
|
||
|
"""
|
||
|
built_targets = []
|
||
|
for group in self.group_names:
|
||
|
need_pack = False
|
||
|
if group.startswith('pack'):
|
||
|
need_pack = True
|
||
|
chip = self.get_chip_name(group)
|
||
|
if os.path.exists(os.path.join(output_root, 'package', chip, group)):
|
||
|
shutil.rmtree(os.path.join(output_root, 'package', chip, group))
|
||
|
|
||
|
for target in self.get_target_names_by_group_name(group):
|
||
|
self.pack_tool = packTool(group, target)
|
||
|
if self.is_group(target):
|
||
|
self.group_names.append(target)
|
||
|
continue
|
||
|
|
||
|
if self.is_copy_target(target):
|
||
|
self.pack_tool.pack()
|
||
|
continue
|
||
|
|
||
|
if target == 'fwpkg' and need_pack:
|
||
|
self.pack_fwpkg(chip, group)
|
||
|
continue
|
||
|
|
||
|
if not self.is_target(target):
|
||
|
print("Invalid target %s" % target)
|
||
|
raise
|
||
|
if not target in built_targets:
|
||
|
self.build_target(target)
|
||
|
built_targets.append(target)
|
||
|
else:
|
||
|
print("%s has built, skip" % target)
|
||
|
target_env = TargetEnvironment(target, self.extr_defines)
|
||
|
if target_env.get('build_type') == 'SDK':
|
||
|
continue
|
||
|
if need_pack:
|
||
|
self.pack_tool.pack()
|
||
|
|
||
|
if len(self.target_names) == 1 and self.open_kconfig == True:
|
||
|
self.menuconfig_to_build(self.target_names[0])
|
||
|
return
|
||
|
|
||
|
for target in self.target_names:
|
||
|
self.build_target(target)
|
||
|
|
||
|
def menuconfig_to_build(self, target):
|
||
|
env = TargetEnvironment(target)
|
||
|
mconfig(self.kconfig_param, env.get("chip"), env.get("core"), target, None)
|
||
|
|
||
|
def build_target(self, target):
|
||
|
env = TargetEnvironment(target, self.extr_defines)
|
||
|
if env.get('build_type') == 'SDK':
|
||
|
self.build_sdk(env)
|
||
|
return
|
||
|
if not run_custom_cmd(env, target, 'build_pre'):
|
||
|
self.print_build_result(target, 1)
|
||
|
sys.exit(1)
|
||
|
|
||
|
self.compile_target(target, env)
|
||
|
|
||
|
if env.get('just_build_components'):
|
||
|
return
|
||
|
|
||
|
if env.get("fs_image"):
|
||
|
fs_image_path = os.path.join(root_path, 'build', 'config', 'target_config', env.get('chip'), 'mk_fs_image')
|
||
|
fs_script_path = os.path.join(fs_image_path, 'mkyaffs2tool.py')
|
||
|
output_path = env.get_output_path()
|
||
|
print(output_path)
|
||
|
errcode = exec_shell([self.python_path, fs_script_path, output_path], None, True)
|
||
|
if errcode != 0:
|
||
|
print("creat fs image error!")
|
||
|
self.print_build_result(target, errcode)
|
||
|
sys.exit(1)
|
||
|
print("fs image success!")
|
||
|
|
||
|
if env.get('upg_pkg'):
|
||
|
self.pack_fota(env.get('chip'), target, env.get('upg_pkg'))
|
||
|
|
||
|
if not run_custom_cmd(env, target, 'build_post'):
|
||
|
self.print_build_result(target, 1)
|
||
|
sys.exit(1)
|
||
|
|
||
|
if env.get('packet') :
|
||
|
self.pack_fwpkg(env.get('chip'), target)
|
||
|
|
||
|
def build_sdk(self, env):
|
||
|
self.sdk = SdkGenerator(env, sdk_output_path)
|
||
|
if os.path.exists(sdk_output_path):
|
||
|
print("Cleaning SDK output path")
|
||
|
shutil.rmtree(sdk_output_path)
|
||
|
sdk_pkg_target_name = env.get('pkg_target_name', cmake_type=False)
|
||
|
|
||
|
for sdk_target in sdk_pkg_target_name:
|
||
|
sdk_target_env = TargetEnvironment(sdk_target, self.extr_defines)
|
||
|
output_path = sdk_target_env.get_output_path()
|
||
|
self.compile_target(sdk_target, sdk_target_env)
|
||
|
self.sdk.copy_depends('%s/cmake_trace.txt' % output_path)
|
||
|
if self.sdk.env.get('reload_kconfig'):
|
||
|
cwd = os.getcwd()
|
||
|
os.chdir(sdk_output_path)
|
||
|
mconfig('reloadconfig', sdk_target_env.get("chip"), sdk_target_env.get("core"), sdk_target, None, root=sdk_output_path)
|
||
|
os.chdir(cwd)
|
||
|
|
||
|
if env.get('config') and 'lib_gen' in env.get('config'):
|
||
|
lib_gen_tasks = env.get('config')['lib_gen']
|
||
|
print(lib_gen_tasks)
|
||
|
for libs in lib_gen_tasks:
|
||
|
task = lib_gen_tasks[libs]
|
||
|
target_name = task['base_target_name']
|
||
|
defines = task.get("defines", [])
|
||
|
self.component = task['components']
|
||
|
target_env = TargetEnvironment(target_name, extra_defines=defines)
|
||
|
target_env.add("LIB_GEN_NAME", libs)
|
||
|
target_env.extend("SDK_LIBGEN_COMPONENTS", self.component)
|
||
|
self.compile_target(target_name, target_env)
|
||
|
self.sdk.sdk_build(self.build_time, self.no_hso, self.build_level)
|
||
|
self.sdk = None
|
||
|
self.component = []
|
||
|
|
||
|
def compile_target(self, target_name, env):
|
||
|
start_time = time.time()
|
||
|
self.deal_symbol_link(env)
|
||
|
env.add('build_level', self.build_level)
|
||
|
if self.build_level == "debug":
|
||
|
env.extend("ccflags", ['-funwind-tables', '-fasynchronous-unwind-tables'])
|
||
|
env.extend("defines", "NO_TIMEOUT")
|
||
|
if self.build_as_lib:
|
||
|
env.add("GEN_ONLY_LIB_PATH")
|
||
|
self.cmake_cmd = ['cmake', '-G', self.generator, '-Wno-dev', '--no-warn-unused-cli', '-DCMAKE_C_COMPILER_WORKS=TRUE', '-DCMAKE_CXX_COMPILER_WORKS=TRUE']
|
||
|
if env.get('fp_enable'):
|
||
|
env.append('defines', 'SUPPORT_CALLSTACK')
|
||
|
env.append('ccflags', '-fno-omit-frame-pointer')
|
||
|
self.add_build_param(env)
|
||
|
|
||
|
output_path = env.get_output_path()
|
||
|
self.pre_sdk(output_path, env)
|
||
|
if env.get('libstd_option'):
|
||
|
self.add_cmake_def(env, 'std_libs')
|
||
|
self.cmake_cmd.append(root_path)
|
||
|
|
||
|
if env.get('product_type'):
|
||
|
self.cmake_cmd.append('-DPRODUCT_TYPE={0}'.format(env.get('product_type')))
|
||
|
else:
|
||
|
self.cmake_cmd.append('-DPRODUCT_TYPE=default')
|
||
|
|
||
|
if self.dump:
|
||
|
env.dump()
|
||
|
|
||
|
if self.rom_callback(env, target_name, output_path):
|
||
|
if not os.path.exists(output_path):
|
||
|
os.makedirs(output_path)
|
||
|
env.set('build_rom_callback', False)
|
||
|
env.append('defines', '_PRE_FEATURE_VENEER_ROM')
|
||
|
env.append('ram_component', 'rom_callback')
|
||
|
self.redef_cmake_def(env, 'build_rom_callback')
|
||
|
self.redef_cmake_def(env, 'defines')
|
||
|
self.redef_cmake_def(env, 'ram_component')
|
||
|
self.add_cmake_param("-DROM_CHECK=False")
|
||
|
self.start(env, target_name, output_path, clean=self.need_clean, nhso=self.no_hso)
|
||
|
self.rom_check(env, target_name, output_path)
|
||
|
|
||
|
end_time = time.time()
|
||
|
print("%s takes %f s" % (target_name, end_time - start_time))
|
||
|
|
||
|
def deal_symbol_link(self, env):
|
||
|
if "rom_sym_path" not in env.config:
|
||
|
return
|
||
|
if self.no_symbol_link and not self.sdk:
|
||
|
env.config["rom_sym_path"] = ""
|
||
|
else:
|
||
|
env.config["rom_sym_path"] = env.config["rom_sym_path"].replace("<root>", root_path)
|
||
|
if os.path.exists(env.config["rom_sym_path"]):
|
||
|
env.config["linkflags"].append("-Wl,--just-symbols=" + env.config["rom_sym_path"])
|
||
|
env.config["defines"].append("ROM_SYMBOL_LINK")
|
||
|
else:
|
||
|
print("ERROR: rom_sym_path %s is not exists" % env.config["rom_sym_path"])
|
||
|
if "bootrom_sym_path" not in env.config:
|
||
|
return
|
||
|
if env.config["bootrom_sym_path"] != "":
|
||
|
env.config["bootrom_sym_path"] = env.config["bootrom_sym_path"].replace("<root>", root_path)
|
||
|
if os.path.exists(env.config["bootrom_sym_path"]):
|
||
|
env.config["linkflags"].append("-Wl,--just-symbols=" + env.config["bootrom_sym_path"])
|
||
|
env.config["defines"].append("BOOTROM_SYMBOL_LINK")
|
||
|
else:
|
||
|
print("ERROR: bootrom_sym_path %s is not exists" % env.config["bootrom_sym_path"])
|
||
|
|
||
|
def add_build_param(self, env):
|
||
|
for item in env.config:
|
||
|
self.add_cmake_def(env, item)
|
||
|
self.add_cmake_param('-DCMAKE_TOOLCHAIN_FILE=%s' % env.get_tool_chain())
|
||
|
self.add_cmake_param('-DPY_PATH=%s' % self.python_path)
|
||
|
if self.build_time != '':
|
||
|
self.add_cmake_param('-DBUILD_TIME=%s' % self.build_time)
|
||
|
|
||
|
def pre_sdk(self, output_path, env):
|
||
|
if not self.sdk:
|
||
|
return
|
||
|
|
||
|
self.sdk.register_org_target_path(output_path)
|
||
|
self.add_cmake_param('-DSDK_OUTPUT_PATH=%s' % sdk_output_path)
|
||
|
self.add_cmake_def(self.sdk.env, 'sdk_type')
|
||
|
# closed_components takes precedence over open_components
|
||
|
closed_components = self.sdk.env.get('closed_components', cmake_type=False)
|
||
|
open_components = self.sdk.env.get('open_components', cmake_type=False)
|
||
|
if None not in (closed_components, open_components):
|
||
|
raise Exception(f'ERROR! closed_components and open_components cannot be set together!')
|
||
|
self.add_cmake_def(self.sdk.env, 'closed_components')
|
||
|
if not closed_components:
|
||
|
self.add_cmake_def(self.sdk.env, 'open_components')
|
||
|
|
||
|
self.add_cmake_def(env, 'main_component')
|
||
|
|
||
|
# export trace of cmake invocation
|
||
|
cmake_trace_file = os.path.join(output_path, 'cmake_trace.txt')
|
||
|
self.cmake_cmd.append('--trace-format=json-v1')
|
||
|
self.cmake_cmd.append('--trace-redirect=%s' % cmake_trace_file)
|
||
|
|
||
|
def print_build_result(self, target_name, fail):
|
||
|
print("######### Build target:%s %s" % (target_name, "failed" if fail else "success"))
|
||
|
if self.sdk:
|
||
|
print("######### Build sdk %s!!" % ("failed" if fail else "success"))
|
||
|
|
||
|
def rom_callback(self, env, target_name, output_path):
|
||
|
if not env.get('build_rom_callback'):
|
||
|
return False
|
||
|
if env.get('fixed_rom'):
|
||
|
return True
|
||
|
self.start(env, target_name, output_path, nhso=True, clean=self.need_clean)
|
||
|
print("GENERATING AUTO ROM BIN FILE!!!")
|
||
|
chip = env.get("chip")
|
||
|
core = env.get("core")
|
||
|
board = env.get('board')
|
||
|
application = env.get('application')
|
||
|
arch = env.get('arch')
|
||
|
rom_config = os.path.join(root_path, 'drivers', 'chips', chip, 'rom_config', core)
|
||
|
rom_output = os.path.join(rom_config, 'output')
|
||
|
if not os.path.exists(rom_output):
|
||
|
os.makedirs(rom_output)
|
||
|
|
||
|
shutil.copy(os.path.join(output_path, "rom_bin_raw.undef"), rom_output)
|
||
|
shutil.copy(os.path.join(output_path, "rom_symbol.list"), rom_output)
|
||
|
shutil.copy(os.path.join(output_path, "rom_bin.rel"), rom_output)
|
||
|
shutil.copy(os.path.join(output_path, "image_symbol.list"), rom_output)
|
||
|
shutil.copy(os.path.join(rom_config, "undef_rom_filter.list"), rom_output)
|
||
|
shutil.copy(os.path.join(rom_config, "region.list"), rom_output)
|
||
|
|
||
|
strip_undefined_symbols(rom_output)
|
||
|
if arch[:5] == "riscv":
|
||
|
target = "riscv32"
|
||
|
elif arch[:3] == "arm":
|
||
|
target = "arm32"
|
||
|
gen_rom_ram_callback(target, rom_output)
|
||
|
print("ROM CALLBACK BUILD SUCCESSFULLY!!!")
|
||
|
shutil.rmtree(output_path)
|
||
|
return True
|
||
|
|
||
|
def start(self, env, target_name, output_path, nhso=None, clean=None):
|
||
|
# remember the root folder
|
||
|
def _excute(cmd, log_file, is_dump):
|
||
|
errcode = exec_shell(cmd, log_file, is_dump)
|
||
|
if errcode != 0:
|
||
|
self.print_build_result(target_name, errcode)
|
||
|
sys.exit(1)
|
||
|
org_work_path = os.getcwd()
|
||
|
self.cmake_cmd.append('-DPKG_TARGET_NAME=%s' % target_name)
|
||
|
target_name = target_name.replace('-', "_")
|
||
|
if clean and os.path.exists(output_path):
|
||
|
shutil.rmtree(output_path)
|
||
|
if not os.path.exists(output_path):
|
||
|
os.makedirs(output_path)
|
||
|
self.cmake_cmd.append('-DBUILD_TARGET_NAME=%s' % (target_name))
|
||
|
self.cmake_cmd.append('-DNHSO=%s' %nhso)
|
||
|
chip = env.get('chip')
|
||
|
core = env.get('core')
|
||
|
|
||
|
# Generate the menuconfig header.
|
||
|
mconfig_file_path = os.path.join(root_path, 'build', 'config', 'target_config', chip, 'menuconfig', core, f"{target_name}.config")
|
||
|
if os.path.exists(mconfig_file_path):
|
||
|
if env.get('reload_kconfig'):
|
||
|
print("build reload %s" %mconfig_file_path)
|
||
|
mconfig("reloadconfig", chip, core, target_name, output_path)
|
||
|
mconfig("savemenuconfig", chip, core, target_name, output_path)
|
||
|
|
||
|
os.chdir(output_path)
|
||
|
log_file_name = "build_%s.log" % target_name
|
||
|
log_file = os.path.join(output_root, chip, log_file_name)
|
||
|
|
||
|
# run 'make'
|
||
|
if self.is_command_refresh(output_path):
|
||
|
self.dump_cmake_command(output_path)
|
||
|
_excute(self.cmake_cmd, log_file, self.dump)
|
||
|
_excute(self.get_build_cmd(env), log_file, self.dump)
|
||
|
else:
|
||
|
ext_cmd = []
|
||
|
components_target = self.get_component(env)
|
||
|
print(components_target)
|
||
|
if components_target:
|
||
|
ext_cmd = ['--target'] + components_target
|
||
|
_excute(["cmake", "--build", output_path, '-j%d' % self.thread] + ext_cmd, log_file, self.dump)
|
||
|
|
||
|
if len(self.get_component(env)) > 0:
|
||
|
os.chdir(org_work_path)
|
||
|
print("######### Build target:%s, component:[%s] success" % (target_name, ' '.join(self.get_component(env))))
|
||
|
return 0
|
||
|
|
||
|
if env.is_enable_hso() and not nhso:
|
||
|
cmd = self.get_build_cmd(env)
|
||
|
cmd.append("HSO_DB")
|
||
|
_excute(cmd, log_file, self.dump)
|
||
|
|
||
|
# switch the work folder back
|
||
|
os.chdir(org_work_path)
|
||
|
self.print_build_result(target_name, 0)
|
||
|
return 0
|
||
|
|
||
|
def add_cmake_param(self, param):
|
||
|
"""
|
||
|
accept string only
|
||
|
"""
|
||
|
self.cmake_cmd.append(param)
|
||
|
|
||
|
def add_cmake_def(self, env, item):
|
||
|
if env.get(item) is None or env.get(item) == '':
|
||
|
return
|
||
|
self.cmake_cmd.append('-D%s=%s' % (item.upper(), env.get(item)))
|
||
|
|
||
|
def redef_cmake_def(self, env, item):
|
||
|
if env.get(item) is None or env.get(item) == '':
|
||
|
return
|
||
|
val = env.get(item)
|
||
|
item = item.upper()
|
||
|
for i, para in enumerate(self.cmake_cmd):
|
||
|
if not para.startswith('-D%s=' % item):
|
||
|
continue
|
||
|
self.cmake_cmd[i] = '-D%s=%s' % (item, val)
|
||
|
break
|
||
|
|
||
|
def rom_check(self, env, target_name, output_path):
|
||
|
if env.get('rom_sym_path'):
|
||
|
return True
|
||
|
|
||
|
if env.get('fixed_rom'):
|
||
|
fix_path = env.get('fixed_rom_path').replace('<root>', root_path)
|
||
|
bin1 = os.path.join(output_path, '%s_rom.bin' % env.get('bin_name'))
|
||
|
bin2 = fix_path
|
||
|
if not compare_bin(bin1, bin2):
|
||
|
print(f"ERROR! :{bin1} is not same with {bin2}")
|
||
|
sys.exit(1)
|
||
|
return True
|
||
|
|
||
|
if env.get('rom_ram_check'):
|
||
|
self.add_cmake_param("-DROM_CHECK=True")
|
||
|
self.start(env, target_name, output_path, clean=False, nhso=True)
|
||
|
if not env.get('rom_ram_compare'):
|
||
|
return True
|
||
|
bin1 = os.path.join(output_path, '%s_rom.bin' % env.get('bin_name'))
|
||
|
bin2 = os.path.join(output_path, '%s_romcheck_rom.bin' % env.get('bin_name'))
|
||
|
if not compare_bin(bin1, bin2):
|
||
|
print(f"ERROR! :{bin1} is not same with {bin2}")
|
||
|
sys.exit(1)
|
||
|
|
||
|
def pack_fwpkg(self, chip, target_name):
|
||
|
# bin packet all in one
|
||
|
packet_script_path = os.path.join(pkg_tools_path, 'packet.py')
|
||
|
print("packet ing...")
|
||
|
errcode = exec_shell([self.python_path, packet_script_path, chip, target_name, " ".join(self.extr_defines)], None, True)
|
||
|
if errcode != 0:
|
||
|
print("packet error!")
|
||
|
self.print_build_result(target_name, errcode)
|
||
|
sys.exit(1)
|
||
|
|
||
|
os.system('python3 build/config/target_config/ws63/build_ws63_update.py --pkt=app_iot') #BY _HSF_ Hilink OTA
|
||
|
|
||
|
copy_file("output/ws63/fwpkg/ws63-liteos-app-iot/ws63-liteos-app-iot_mfg_all.fwpkg", "output/LPT262_hilink_MFG.fwpkg") # ====>BY _HSF
|
||
|
copy_file("output/ws63/fwpkg/ws63-liteos-app-iot/ws63-liteos-app-iot_all.fwpkg", "output/LPT262_hilink.fwpkg")
|
||
|
copy_file("output/ws63/upgrade/update.fwpkg", "output/LPT262_hilink_UPGRADE.bin")
|
||
|
|
||
|
print("packet success!")
|
||
|
print (time.strftime("%Y年%m月%d日")+" ("+time.strftime("%H:%M:%S")+")")
|
||
|
|
||
|
|
||
|
|
||
|
def pack_fota(self, chip, target_name, option):
|
||
|
fota_script_path = os.path.join(root_path, 'build', 'config', 'target_config', chip, 'build_' + chip + '_update.py')
|
||
|
print("fota packet generating...")
|
||
|
errcode = exec_shell([self.python_path, fota_script_path, target_name, option], None, True)
|
||
|
if errcode != 0:
|
||
|
print("fota packet error!")
|
||
|
self.print_build_result(target_name, errcode)
|
||
|
sys.exit(1)
|
||
|
print("fota packet success!")
|
||
|
|
||
|
def dump_cmake_command(self, output_path):
|
||
|
with open(os.path.join(output_path, 'cmake_command.txt'), "w") as f:
|
||
|
f.write("\n".join(self.cmake_cmd))
|
||
|
|
||
|
def is_command_refresh(self, output_path):
|
||
|
cmd_path = os.path.join(output_path, 'cmake_command.txt')
|
||
|
if not os.path.exists(cmd_path):
|
||
|
return True
|
||
|
with open(cmd_path, "r") as f:
|
||
|
text = f.read()
|
||
|
return text != "\n".join(self.cmake_cmd)
|