1# 2# File : utils.py 3# This file is part of RT-Thread RTOS 4# COPYRIGHT (C) 2006 - 2015, RT-Thread Development Team 5# 6# This program is free software; you can redistribute it and/or modify 7# it under the terms of the GNU General Public License as published by 8# the Free Software Foundation; either version 2 of the License, or 9# (at your option) any later version. 10# 11# This program is distributed in the hope that it will be useful, 12# but WITHOUT ANY WARRANTY; without even the implied warranty of 13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14# GNU General Public License for more details. 15# 16# You should have received a copy of the GNU General Public License along 17# with this program; if not, write to the Free Software Foundation, Inc., 18# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19# 20# Change Logs: 21# Date Author Notes 22# 2015-01-20 Bernard Add copyright information 23# 2024-04-21 Bernard Add ImportModule to import local module 24 25import sys 26import os 27import re 28 29def splitall(loc): 30 """ 31 Return a list of the path components in loc. (Used by relpath_). 32 33 The first item in the list will be either ``os.curdir``, ``os.pardir``, empty, 34 or the root directory of loc (for example, ``/`` or ``C:\\). 35 36 The other items in the list will be strings. 37 38 Adapted from *path.py* by Jason Orendorff. 39 """ 40 parts = [] 41 while loc != os.curdir and loc != os.pardir: 42 prev = loc 43 loc, child = os.path.split(prev) 44 if loc == prev: 45 break 46 parts.append(child) 47 parts.append(loc) 48 parts.reverse() 49 return parts 50 51def _make_path_relative(origin, dest): 52 """ 53 Return the relative path between origin and dest. 54 55 If it's not possible return dest. 56 57 58 If they are identical return ``os.curdir`` 59 60 Adapted from `path.py <http://www.jorendorff.com/articles/python/path/>`_ by Jason Orendorff. 61 """ 62 origin = os.path.abspath(origin).replace('\\', '/') 63 dest = os.path.abspath(dest).replace('\\', '/') 64 # 65 orig_list = splitall(os.path.normcase(origin)) 66 # Don't normcase dest! We want to preserve the case. 67 dest_list = splitall(dest) 68 # 69 if orig_list[0] != os.path.normcase(dest_list[0]): 70 # Can't get here from there. 71 return dest 72 # 73 # Find the location where the two paths start to differ. 74 i = 0 75 for start_seg, dest_seg in zip(orig_list, dest_list): 76 if start_seg != os.path.normcase(dest_seg): 77 break 78 i += 1 79 # 80 # Now i is the point where the two paths diverge. 81 # Need a certain number of "os.pardir"s to work up 82 # from the origin to the point of divergence. 83 segments = [os.pardir] * (len(orig_list) - i) 84 # Need to add the diverging part of dest_list. 85 segments += dest_list[i:] 86 if len(segments) == 0: 87 # If they happen to be identical, use os.curdir. 88 return os.curdir 89 else: 90 # return os.path.join(*segments).replace('\\', '/') 91 return os.path.join(*segments) 92 93def xml_indent(elem, level=0): 94 i = "\n" + level*" " 95 if len(elem): 96 if not elem.text or not elem.text.strip(): 97 elem.text = i + " " 98 if not elem.tail or not elem.tail.strip(): 99 elem.tail = i 100 for elem in elem: 101 xml_indent(elem, level+1) 102 if not elem.tail or not elem.tail.strip(): 103 elem.tail = i 104 else: 105 if level and (not elem.tail or not elem.tail.strip()): 106 elem.tail = i 107 108 109source_ext = ["c", "h", "s", "S", "cpp", "cxx", "cc", "xpm"] 110source_list = [] 111 112def walk_children(child): 113 global source_list 114 global source_ext 115 116 # print child 117 full_path = child.rfile().abspath 118 file_type_list = full_path.rsplit('.',1) 119 #print file_type 120 if (len(file_type_list) > 1): 121 file_type = full_path.rsplit('.',1)[1] 122 123 if file_type in source_ext: 124 if full_path not in source_list: 125 source_list.append(full_path) 126 127 children = child.all_children() 128 if children != []: 129 for item in children: 130 walk_children(item) 131 132def PrefixPath(prefix, path): 133 path = os.path.abspath(path) 134 prefix = os.path.abspath(prefix) 135 136 if sys.platform == 'win32': 137 prefix = prefix.lower() 138 path = path.lower() 139 140 if path.startswith(prefix): 141 return True 142 143 return False 144 145def ListMap(l): 146 ret_list = [] 147 for item in l: 148 if type(item) == type(()): 149 ret = ListMap(item) 150 ret_list += ret 151 elif type(item) == type([]): 152 ret = ListMap(item) 153 ret_list += ret 154 else: 155 ret_list.append(item) 156 157 return ret_list 158 159def TargetGetList(env, postfix): 160 global source_ext 161 global source_list 162 163 target = env['target'] 164 165 source_ext = postfix 166 for item in target: 167 walk_children(item) 168 169 source_list.sort() 170 171 return source_list 172 173def ProjectInfo(env): 174 175 project = env['project'] 176 RTT_ROOT = env['RTT_ROOT'] 177 BSP_ROOT = env['BSP_ROOT'] 178 179 FILES = [] 180 DIRS = [] 181 HEADERS = [] 182 CPPPATH = [] 183 CPPDEFINES = [] 184 185 for group in project: 186 # get each files 187 if 'src' in group and group['src']: 188 FILES += group['src'] 189 190 # get each include path 191 if 'CPPPATH' in group and group['CPPPATH']: 192 CPPPATH += group['CPPPATH'] 193 194 if 'CPPDEFINES' in env: 195 CPPDEFINES = env['CPPDEFINES'] 196 CPPDEFINES = ListMap(CPPDEFINES) 197 198 # process FILES and DIRS 199 if len(FILES): 200 # use absolute path 201 for i in range(len(FILES)): 202 FILES[i] = os.path.abspath(str(FILES[i])) 203 DIRS.append(os.path.dirname(FILES[i])) 204 205 FILES.sort() 206 DIRS = list(set(DIRS)) 207 DIRS.sort() 208 209 # process HEADERS 210 HEADERS = TargetGetList(env, ['h']) 211 212 # process CPPPATH 213 if len(CPPPATH): 214 # use absolute path 215 for i in range(len(CPPPATH)): 216 CPPPATH[i] = os.path.abspath(CPPPATH[i]) 217 218 # remove repeat path 219 paths = [] 220 for p in CPPPATH: 221 if p not in paths: 222 paths.append(p) 223 224 CPPPATH = [] 225 for path in paths: 226 if PrefixPath(RTT_ROOT, path): 227 CPPPATH += [os.path.abspath(path).replace('\\', '/')] 228 229 elif PrefixPath(BSP_ROOT, path): 230 CPPPATH += [os.path.abspath(path).replace('\\', '/')] 231 232 else: 233 CPPPATH += ['"%s",' % path.replace('\\', '/')] 234 235 # process CPPDEFINES 236 if len(CPPDEFINES): 237 CPPDEFINES = [i for i in set(CPPDEFINES)] 238 239 CPPDEFINES.sort() 240 241 proj = {} 242 proj['FILES'] = FILES 243 proj['DIRS'] = DIRS 244 proj['HEADERS'] = HEADERS 245 proj['CPPPATH'] = CPPPATH 246 proj['CPPDEFINES'] = CPPDEFINES 247 248 return proj 249 250def VersionCmp(ver1, ver2): 251 la=[] 252 if ver1: 253 la = re.split("[. ]", ver1) 254 lb = re.split("[. ]", ver2) 255 256 f = 0 257 if len(la) > len(lb): 258 f = len(la) 259 else: 260 f = len(lb) 261 for i in range(f): 262 try: 263 if int(la[i]) > int(lb[i]): 264 return 1 265 elif int(la[i]) == int(lb[i]): 266 continue 267 else: 268 return -1 269 except (IndexError, ValueError) as e: 270 if len(la) > len(lb): 271 return 1 272 else: 273 return -1 274 return 0 275 276def GCCC99Patch(cflags): 277 import building 278 gcc_version = building.GetDepend('GCC_VERSION_STR') 279 if gcc_version: 280 gcc_version = gcc_version.replace('"', '') 281 if VersionCmp(gcc_version, "4.8.0") == 1: 282 # remove -std=c99 after GCC 4.8.x 283 cflags = cflags.replace('-std=c99', '') 284 285 return cflags 286 287def ReloadModule(module): 288 import sys 289 if sys.version_info.major >= 3: 290 import importlib 291 importlib.reload(module) 292 else: 293 reload(module) 294 295def ImportModule(module): 296 import sys 297 if sys.version_info.major >= 3: 298 import importlib.util 299 path = os.path.dirname(__file__) 300 spec = importlib.util.spec_from_file_location(module, os.path.join(path, module+".py")) 301 module = importlib.util.module_from_spec(spec) 302 spec.loader.exec_module(module) 303 return module 304 else: 305 return __import__(module, fromlist=[module]) 306 307def VerTuple(version_str): 308 ver_parts = version_str.split('.') 309 ver = tuple(int(part) for part in ver_parts) 310 311 return ver 312 313def CmdExists(cmd): 314 # Check if the path directly points to an existing file. 315 if os.path.isfile(cmd): 316 return True 317 else: 318 # On Windows systems, check for common script file extensions 319 # if the file does not exist as specified. 320 if sys.platform.startswith('win'): 321 # Loop through possible extensions to cover cases where the extension is omitted in the input. 322 for ext in ['.exe', '.bat', '.ps1']: 323 # Append the extension to the command path and check if this file exists. 324 if os.path.isfile(cmd + ext): 325 return True 326 327 # If none of the checks confirm the file exists, return False. 328 return False 329