• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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