1#! /usr/bin/env python 2# coding=utf-8 3# 4# Copyright (c) 2024, RT-Thread Development Team 5# 6# SPDX-License-Identifier: GPL-2.0 7# 8# Change Logs: 9# Date Author Notes 10# 2024-04-20 Bernard the first version 11 12import os 13import json 14import platform 15import re 16import sys 17import shutil 18import hashlib 19import operator 20 21 22def GetEnvPath(): 23 if "ENV_ROOT" in os.environ: 24 return os.environ["ENV_ROOT"] 25 26 if platform.system() == 'Windows': 27 env_root = os.path.join(os.environ['USERPROFILE'], '.env') 28 else: 29 env_root = os.path.join(os.environ['HOME'], '.env') 30 31 return env_root 32 33 34def GetPkgPath(): 35 if "PKGS_DIR" in os.environ: 36 return os.environ["PKGS_DIR"] 37 elif "PKGS_ROOT" in os.environ: 38 return os.environ["PKGS_ROOT"] 39 elif GetEnvPath(): 40 return os.path.join(GetEnvPath(), "packages") 41 else: 42 return None 43 44def GetSDKPackagePath(): 45 env = GetEnvPath() 46 47 if env: 48 return os.path.join(env, "tools", "scripts", "packages") 49 50 return None 51 52# get SDK path based on name 53# for example, GetSDKPath('arm-none-eabi') = '.env/tools/scripts/packages/arm-none-eabi-gcc-v10.3' 54def GetSDKPath(name): 55 sdk_pkgs = GetSDKPackagePath() 56 57 if sdk_pkgs: 58 # read env/tools/scripts/sdk_cfg.json for curstomized SDK path 59 if os.path.exists(os.path.join(sdk_pkgs, '..', 'sdk_cfg.json')): 60 with open(os.path.join(sdk_pkgs, '..', 'sdk_cfg.json'), 'r', encoding='utf-8') as f: 61 sdk_cfg = json.load(f) 62 for item in sdk_cfg: 63 if item['name'] == name: 64 sdk = os.path.join(sdk_pkgs, item['path']) 65 return sdk 66 67 # read packages.json under env/tools/scripts/packages 68 with open(os.path.join(sdk_pkgs, 'pkgs.json'), 'r', encoding='utf-8') as f: 69 # packages_json = f.read() 70 packages = json.load(f) 71 72 for item in packages: 73 package_path = os.path.join(GetEnvPath(), 'packages', item['path'], 'package.json') 74 # read package['path']/package.json under env/packages 75 with open(package_path, 'r', encoding='utf-8') as f: 76 # package_json = f.read() 77 package = json.load(f) 78 79 if package['name'] == name: 80 sdk = os.path.join(sdk_pkgs, package['name'] + '-' + item['ver']) 81 return sdk 82 83 # not found named package 84 return None 85 86def help_info(): 87 print( 88 "**********************************************************************************\n" 89 "* Help infomation:\n" 90 "* Git tool install step.\n" 91 "* If your system is linux, you can use command below to install git.\n" 92 "* $ sudo yum install git\n" 93 "* $ sudo apt-get install git\n" 94 "* If your system is windows, you should download git software(msysGit).\n" 95 "* Download path: http://git-scm.com/download/win\n" 96 "* After you install it, be sure to add the git command execution PATH \n" 97 "* to your system PATH.\n" 98 "* Usually, git command PATH is $YOUR_INSTALL_DIR\\Git\\bin\n" 99 "* If your system is OSX, please download git and install it.\n" 100 "* Download path: http://git-scm.com/download/mac\n" 101 "**********************************************************************************\n" 102 ) 103 104 105def touch_env(use_gitee=False): 106 if sys.platform != 'win32': 107 home_dir = os.environ['HOME'] 108 else: 109 home_dir = os.environ['USERPROFILE'] 110 111 if use_gitee: 112 # "Install RT-Thread Environment from Gitee" 113 sdk_url = 'https://gitee.com/RT-Thread-Mirror/sdk.git' 114 pkg_url = 'https://gitee.com/RT-Thread-Mirror/packages.git' 115 env_url = 'https://gitee.com/RT-Thread-Mirror/env.git' 116 else: 117 pkg_url = 'https://github.com/RT-Thread/packages.git' 118 sdk_url = 'https://github.com/RT-Thread/sdk.git' 119 env_url = 'https://github.com/RT-Thread/env.git' 120 121 pkg_url = os.getenv('RTT_PACKAGE_URL') or pkg_url 122 sdk_url = os.getenv('RTT_SDK_URL') or sdk_url 123 env_url = os.getenv('RTT_ENV_URL') or env_url 124 125 # make .env and other directories 126 env_dir = os.path.join(home_dir, '.env') 127 if not os.path.exists(env_dir): 128 os.mkdir(env_dir) 129 os.mkdir(os.path.join(env_dir, 'local_pkgs')) 130 os.mkdir(os.path.join(env_dir, 'packages')) 131 os.mkdir(os.path.join(env_dir, 'tools')) 132 kconfig = open(os.path.join(env_dir, 'packages', 'Kconfig'), 'w') 133 kconfig.close() 134 135 # git clone packages 136 if not os.path.exists(os.path.join(env_dir, 'packages', 'packages')): 137 try: 138 ret = os.system('git clone %s %s' % (pkg_url, os.path.join(env_dir, 'packages', 'packages'))) 139 if ret != 0: 140 shutil.rmtree(os.path.join(env_dir, 'packages', 'packages')) 141 print( 142 "********************************************************************************\n" 143 "* Warnning:\n" 144 "* Run command error for \"git clone https://github.com/RT-Thread/packages.git\".\n" 145 "* This error may have been caused by not found a git tool or network error.\n" 146 "* If the git tool is not installed, install the git tool first.\n" 147 "* If the git utility is installed, check whether the git command is added to \n" 148 "* the system PATH.\n" 149 "* This error may cause the RT-Thread packages to not work properly.\n" 150 "********************************************************************************\n" 151 ) 152 help_info() 153 else: 154 kconfig = open(os.path.join(env_dir, 'packages', 'Kconfig'), 'w') 155 kconfig.write('source "$PKGS_DIR/packages/Kconfig"') 156 kconfig.close() 157 except: 158 print( 159 "**********************************************************************************\n" 160 "* Warnning:\n" 161 "* Run command error for \"git clone https://github.com/RT-Thread/packages.git\". \n" 162 "* This error may have been caused by not found a git tool or git tool not in \n" 163 "* the system PATH. \n" 164 "* This error may cause the RT-Thread packages to not work properly. \n" 165 "**********************************************************************************\n" 166 ) 167 help_info() 168 169 # git clone env scripts 170 if not os.path.exists(os.path.join(env_dir, 'tools', 'scripts')): 171 try: 172 ret = os.system('git clone %s %s' % (env_url, os.path.join(env_dir, 'tools', 'scripts'))) 173 if ret != 0: 174 shutil.rmtree(os.path.join(env_dir, 'tools', 'scripts')) 175 print( 176 "********************************************************************************\n" 177 "* Warnning:\n" 178 "* Run command error for \"git clone https://github.com/RT-Thread/env.git\".\n" 179 "* This error may have been caused by not found a git tool or network error.\n" 180 "* If the git tool is not installed, install the git tool first.\n" 181 "* If the git utility is installed, check whether the git command is added \n" 182 "* to the system PATH.\n" 183 "* This error may cause script tools to fail to work properly.\n" 184 "********************************************************************************\n" 185 ) 186 help_info() 187 except: 188 print( 189 "********************************************************************************\n" 190 "* Warnning:\n" 191 "* Run command error for \"git clone https://github.com/RT-Thread/env.git\". \n" 192 "* This error may have been caused by not found a git tool or git tool not in \n" 193 "* the system PATH. \n" 194 "* This error may cause script tools to fail to work properly. \n" 195 "********************************************************************************\n" 196 ) 197 help_info() 198 199 # git clone sdk 200 if not os.path.exists(os.path.join(env_dir, 'packages', 'sdk')): 201 try: 202 ret = os.system('git clone %s %s' % (sdk_url, os.path.join(env_dir, 'packages', 'sdk'))) 203 if ret != 0: 204 shutil.rmtree(os.path.join(env_dir, 'packages', 'sdk')) 205 print( 206 "********************************************************************************\n" 207 "* Warnning:\n" 208 "* Run command error for \"git clone https://github.com/RT-Thread/sdk.git\".\n" 209 "* This error may have been caused by not found a git tool or network error.\n" 210 "* If the git tool is not installed, install the git tool first.\n" 211 "* If the git utility is installed, check whether the git command is added \n" 212 "* to the system PATH.\n" 213 "* This error may cause the RT-Thread SDK to not work properly.\n" 214 "********************************************************************************\n" 215 ) 216 help_info() 217 except: 218 print( 219 "********************************************************************************\n" 220 "* Warnning:\n" 221 "* Run command error for \"https://github.com/RT-Thread/sdk.git\".\n" 222 "* This error may have been caused by not found a git tool or git tool not in \n" 223 "* the system PATH. \n" 224 "* This error may cause the RT-Thread SDK to not work properly. \n" 225 "********************************************************************************\n" 226 ) 227 help_info() 228 229 # try to create an empty .config file 230 if not os.path.exists(os.path.join(env_dir, 'tools', '.config')): 231 kconfig = open(os.path.join(env_dir, 'tools', '.config'), 'w') 232 kconfig.close() 233 234 # copy env.sh or env.ps1, Kconfig 235 shutil.copy(os.path.join(env_dir, 'tools', 'scripts', 'Kconfig'), os.path.join(home_dir, '.env', 'tools')) 236 if sys.platform != 'win32': 237 shutil.copy(os.path.join(env_dir, 'tools', 'scripts', 'env.sh'), os.path.join(home_dir, '.env', 'env.sh')) 238 else: 239 shutil.copy(os.path.join(env_dir, 'tools', 'scripts', 'env.ps1'), os.path.join(home_dir, '.env', 'env.ps1')) 240 # unzip kconfig-mconf.zip 241 # zip_file = os.path.join(env_dir, 'tools', 'scripts', 'kconfig-mconf.zip') 242 # if os.path.exists(zip_file): 243 # zip_file_dir = os.path.join(env_dir, 'tools', 'bin') 244 # if os.path.exists(zip_file_dir): 245 # shutil.rmtree(zip_file_dir) 246 # zip_file_obj = zipfile.ZipFile(zip_file, 'r') 247 # for file in zip_file_obj.namelist(): 248 # zip_file_obj.extract(file, zip_file_dir) 249 # zip_file_obj.close() 250 251 252def is_pkg_special_config(config_str): 253 '''judge if it's CONFIG_PKG_XX_PATH or CONFIG_PKG_XX_VER''' 254 255 if type(config_str) == type('a'): 256 if config_str.startswith("PKG_") and (config_str.endswith('_PATH') or config_str.endswith('_VER')): 257 return True 258 return False 259 260 261def mk_rtconfig(filename): 262 try: 263 config = open(filename, 'r') 264 except: 265 print('open config:%s failed' % filename) 266 return 267 268 rtconfig = open('rtconfig.h', 'w') 269 rtconfig.write('#ifndef RT_CONFIG_H__\n') 270 rtconfig.write('#define RT_CONFIG_H__\n\n') 271 272 empty_line = 1 273 274 for line in config: 275 line = line.lstrip(' ').replace('\n', '').replace('\r', '') 276 277 if len(line) == 0: 278 continue 279 280 if line[0] == '#': 281 if len(line) == 1: 282 if empty_line: 283 continue 284 285 rtconfig.write('\n') 286 empty_line = 1 287 continue 288 289 if line.startswith('# CONFIG_'): 290 line = ' ' + line[9:] 291 else: 292 line = line[1:] 293 rtconfig.write('/*%s */\n' % line) 294 295 empty_line = 0 296 else: 297 empty_line = 0 298 setting = line.split('=') 299 if len(setting) >= 2: 300 if setting[0].startswith('CONFIG_'): 301 setting[0] = setting[0][7:] 302 303 # remove CONFIG_PKG_XX_PATH or CONFIG_PKG_XX_VER 304 if is_pkg_special_config(setting[0]): 305 continue 306 307 if setting[1] == 'y': 308 rtconfig.write('#define %s\n' % setting[0]) 309 else: 310 rtconfig.write('#define %s %s\n' % (setting[0], re.findall(r"^.*?=(.*)$", line)[0])) 311 312 if os.path.isfile('rtconfig_project.h'): 313 rtconfig.write('#include "rtconfig_project.h"\n') 314 315 rtconfig.write('\n') 316 rtconfig.write('#endif\n') 317 rtconfig.close() 318 319 320def get_file_md5(file): 321 MD5 = hashlib.new('md5') 322 with open(file, 'r') as fp: 323 MD5.update(fp.read().encode('utf8')) 324 fp_md5 = MD5.hexdigest() 325 return fp_md5 326 327 328# Exclude utestcases 329def exclude_utestcases(RTT_ROOT): 330 if os.path.isfile(os.path.join(RTT_ROOT, 'examples/utest/testcases/Kconfig')): 331 return 332 333 if not os.path.isfile(os.path.join(RTT_ROOT, 'Kconfig')): 334 return 335 336 with open(os.path.join(RTT_ROOT, 'Kconfig'), 'r') as f: 337 data = f.readlines() 338 with open(os.path.join(RTT_ROOT, 'Kconfig'), 'w') as f: 339 for line in data: 340 if line.find('examples/utest/testcases/Kconfig') == -1: 341 f.write(line) 342 343 344# fix locale for kconfiglib 345def kconfiglib_fix_locale(): 346 import os 347 import locale 348 349 # Get the list of supported locales 350 supported_locales = set(locale.locale_alias.keys()) 351 352 # Check if LANG is set and its value is not in the supported locales 353 if 'LANG' in os.environ and os.environ['LANG'] not in supported_locales: 354 os.environ['LANG'] = 'C' 355 356 357def kconfiglib_check_installed(): 358 try: 359 import kconfiglib 360 except ImportError as e: 361 print("\033[1;31m**ERROR**: Failed to import kconfiglib, " + str(e)) 362 print("") 363 print("You may need to install it using:") 364 print(" pip install kconfiglib\033[0m") 365 print("") 366 sys.exit(1) 367 368 # set PKGS_DIR envrionment 369 pkg_dir = GetPkgPath() 370 if os.path.exists(pkg_dir): 371 os.environ["PKGS_DIR"] = pkg_dir 372 elif sys.platform != 'win32': 373 touch_env() 374 os.environ["PKGS_DIR"] = GetPkgPath() 375 else: 376 print("\033[1;33m**WARNING**: PKGS_DIR not found, please install ENV tools\033[0m") 377 378 379# menuconfig for Linux and Windows 380def menuconfig(RTT_ROOT): 381 kconfiglib_check_installed() 382 383 import menuconfig 384 385 # Exclude utestcases 386 exclude_utestcases(RTT_ROOT) 387 388 fn = '.config' 389 fn_old = '.config.old' 390 391 sys.argv = ['menuconfig', 'Kconfig'] 392 393 # fix vscode console 394 kconfiglib_fix_locale() 395 396 menuconfig._main() 397 398 if os.path.isfile(fn): 399 if os.path.isfile(fn_old): 400 diff_eq = operator.eq(get_file_md5(fn), get_file_md5(fn_old)) 401 else: 402 diff_eq = False 403 else: 404 sys.exit(-1) 405 406 # make rtconfig.h 407 if diff_eq == False: 408 shutil.copyfile(fn, fn_old) 409 mk_rtconfig(fn) 410 411 412# guiconfig for windows and linux 413def guiconfig(RTT_ROOT): 414 kconfiglib_check_installed() 415 416 import guiconfig 417 418 # Exclude utestcases 419 exclude_utestcases(RTT_ROOT) 420 421 fn = '.config' 422 fn_old = '.config.old' 423 424 sys.argv = ['guiconfig', 'Kconfig'] 425 guiconfig._main() 426 427 if os.path.isfile(fn): 428 if os.path.isfile(fn_old): 429 diff_eq = operator.eq(get_file_md5(fn), get_file_md5(fn_old)) 430 else: 431 diff_eq = False 432 else: 433 sys.exit(-1) 434 435 # make rtconfig.h 436 if diff_eq == False: 437 shutil.copyfile(fn, fn_old) 438 mk_rtconfig(fn) 439 440 441# defconfig for windows and linux 442def defconfig(RTT_ROOT): 443 kconfiglib_check_installed() 444 445 import defconfig 446 447 # Exclude utestcases 448 exclude_utestcases(RTT_ROOT) 449 450 fn = '.config' 451 452 sys.argv = ['defconfig', '--kconfig', 'Kconfig', '.config'] 453 defconfig.main() 454 455 # silent mode, force to make rtconfig.h 456 mk_rtconfig(fn) 457 458 459def genconfig(): 460 from SCons.Script import SCons 461 462 PreProcessor = SCons.cpp.PreProcessor() 463 464 try: 465 f = open('rtconfig.h', 'r') 466 contents = f.read() 467 f.close() 468 except: 469 print("Open rtconfig.h file failed.") 470 471 PreProcessor.process_contents(contents) 472 options = PreProcessor.cpp_namespace 473 474 try: 475 f = open('.config', 'w') 476 for opt, value in options.items(): 477 if type(value) == type(1): 478 f.write("CONFIG_%s=%d\n" % (opt, value)) 479 480 if type(value) == type('') and value == '': 481 f.write("CONFIG_%s=y\n" % opt) 482 elif type(value) == type('str'): 483 f.write("CONFIG_%s=%s\n" % (opt, value)) 484 485 print("Generate .config done!") 486 f.close() 487 except: 488 print("Generate .config file failed.") 489