mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2025-10-14 20:00:15 +08:00

Change the entry of utest's Kconfig from 'examples/utest/testcases/Kconfig' to 'Kconfig.utestcases'. Modified the build scripts where the path name is "examples/utest/testcases/Kconfig" and changed it to 'Kconfig.utestcases', otherwise build operations such 'scons --dist' may fail. In the future, the testcase source code of utest will be placed in each module for maintenance, but the entry of Kconfig will all be placed in Kconfig.utestcases for unified maintenance. In this way, when executing menuconfig, people can enter and configure from one place, avoiding searching for utest configuration switches here and there in the menuconfig interface. For each module, you can maintain unit-test in a unified manner in the following way: - Create a subdirectory named 'utest' in the directory where your module is located. - Store the following files in the utest subdirectory: - Unit test case program source code files for this module. - Kconfig file, add configuration options for the unit test files of this module, the recommended option is named RT_UTEST_TC_USING_XXXX, XXXX is the global unique module name of this module. - SConscript file, note that when adding src files, in addition to relying on RT_UTEST_TC_USING_XXXX, you must also rely on RT_UTEST_USING_ALL_CASES, the two dependencies are in an "or" relationship. The role of RT_UTEST_USING_ALL_CASES is that once this option is turned on, all unit tests will be enabled to avoid selecting one by one. After completing the above steps, add the path of the Kconfig file of utest of this module to the Kconfig.utestcases file. Signed-off-by: Chen Wang <unicorn_wang@outlook.com>
489 lines
17 KiB
Python
489 lines
17 KiB
Python
#! /usr/bin/env python
|
|
# coding=utf-8
|
|
#
|
|
# Copyright (c) 2024, RT-Thread Development Team
|
|
#
|
|
# SPDX-License-Identifier: GPL-2.0
|
|
#
|
|
# Change Logs:
|
|
# Date Author Notes
|
|
# 2024-04-20 Bernard the first version
|
|
|
|
import os
|
|
import json
|
|
import platform
|
|
import re
|
|
import sys
|
|
import shutil
|
|
import hashlib
|
|
import operator
|
|
|
|
|
|
def GetEnvPath():
|
|
if "ENV_ROOT" in os.environ:
|
|
return os.environ["ENV_ROOT"]
|
|
|
|
if platform.system() == 'Windows':
|
|
env_root = os.path.join(os.environ['USERPROFILE'], '.env')
|
|
else:
|
|
env_root = os.path.join(os.environ['HOME'], '.env')
|
|
|
|
return env_root
|
|
|
|
|
|
def GetPkgPath():
|
|
if "PKGS_DIR" in os.environ:
|
|
return os.environ["PKGS_DIR"]
|
|
elif "PKGS_ROOT" in os.environ:
|
|
return os.environ["PKGS_ROOT"]
|
|
elif GetEnvPath():
|
|
return os.path.join(GetEnvPath(), "packages")
|
|
else:
|
|
return None
|
|
|
|
def GetSDKPackagePath():
|
|
env = GetEnvPath()
|
|
|
|
if env:
|
|
return os.path.join(env, "tools", "scripts", "packages")
|
|
|
|
return None
|
|
|
|
# get SDK path based on name
|
|
# for example, GetSDKPath('arm-none-eabi') = '.env/tools/scripts/packages/arm-none-eabi-gcc-v10.3'
|
|
def GetSDKPath(name):
|
|
sdk_pkgs = GetSDKPackagePath()
|
|
|
|
if sdk_pkgs:
|
|
# read env/tools/scripts/sdk_cfg.json for curstomized SDK path
|
|
if os.path.exists(os.path.join(sdk_pkgs, '..', 'sdk_cfg.json')):
|
|
with open(os.path.join(sdk_pkgs, '..', 'sdk_cfg.json'), 'r', encoding='utf-8') as f:
|
|
sdk_cfg = json.load(f)
|
|
for item in sdk_cfg:
|
|
if item['name'] == name:
|
|
sdk = os.path.join(sdk_pkgs, item['path'])
|
|
return sdk
|
|
|
|
# read packages.json under env/tools/scripts/packages
|
|
with open(os.path.join(sdk_pkgs, 'pkgs.json'), 'r', encoding='utf-8') as f:
|
|
# packages_json = f.read()
|
|
packages = json.load(f)
|
|
|
|
for item in packages:
|
|
package_path = os.path.join(GetEnvPath(), 'packages', item['path'], 'package.json')
|
|
# read package['path']/package.json under env/packages
|
|
with open(package_path, 'r', encoding='utf-8') as f:
|
|
# package_json = f.read()
|
|
package = json.load(f)
|
|
|
|
if package['name'] == name:
|
|
sdk = os.path.join(sdk_pkgs, package['name'] + '-' + item['ver'])
|
|
return sdk
|
|
|
|
# not found named package
|
|
return None
|
|
|
|
def help_info():
|
|
print(
|
|
"**********************************************************************************\n"
|
|
"* Help infomation:\n"
|
|
"* Git tool install step.\n"
|
|
"* If your system is linux, you can use command below to install git.\n"
|
|
"* $ sudo yum install git\n"
|
|
"* $ sudo apt-get install git\n"
|
|
"* If your system is windows, you should download git software(msysGit).\n"
|
|
"* Download path: http://git-scm.com/download/win\n"
|
|
"* After you install it, be sure to add the git command execution PATH \n"
|
|
"* to your system PATH.\n"
|
|
"* Usually, git command PATH is $YOUR_INSTALL_DIR\\Git\\bin\n"
|
|
"* If your system is OSX, please download git and install it.\n"
|
|
"* Download path: http://git-scm.com/download/mac\n"
|
|
"**********************************************************************************\n"
|
|
)
|
|
|
|
|
|
def touch_env(use_gitee=False):
|
|
if sys.platform != 'win32':
|
|
home_dir = os.environ['HOME']
|
|
else:
|
|
home_dir = os.environ['USERPROFILE']
|
|
|
|
if use_gitee:
|
|
# "Install RT-Thread Environment from Gitee"
|
|
sdk_url = 'https://gitee.com/RT-Thread-Mirror/sdk.git'
|
|
pkg_url = 'https://gitee.com/RT-Thread-Mirror/packages.git'
|
|
env_url = 'https://gitee.com/RT-Thread-Mirror/env.git'
|
|
else:
|
|
pkg_url = 'https://github.com/RT-Thread/packages.git'
|
|
sdk_url = 'https://github.com/RT-Thread/sdk.git'
|
|
env_url = 'https://github.com/RT-Thread/env.git'
|
|
|
|
pkg_url = os.getenv('RTT_PACKAGE_URL') or pkg_url
|
|
sdk_url = os.getenv('RTT_SDK_URL') or sdk_url
|
|
env_url = os.getenv('RTT_ENV_URL') or env_url
|
|
|
|
# make .env and other directories
|
|
env_dir = os.path.join(home_dir, '.env')
|
|
if not os.path.exists(env_dir):
|
|
os.mkdir(env_dir)
|
|
os.mkdir(os.path.join(env_dir, 'local_pkgs'))
|
|
os.mkdir(os.path.join(env_dir, 'packages'))
|
|
os.mkdir(os.path.join(env_dir, 'tools'))
|
|
kconfig = open(os.path.join(env_dir, 'packages', 'Kconfig'), 'w')
|
|
kconfig.close()
|
|
|
|
# git clone packages
|
|
if not os.path.exists(os.path.join(env_dir, 'packages', 'packages')):
|
|
try:
|
|
ret = os.system('git clone %s %s' % (pkg_url, os.path.join(env_dir, 'packages', 'packages')))
|
|
if ret != 0:
|
|
shutil.rmtree(os.path.join(env_dir, 'packages', 'packages'))
|
|
print(
|
|
"********************************************************************************\n"
|
|
"* Warnning:\n"
|
|
"* Run command error for \"git clone https://github.com/RT-Thread/packages.git\".\n"
|
|
"* This error may have been caused by not found a git tool or network error.\n"
|
|
"* If the git tool is not installed, install the git tool first.\n"
|
|
"* If the git utility is installed, check whether the git command is added to \n"
|
|
"* the system PATH.\n"
|
|
"* This error may cause the RT-Thread packages to not work properly.\n"
|
|
"********************************************************************************\n"
|
|
)
|
|
help_info()
|
|
else:
|
|
kconfig = open(os.path.join(env_dir, 'packages', 'Kconfig'), 'w')
|
|
kconfig.write('source "$PKGS_DIR/packages/Kconfig"')
|
|
kconfig.close()
|
|
except:
|
|
print(
|
|
"**********************************************************************************\n"
|
|
"* Warnning:\n"
|
|
"* Run command error for \"git clone https://github.com/RT-Thread/packages.git\". \n"
|
|
"* This error may have been caused by not found a git tool or git tool not in \n"
|
|
"* the system PATH. \n"
|
|
"* This error may cause the RT-Thread packages to not work properly. \n"
|
|
"**********************************************************************************\n"
|
|
)
|
|
help_info()
|
|
|
|
# git clone env scripts
|
|
if not os.path.exists(os.path.join(env_dir, 'tools', 'scripts')):
|
|
try:
|
|
ret = os.system('git clone %s %s' % (env_url, os.path.join(env_dir, 'tools', 'scripts')))
|
|
if ret != 0:
|
|
shutil.rmtree(os.path.join(env_dir, 'tools', 'scripts'))
|
|
print(
|
|
"********************************************************************************\n"
|
|
"* Warnning:\n"
|
|
"* Run command error for \"git clone https://github.com/RT-Thread/env.git\".\n"
|
|
"* This error may have been caused by not found a git tool or network error.\n"
|
|
"* If the git tool is not installed, install the git tool first.\n"
|
|
"* If the git utility is installed, check whether the git command is added \n"
|
|
"* to the system PATH.\n"
|
|
"* This error may cause script tools to fail to work properly.\n"
|
|
"********************************************************************************\n"
|
|
)
|
|
help_info()
|
|
except:
|
|
print(
|
|
"********************************************************************************\n"
|
|
"* Warnning:\n"
|
|
"* Run command error for \"git clone https://github.com/RT-Thread/env.git\". \n"
|
|
"* This error may have been caused by not found a git tool or git tool not in \n"
|
|
"* the system PATH. \n"
|
|
"* This error may cause script tools to fail to work properly. \n"
|
|
"********************************************************************************\n"
|
|
)
|
|
help_info()
|
|
|
|
# git clone sdk
|
|
if not os.path.exists(os.path.join(env_dir, 'packages', 'sdk')):
|
|
try:
|
|
ret = os.system('git clone %s %s' % (sdk_url, os.path.join(env_dir, 'packages', 'sdk')))
|
|
if ret != 0:
|
|
shutil.rmtree(os.path.join(env_dir, 'packages', 'sdk'))
|
|
print(
|
|
"********************************************************************************\n"
|
|
"* Warnning:\n"
|
|
"* Run command error for \"git clone https://github.com/RT-Thread/sdk.git\".\n"
|
|
"* This error may have been caused by not found a git tool or network error.\n"
|
|
"* If the git tool is not installed, install the git tool first.\n"
|
|
"* If the git utility is installed, check whether the git command is added \n"
|
|
"* to the system PATH.\n"
|
|
"* This error may cause the RT-Thread SDK to not work properly.\n"
|
|
"********************************************************************************\n"
|
|
)
|
|
help_info()
|
|
except:
|
|
print(
|
|
"********************************************************************************\n"
|
|
"* Warnning:\n"
|
|
"* Run command error for \"https://github.com/RT-Thread/sdk.git\".\n"
|
|
"* This error may have been caused by not found a git tool or git tool not in \n"
|
|
"* the system PATH. \n"
|
|
"* This error may cause the RT-Thread SDK to not work properly. \n"
|
|
"********************************************************************************\n"
|
|
)
|
|
help_info()
|
|
|
|
# try to create an empty .config file
|
|
if not os.path.exists(os.path.join(env_dir, 'tools', '.config')):
|
|
kconfig = open(os.path.join(env_dir, 'tools', '.config'), 'w')
|
|
kconfig.close()
|
|
|
|
# copy env.sh or env.ps1, Kconfig
|
|
shutil.copy(os.path.join(env_dir, 'tools', 'scripts', 'Kconfig'), os.path.join(home_dir, '.env', 'tools'))
|
|
if sys.platform != 'win32':
|
|
shutil.copy(os.path.join(env_dir, 'tools', 'scripts', 'env.sh'), os.path.join(home_dir, '.env', 'env.sh'))
|
|
else:
|
|
shutil.copy(os.path.join(env_dir, 'tools', 'scripts', 'env.ps1'), os.path.join(home_dir, '.env', 'env.ps1'))
|
|
# unzip kconfig-mconf.zip
|
|
# zip_file = os.path.join(env_dir, 'tools', 'scripts', 'kconfig-mconf.zip')
|
|
# if os.path.exists(zip_file):
|
|
# zip_file_dir = os.path.join(env_dir, 'tools', 'bin')
|
|
# if os.path.exists(zip_file_dir):
|
|
# shutil.rmtree(zip_file_dir)
|
|
# zip_file_obj = zipfile.ZipFile(zip_file, 'r')
|
|
# for file in zip_file_obj.namelist():
|
|
# zip_file_obj.extract(file, zip_file_dir)
|
|
# zip_file_obj.close()
|
|
|
|
|
|
def is_pkg_special_config(config_str):
|
|
'''judge if it's CONFIG_PKG_XX_PATH or CONFIG_PKG_XX_VER'''
|
|
|
|
if type(config_str) == type('a'):
|
|
if config_str.startswith("PKG_") and (config_str.endswith('_PATH') or config_str.endswith('_VER')):
|
|
return True
|
|
return False
|
|
|
|
|
|
def mk_rtconfig(filename):
|
|
try:
|
|
config = open(filename, 'r')
|
|
except:
|
|
print('open config:%s failed' % filename)
|
|
return
|
|
|
|
rtconfig = open('rtconfig.h', 'w')
|
|
rtconfig.write('#ifndef RT_CONFIG_H__\n')
|
|
rtconfig.write('#define RT_CONFIG_H__\n\n')
|
|
|
|
empty_line = 1
|
|
|
|
for line in config:
|
|
line = line.lstrip(' ').replace('\n', '').replace('\r', '')
|
|
|
|
if len(line) == 0:
|
|
continue
|
|
|
|
if line[0] == '#':
|
|
if len(line) == 1:
|
|
if empty_line:
|
|
continue
|
|
|
|
rtconfig.write('\n')
|
|
empty_line = 1
|
|
continue
|
|
|
|
if line.startswith('# CONFIG_'):
|
|
line = ' ' + line[9:]
|
|
else:
|
|
line = line[1:]
|
|
rtconfig.write('/*%s */\n' % line)
|
|
|
|
empty_line = 0
|
|
else:
|
|
empty_line = 0
|
|
setting = line.split('=')
|
|
if len(setting) >= 2:
|
|
if setting[0].startswith('CONFIG_'):
|
|
setting[0] = setting[0][7:]
|
|
|
|
# remove CONFIG_PKG_XX_PATH or CONFIG_PKG_XX_VER
|
|
if is_pkg_special_config(setting[0]):
|
|
continue
|
|
|
|
if setting[1] == 'y':
|
|
rtconfig.write('#define %s\n' % setting[0])
|
|
else:
|
|
rtconfig.write('#define %s %s\n' % (setting[0], re.findall(r"^.*?=(.*)$", line)[0]))
|
|
|
|
if os.path.isfile('rtconfig_project.h'):
|
|
rtconfig.write('#include "rtconfig_project.h"\n')
|
|
|
|
rtconfig.write('\n')
|
|
rtconfig.write('#endif\n')
|
|
rtconfig.close()
|
|
|
|
|
|
def get_file_md5(file):
|
|
MD5 = hashlib.new('md5')
|
|
with open(file, 'r') as fp:
|
|
MD5.update(fp.read().encode('utf8'))
|
|
fp_md5 = MD5.hexdigest()
|
|
return fp_md5
|
|
|
|
|
|
# Exclude utestcases
|
|
def exclude_utestcases(RTT_ROOT):
|
|
if os.path.isfile(os.path.join(RTT_ROOT, 'Kconfig.utestcases')):
|
|
return
|
|
|
|
if not os.path.isfile(os.path.join(RTT_ROOT, 'Kconfig')):
|
|
return
|
|
|
|
with open(os.path.join(RTT_ROOT, 'Kconfig'), 'r') as f:
|
|
data = f.readlines()
|
|
with open(os.path.join(RTT_ROOT, 'Kconfig'), 'w') as f:
|
|
for line in data:
|
|
if line.find('Kconfig.utestcases') == -1:
|
|
f.write(line)
|
|
|
|
|
|
# fix locale for kconfiglib
|
|
def kconfiglib_fix_locale():
|
|
import os
|
|
import locale
|
|
|
|
# Get the list of supported locales
|
|
supported_locales = set(locale.locale_alias.keys())
|
|
|
|
# Check if LANG is set and its value is not in the supported locales
|
|
if 'LANG' in os.environ and os.environ['LANG'] not in supported_locales:
|
|
os.environ['LANG'] = 'C'
|
|
|
|
|
|
def kconfiglib_check_installed():
|
|
try:
|
|
import kconfiglib
|
|
except ImportError as e:
|
|
print("\033[1;31m**ERROR**: Failed to import kconfiglib, " + str(e))
|
|
print("")
|
|
print("You may need to install it using:")
|
|
print(" pip install kconfiglib\033[0m")
|
|
print("")
|
|
sys.exit(1)
|
|
|
|
# set PKGS_DIR envrionment
|
|
pkg_dir = GetPkgPath()
|
|
if os.path.exists(pkg_dir):
|
|
os.environ["PKGS_DIR"] = pkg_dir
|
|
elif sys.platform != 'win32':
|
|
touch_env()
|
|
os.environ["PKGS_DIR"] = GetPkgPath()
|
|
else:
|
|
print("\033[1;33m**WARNING**: PKGS_DIR not found, please install ENV tools\033[0m")
|
|
|
|
|
|
# menuconfig for Linux and Windows
|
|
def menuconfig(RTT_ROOT):
|
|
kconfiglib_check_installed()
|
|
|
|
import menuconfig
|
|
|
|
# Exclude utestcases
|
|
exclude_utestcases(RTT_ROOT)
|
|
|
|
fn = '.config'
|
|
fn_old = '.config.old'
|
|
|
|
sys.argv = ['menuconfig', 'Kconfig']
|
|
|
|
# fix vscode console
|
|
kconfiglib_fix_locale()
|
|
|
|
menuconfig._main()
|
|
|
|
if os.path.isfile(fn):
|
|
if os.path.isfile(fn_old):
|
|
diff_eq = operator.eq(get_file_md5(fn), get_file_md5(fn_old))
|
|
else:
|
|
diff_eq = False
|
|
else:
|
|
sys.exit(-1)
|
|
|
|
# make rtconfig.h
|
|
if diff_eq == False:
|
|
shutil.copyfile(fn, fn_old)
|
|
mk_rtconfig(fn)
|
|
|
|
|
|
# guiconfig for windows and linux
|
|
def guiconfig(RTT_ROOT):
|
|
kconfiglib_check_installed()
|
|
|
|
import guiconfig
|
|
|
|
# Exclude utestcases
|
|
exclude_utestcases(RTT_ROOT)
|
|
|
|
fn = '.config'
|
|
fn_old = '.config.old'
|
|
|
|
sys.argv = ['guiconfig', 'Kconfig']
|
|
guiconfig._main()
|
|
|
|
if os.path.isfile(fn):
|
|
if os.path.isfile(fn_old):
|
|
diff_eq = operator.eq(get_file_md5(fn), get_file_md5(fn_old))
|
|
else:
|
|
diff_eq = False
|
|
else:
|
|
sys.exit(-1)
|
|
|
|
# make rtconfig.h
|
|
if diff_eq == False:
|
|
shutil.copyfile(fn, fn_old)
|
|
mk_rtconfig(fn)
|
|
|
|
|
|
# defconfig for windows and linux
|
|
def defconfig(RTT_ROOT):
|
|
kconfiglib_check_installed()
|
|
|
|
import defconfig
|
|
|
|
# Exclude utestcases
|
|
exclude_utestcases(RTT_ROOT)
|
|
|
|
fn = '.config'
|
|
|
|
sys.argv = ['defconfig', '--kconfig', 'Kconfig', '.config']
|
|
defconfig.main()
|
|
|
|
# silent mode, force to make rtconfig.h
|
|
mk_rtconfig(fn)
|
|
|
|
|
|
def genconfig():
|
|
from SCons.Script import SCons
|
|
|
|
PreProcessor = SCons.cpp.PreProcessor()
|
|
|
|
try:
|
|
f = open('rtconfig.h', 'r')
|
|
contents = f.read()
|
|
f.close()
|
|
except:
|
|
print("Open rtconfig.h file failed.")
|
|
|
|
PreProcessor.process_contents(contents)
|
|
options = PreProcessor.cpp_namespace
|
|
|
|
try:
|
|
f = open('.config', 'w')
|
|
for opt, value in options.items():
|
|
if type(value) == type(1):
|
|
f.write("CONFIG_%s=%d\n" % (opt, value))
|
|
|
|
if type(value) == type('') and value == '':
|
|
f.write("CONFIG_%s=y\n" % opt)
|
|
elif type(value) == type('str'):
|
|
f.write("CONFIG_%s=%s\n" % (opt, value))
|
|
|
|
print("Generate .config done!")
|
|
f.close()
|
|
except:
|
|
print("Generate .config file failed.")
|