1#!/usr/bin/env python3 2# coding=utf-8 3 4# Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED. 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17""" 18* Description: Utilities of compile system. 19* Create: 2020-1-2 20""" 21 22import os 23import sys 24import time 25import subprocess 26import re 27import shutil 28import fnmatch 29import struct 30import hashlib 31import platform 32import filecmp 33 34root_path = os.path.join(os.path.split(os.path.realpath(__file__))[0], '..', '..', '..') 35root_path = os.path.abspath(root_path) 36script_path = os.path.join(root_path, 'build', 'script') 37target_config_path = os.path.join(root_path, 'build', 'config', 'target_config') 38output_root = os.path.join(root_path, 'output') 39sdk_output_path = os.path.join(output_root, 'sdk') 40pkg_tools_path = os.path.join(root_path, 'tools', 'pkg') 41jlink_tools_path = os.path.join(root_path, 'tools', 'bin', 'jlink_tool') 42lzma_tools_path = os.path.join(root_path, 'tools', 'bin', 'lzma_tool') 43sign_tools_path = os.path.join(root_path, 'tools', 'bin', 'sign_tool') 44derived_tools_path = os.path.join(root_path, 'tools', 'bin', 'derived_key_tool') 45 46""" 47Colors defines. To highlight important output. 48""" 49__colors__ = {'purple': '\033[95m', 'red': '\033[91m', 'blue': '\033[94m', 'green': '\033[92m', 'end': '\033[0m'} 50 51 52class BuildError(Exception): 53 """ 54 Error handling, highlight in red. 55 """ 56 def __init__(self, err): 57 emsg = "%s%s%s" % (color_red(), err, color_end()) 58 Exception.__init__(self, emsg) 59 60 61class BuildTimer: 62 """ 63 timer 64 """ 65 def __init__(self, name='A'): 66 self._start = -1 67 self._name = name 68 69 def start(self): 70 self._start = time.time() 71 72 def stop(self): 73 if self._start == -1: 74 raise BuildError("Timer %s never been started!" % self._name) 75 retval = time.time() - self._start 76 self._start = -1 77 return retval 78 79 80class CopyModule: 81 def __init__(self, replace_root='', replace_suffix='', pattern='*', copy_header = True): 82 self.replace_root = replace_root 83 if replace_suffix and isinstance(replace_suffix, str): 84 replace_suffix = [replace_suffix] 85 86 self.replace_suffix = replace_suffix 87 self.mask = ['__pycache__', '.git*'] 88 self.pattern = pattern 89 self.copy_header = copy_header 90 91 def append_mask(self, mask): 92 if isinstance(mask, list): 93 self.mask.extend(mask) 94 return 95 self.mask.append(mask) 96 97 def __ignore(self, path, names): 98 ignored_names = [] 99 names = set(names) 100 for mask in self.mask: 101 ignored_names.extend(fnmatch.filter(names, mask)) 102 if self.pattern == "*.h" and 'drivers/hal' not in path: 103 for name in names: 104 if "." in name and not name.endswith('.h'): 105 ignored_names.append(name) 106 else: 107 ignored_names.extend(names - set(fnmatch.filter(names, self.pattern))) 108 return set(ignored_names) 109 110 def copy_file(self, file, dest=None): 111 if dest is None and self.replace_root: 112 dest = file.replace(root_path, self.replace_root) 113 if os.path.exists(dest) and os.path.isfile(dest): 114 return None 115 path = os.path.split(dest)[0] 116 if not os.path.exists(path): 117 os.makedirs(path, exist_ok=True) 118 if self.replace_suffix: 119 for suffix in self.replace_suffix: 120 if os.path.exists(file + suffix): 121 file = file + suffix 122 break 123 try: 124 shutil.copy2(file, dest, follow_symlinks=True) 125 except: 126 print("[WARN] copy %s exception" % file) 127 return 128 if self.copy_header: 129 self.copy_file_header(file) 130 return dest 131 132 #add for copy header file 133 def copy_file_header(self, file): 134 file_path = os.path.dirname(file) 135 for inner_file in os.listdir(file_path): 136 if not inner_file.endswith('.h'): 137 continue 138 tmp_src = "%s/%s" %(file_path, inner_file) 139 tmp_dest = "%s/%s" %(file_path.replace(root_path, sdk_output_path), inner_file) 140 if self.replace_suffix: 141 for suffix in self.replace_suffix: 142 if os.path.exists(tmp_src + suffix): 143 tmp_src = tmp_src + suffix 144 break 145 if not os.path.exists(tmp_dest): 146 if not os.path.isdir(os.path.dirname(tmp_dest)): 147 os.makedirs(os.path.dirname(tmp_dest), exist_ok=True) 148 shutil.copy(tmp_src, tmp_dest) 149 150 def copy_folder(self, path, dest=None): 151 if dest is None and self.replace_root: 152 dest = path.replace(root_path, self.replace_root) 153 shutil.copytree(path, dest, copy_function=self.copy_file, dirs_exist_ok=True, ignore=self.__ignore) 154 return dest 155 156 def copy(self, src, dest=None): 157 if not os.path.exists(src): 158 print("WARNING : Sdk copy src: %s is not exists!!" % src) 159 return 160 if os.path.isfile(src): 161 return self.copy_file(src, dest) 162 else: 163 return self.copy_folder(src, dest) 164 165 166# End of class BuildTimer 167 168def color_red(): 169 return __colors__.get('red') 170 171 172def color_purple(): 173 return __colors__.get('purple') 174 175 176def color_blue(): 177 return __colors__.get('blue') 178 179 180def color_green(): 181 return __colors__.get('green') 182 183 184def color_end(): 185 return __colors__.get('end') 186 187 188def print_info(msg): 189 print(msg) 190 191 192def print_tips(msg): 193 print("%s%s%s" % (color_purple(), msg, color_end())) 194 195 196def print_warning(msg): 197 print("%s%s%s" % (color_green(), msg, color_end())) 198 199 200def print_alert(msg): 201 print("%s%s%s" % (color_red(), msg, color_end())) 202 203def cmp_file(f1, f2): 204 filecmp.clear_cache() 205 return filecmp.cmp(f1, f2, shallow = False) 206 207def fn_filter_dirs(dirs, filters=None): 208 if filters is None: 209 filters = [] 210 retval = list(dirs) 211 for dir_path in dirs: 212 for item in filters: 213 fstr = "%s%s%s" % (os.sep, item, os.sep) 214 if dir_path.find(fstr) >= 0: 215 try: 216 print("remove dir_path:%s" % dir_path) 217 retval.remove(dir_path) 218 except ValueError as e: 219 print(e) 220 221 return retval 222 223 224def fn_search_all_files(top_dir, file_name, excludes=[]): 225 """ 226 Traverse sub-folders to find all files named "file_name". 227 """ 228 retval = [] 229 for dir_path, dir_names, file_names in os.walk(top_dir, followlinks=True): 230 # remove useless folder first 231 dir_names = [dir_names.remove(x) for x in dir_names if x.startswith(".")] 232 if file_name in file_names: 233 retval.append(os.path.join(dir_path, file_name)) 234 return fn_filter_dirs(retval, excludes) 235 236 237def fn_search_all_dirs(top_dir, dir_name, excludes=None): 238 """ 239 Traverse sub-folders to find all files named "dir_name". 240 """ 241 if excludes is None: 242 excludes = [] 243 retval = [] 244 for dir_path, dir_names, file_names in os.walk(top_dir, followlinks=True): 245 if not dir_names: 246 continue 247 # remove useless folder first 248 temp_dirs = list(dir_names) 249 dirnames = [x for x in dir_names if not x.startswith(".")] 250 for dirname in dirnames: 251 if dirname and dirname == dir_name: 252 retval.append(os.path.join(dir_path, dirname)) 253 return fn_filter_dirs(retval, excludes) 254 255 256def fn_get_subdirs(dir_path): 257 lst = [name for name in os.listdir(dir_path) if os.path.isdir(os.path.join(dir_path, name)) and name[0] != '.'] 258 lst.sort() 259 return lst 260 261 262def fn_str_to_int(text, num=None): 263 if num is not None: 264 return int(text, num) 265 match1 = re.match(r'\s*0x', text) 266 match2 = re.match(r'\s*0X', text) 267 if match1 or match2: 268 return int(text, 16) 269 else: 270 return int(text, 10) 271 272 273def bf_to_str(bf): 274 """ 275 Convert build error from scons to string. 276 """ 277 if bf is None: 278 return '(unknown targets product None in list)' 279 elif bf.node: 280 return str(bf.node) + ': ' + bf.errstr 281 elif bf.filename: 282 return bf.filename + ': ' + bf.errstr 283 else: 284 return str(bf) 285 286 287def exec_shell(cmd, logfile=None, cmd_dump=False): 288 """ 289 call shell 290 """ 291 cmd_list = cmd 292 if isinstance(cmd, str): 293 cmd_list = cmd.split(' ') 294 295 if cmd_dump: 296 print(str(cmd_list)) 297 298 subp = subprocess.Popen(cmd_list, shell=False) 299 subp.wait() 300 code = subp.returncode 301 302 return code 303 304 305def add_temp_sys_path(path): 306 env_path = os.environ.get('PATH') 307 if path.startswith(os.sep): 308 work_path = path 309 else: 310 work_path = os.path.join(os.getcwd(), path) 311 312 if work_path not in env_path: 313 new_env_path = ':'.join([work_path, env_path]) 314 os.environ['PATH'] = new_env_path 315 return os.environ.get('PATH') 316 317 318def rm_all(items): 319 for item in items: 320 if os.path.isdir(item): 321 shutil.rmtree(item) 322 elif os.path.isfile(item): 323 os.unlink(item) 324 else: 325 pass 326 327def add_len_and_sha256_info_to_ssb(source, chip=None): 328 with open(source, "rb+") as bin_file: 329 length = len(bin_file.read()) 330 if chip == "brandy": 331 bin_file.seek(364, 0) # ssb length offset addr 0x16c 332 elif chip == "socmn1": 333 bin_file.seek(404, 0) # ssb length offset addr 0x194 334 else: 335 bin_file.seek(360, 0) # ssb length offset addr 0x168 336 bin_file.write(struct.pack('<L', length)) 337 bin_file.close() 338 339 with open(source, "rb+") as bin_file: 340 sha = hashlib.sha256(bin_file.read()) 341 bin_file.write(sha.digest()[0:32]) 342 bin_file.close() 343 344def create_hex_file(target, source): 345 with open(source, "rb") as binfile, open( 346 target, "wb") as hexfile: 347 while True: 348 bindata = binfile.read(4) 349 if not bindata: 350 break 351 longdata, = struct.unpack("<L", bindata) 352 hexstr = '{:x}'.format(longdata) # dec to hex number str 353 hexstr = '%s\n' % '{:0>8}'.format(hexstr).upper() 354 hexfile.write(str.encode(hexstr)) 355 356def compare_bin(bin1, bin2): 357 print("Comparing:") 358 print(bin1) 359 print(bin2) 360 if not cmp_file(bin1, bin2): 361 print("DIFF") 362 return False 363 print("SAME") 364 return True 365 366def rm_pyc(root): 367 pyc_dirs = fn_search_all_dirs(root, "__pycache__") 368 rm_all(pyc_dirs) 369 370 371def get_diff(list0, list1): 372 diff = list(set(list0) - set(list1)) 373 return diff 374 375 376def copy(src, dest, replace_suffix='', pattern="*"): 377 c = CopyModule(replace_suffix=replace_suffix, pattern=pattern) 378 c.copy(src, dest) 379 380def copy_force(src, dest, pattern = ".a"): 381 for file_name in os.listdir(src): 382 if file_name.endswith(pattern): 383 tmp_src = "%s/%s" %(src, file_name) 384 shutil.copy(tmp_src, dest) 385 386def get_platform_name(): 387 return platform.system().lower() 388 389if __name__ == "__main__": 390 func_list = [ 391 "copy", 392 "add_len_and_sha256_info_to_ssb", 393 "create_hex_file", 394 "copy_force" 395 ] 396 func = sys.argv[1] 397 if func not in func_list: 398 print("ERROR! WRONG FUNC!! YOU CAN ONLY INVOKE FUNC BELOW:") 399 for function in func_list: 400 print(function) 401 sys.exit(1) 402 arg_num = locals()[func].__code__.co_argcount 403 if arg_num == 1: 404 locals()[func](sys.argv[2]) 405 elif arg_num == 2: 406 locals()[func](sys.argv[2], sys.argv[3]) 407 elif arg_num == 3: 408 locals()[func](sys.argv[2], sys.argv[3], sys.argv[4]) 409 elif arg_num == 4: 410 locals()[func](sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5]) 411 elif arg_num == 5: 412 locals()[func](sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5], sys.argv[6]) 413 elif arg_num == 6: 414 locals()[func](sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5], sys.argv[6], sys.argv[7]) 415 else: 416 print("ERROR! arg number out of range") 417