From b91a131654c653d729bea6ad19cb8f556d24e866 Mon Sep 17 00:00:00 2001 From: bernard Date: Mon, 30 Jun 2025 06:17:18 +0800 Subject: [PATCH 1/3] [tools] add vsc_workspace target in scons. --- tools/building.py | 7 +++++ tools/options.py | 2 +- tools/targets/vsc.py | 64 +++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 68 insertions(+), 5 deletions(-) diff --git a/tools/building.py b/tools/building.py index 12689345e7e..635eb7875e4 100644 --- a/tools/building.py +++ b/tools/building.py @@ -58,6 +58,8 @@ def PrepareBuilding(env, root_directory, has_libcpu=False, remove_components = [ AddOptions() Env = env + # export the default environment + Export('env') # prepare logging and set log logging.basicConfig(level=logging.INFO, format="%(message)s") @@ -89,6 +91,7 @@ def PrepareBuilding(env, root_directory, has_libcpu=False, remove_components = [ 'vs':('msvc', 'cl'), 'vs2012':('msvc', 'cl'), 'vsc' : ('gcc', 'gcc'), + 'vsc_workspace':('gcc', 'gcc'), 'cb':('keil', 'armcc'), 'ua':('gcc', 'gcc'), 'cdk':('gcc', 'gcc'), @@ -848,6 +851,10 @@ def GenTargetProject(program = None): from vscpyocd import GenerateVSCodePyocdConfig GenerateVSCodePyocdConfig(GetOption('cmsispack')) + if GetOption('target') == 'vsc_workspace': + from targets.vsc import GenerateVSCodeWorkspace + GenerateVSCodeWorkspace(Env) + if GetOption('target') == 'cdk': from targets.cdk import CDKProject CDKProject(GetOption('project-name') + '.cdkproj', Projects) diff --git a/tools/options.py b/tools/options.py index 2a19e1ac0eb..38bdb2f81bb 100644 --- a/tools/options.py +++ b/tools/options.py @@ -73,7 +73,7 @@ def AddOptions(): AddOption('--target', dest = 'target', type = 'string', - help = 'set target project: mdk/mdk4/mdk5/iar/vs/vsc/ua/cdk/ses/makefile/eclipse/codelite/cmake') + help = 'set target project: mdk/mdk4/mdk5/iar/vs/vsc/ua/cdk/ses/makefile/eclipse/codelite/cmake/vsc_workspace') AddOption('--cmsispack', dest = 'cmsispack', type = 'string', diff --git a/tools/targets/vsc.py b/tools/targets/vsc.py index c005bcf053f..31718ba944c 100644 --- a/tools/targets/vsc.py +++ b/tools/targets/vsc.py @@ -30,6 +30,7 @@ import json import utils import rtconfig +from SCons.Script import * from utils import _make_path_relative def find_first_node_with_two_children(tree): @@ -216,14 +217,14 @@ def GenerateCFiles(env): cc = os.path.abspath(cc).replace('\\', '/') config_obj = {} - config_obj['name'] = 'rt-thread' + config_obj['name'] = 'Linux' config_obj['defines'] = info['CPPDEFINES'] - intelliSenseMode = 'gcc-arm' + intelliSenseMode = 'linux-gcc-arm' if cc.find('aarch64') != -1: - intelliSenseMode = 'gcc-arm64' + intelliSenseMode = 'linux-gcc-arm64' elif cc.find('arm') != -1: - intelliSenseMode = 'gcc-arm' + intelliSenseMode = 'linux-gcc-arm' config_obj['intelliSenseMode'] = intelliSenseMode config_obj['compilerPath'] = cc config_obj['cStandard'] = "c99" @@ -338,3 +339,58 @@ def GenerateVSCode(env): print('Done!') return + +def GenerateVSCodeWorkspace(env): + """ + Generate vscode.code files + """ + print('Update workspace files for VSCode...') + + # get the launch directory + cwd = GetLaunchDir() + + # check if .vscode folder exists, if not, create it + if not os.path.exists(os.path.join(cwd, '.vscode')): + os.mkdir(os.path.join(cwd, '.vscode')) + + vsc_file = open(os.path.join(cwd, '.vscode/c_cpp_properties.json'), 'w') + if vsc_file: + info = utils.ProjectInfo(env) + + cc = os.path.join(rtconfig.EXEC_PATH, rtconfig.CC) + cc = os.path.abspath(cc).replace('\\', '/') + + config_obj = {} + config_obj['name'] = 'Linux' + config_obj['defines'] = info['CPPDEFINES'] + + intelliSenseMode = 'linux-gcc-arm' + if cc.find('aarch64') != -1: + intelliSenseMode = 'linux-gcc-arm64' + elif cc.find('arm') != -1: + intelliSenseMode = 'linux-gcc-arm' + config_obj['intelliSenseMode'] = intelliSenseMode + config_obj['compilerPath'] = cc + config_obj['cStandard'] = "c99" + config_obj['cppStandard'] = "c++11" + + # format "a/b," to a/b. remove first quotation mark("),and remove end (",) + includePath = [] + for i in info['CPPPATH']: + if i[0] == '\"' and i[len(i) - 2:len(i)] == '\",': + includePath.append(_make_path_relative(cwd, i[1:len(i) - 2])) + else: + includePath.append(_make_path_relative(cwd, i)) + # make sort for includePath + includePath = sorted(includePath, key=lambda x: x.lower()) + config_obj['includePath'] = includePath + + json_obj = {} + json_obj['configurations'] = [config_obj] + + vsc_file.write(json.dumps(json_obj, ensure_ascii=False, indent=4)) + vsc_file.close() + + print('Done!') + + return From 4aed0e94e5cf8dc9d30949ec5fe729574f35d9bb Mon Sep 17 00:00:00 2001 From: bernard Date: Sat, 5 Jul 2025 21:07:34 +0800 Subject: [PATCH 2/3] [tools] Add workspace generation for RT-Thread root directory. --- tools/targets/vsc.py | 109 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 101 insertions(+), 8 deletions(-) diff --git a/tools/targets/vsc.py b/tools/targets/vsc.py index 31718ba944c..ccec3fe2f4e 100644 --- a/tools/targets/vsc.py +++ b/tools/targets/vsc.py @@ -22,6 +22,8 @@ # 2018-05-30 Bernard The first version # 2023-03-03 Supperthomas Add the vscode workspace config file # 2024-12-13 Supperthomas covert compile_commands.json to vscode workspace file +# 2025-07-05 Bernard Add support for generating .vscode/c_cpp_properties.json +# and .vscode/settings.json files """ Utils for VSCode """ @@ -63,7 +65,7 @@ def build_tree(paths): tree = {} current_working_directory = os.getcwd() current_folder_name = os.path.basename(current_working_directory) - #过滤异常和不存在的路径 + # Filter out invalid and non-existent paths relative_dirs = [] for path in paths: normalized_path = os.path.normpath(path) @@ -90,7 +92,7 @@ def extract_source_dirs(compile_commands): if file_path.endswith('.c'): dir_path = os.path.dirname(file_path) source_dirs.add(dir_path) - # command 或者arguments + # command or arguments command = entry.get('command') or entry.get('arguments') if isinstance(command, str): @@ -105,7 +107,7 @@ def extract_source_dirs(compile_commands): elif part.startswith('/I'): include_dir = part[2:] if len(part) > 2 else parts[i + 1] source_dirs.add(os.path.abspath(include_dir)) - #print(f"Source Directories: {source_dirs}") + return sorted(source_dirs) @@ -114,8 +116,7 @@ def is_path_in_tree(path, tree): current_level = tree found_first_node = False root_key = list(tree.keys())[0] - #print(root_key) - #print(path) + index_start = parts.index(root_key) length = len(parts) try: @@ -155,7 +156,6 @@ def generate_code_workspace_file(source_dirs,command_json_path,root_path): } } workspace_filename = f'{current_folder_name}.code-workspace' - # print(workspace_data) with open(workspace_filename, 'w') as f: json.dump(workspace_data, f, indent=4) @@ -193,8 +193,6 @@ def command_json_to_workspace(root_path,command_json_path): if not is_path_in_tree(dir_path, filtered_tree): exclude_fold.add(dir_path) - #print("Excluded Folders:") - #print(exclude_fold) generate_code_workspace_file(exclude_fold,command_json_path,root_path) def delete_repeatelist(data): @@ -340,6 +338,51 @@ def GenerateVSCode(env): return +import os + +def find_rtconfig_dirs(bsp_dir, project_dir): + """ + Search for subdirectories containing 'rtconfig.h' under 'bsp_dir' (up to 4 levels deep), excluding 'project_dir'. + + Args: + bsp_dir (str): The root directory to search (absolute path). + project_dir (str): The subdirectory to exclude from the search (absolute path). + + Returns + list: A list of absolute paths to subdirectories containing 'rtconfig.h'. + """ + + result = [] + project_dir = os.path.normpath(project_dir) + + # list the bsp_dir to add result + list = os.listdir(bsp_dir) + for item in list: + item = os.path.join(bsp_dir, item) + + # if item is a directory + if not os.path.isdir(item): + continue + + # print(item, project_dir) + if not project_dir.startswith(item): + result.append(os.path.abspath(item)) + + parent_dir = os.path.dirname(project_dir) + + if parent_dir != bsp_dir: + list = os.listdir(parent_dir) + for item in list: + item = os.path.join(parent_dir, item) + rtconfig_path = os.path.join(item, 'rtconfig.h') + if os.path.isfile(rtconfig_path): + abs_path = os.path.abspath(item) + if abs_path != project_dir: + result.append(abs_path) + + # print(result) + return result + def GenerateVSCodeWorkspace(env): """ Generate vscode.code files @@ -349,6 +392,26 @@ def GenerateVSCodeWorkspace(env): # get the launch directory cwd = GetLaunchDir() + # get .vscode/workspace.json file + workspace_file = os.path.join(cwd, '.vscode', 'workspace.json') + if not os.path.exists(workspace_file): + print('Workspace file not found, skip generating.') + return + + try: + # read the workspace file + with open(workspace_file, 'r') as f: + workspace_data = json.load(f) + + # get the bsp directories from the workspace data, bsps/folder + bsp_dir = os.path.join(cwd, workspace_data.get('bsps', {}).get('folder', '')) + if not bsp_dir: + print('No BSP directories found in the workspace file, skip generating.') + return + except Exception as e: + print('Error reading workspace file, skip generating.') + return + # check if .vscode folder exists, if not, create it if not os.path.exists(os.path.join(cwd, '.vscode')): os.mkdir(os.path.join(cwd, '.vscode')) @@ -391,6 +454,36 @@ def GenerateVSCodeWorkspace(env): vsc_file.write(json.dumps(json_obj, ensure_ascii=False, indent=4)) vsc_file.close() + # generate .vscode/settings.json + vsc_settings = {} + settings_path = os.path.join(cwd, '.vscode/settings.json') + if os.path.exists(settings_path): + with open(settings_path, 'r') as f: + # read the existing settings file and load to vsc_settings + vsc_settings = json.load(f) + + vsc_file = open(settings_path, 'w') + if vsc_file: + vsc_settings['files.exclude'] = { + "**/__pycache__": True, + "tools/kconfig-frontends": True, + } + + result = find_rtconfig_dirs(bsp_dir, os.getcwd()) + if result: + # sort the result + result = sorted(result, key=lambda x: x.lower()) + for item in result: + # make the path relative to the current working directory + rel_path = os.path.relpath(item, cwd) + # add the path to files.exclude + vsc_settings['files.exclude'][rel_path] = True + + vsc_settings['search.exclude'] = vsc_settings['files.exclude'] + # write the settings to the file + vsc_file.write(json.dumps(vsc_settings, ensure_ascii=False, indent=4)) + vsc_file.close() + print('Done!') return From fe7a67ddda5b5d357815d850cbd9c73f733805b3 Mon Sep 17 00:00:00 2001 From: bernard Date: Sun, 6 Jul 2025 22:52:47 +0800 Subject: [PATCH 3/3] [tools] Optimize the file opening method. --- tools/targets/vsc.py | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/tools/targets/vsc.py b/tools/targets/vsc.py index ccec3fe2f4e..b4de67dcfb1 100644 --- a/tools/targets/vsc.py +++ b/tools/targets/vsc.py @@ -32,7 +32,7 @@ import json import utils import rtconfig -from SCons.Script import * +from SCons.Script import GetLaunchDir from utils import _make_path_relative def find_first_node_with_two_children(tree): @@ -82,7 +82,6 @@ def print_tree(tree, indent=''): print(indent + key) print_tree(subtree, indent + ' ') - def extract_source_dirs(compile_commands): source_dirs = set() @@ -207,8 +206,7 @@ def GenerateCFiles(env): if not os.path.exists('.vscode'): os.mkdir('.vscode') - vsc_file = open('.vscode/c_cpp_properties.json', 'w') - if vsc_file: + with open('.vscode/c_cpp_properties.json', 'w') as vsc_file: info = utils.ProjectInfo(env) cc = os.path.join(rtconfig.EXEC_PATH, rtconfig.CC) @@ -242,7 +240,6 @@ def GenerateCFiles(env): json_obj['configurations'] = [config_obj] vsc_file.write(json.dumps(json_obj, ensure_ascii=False, indent=4)) - vsc_file.close() """ Generate vscode.code-workspace files by build/compile_commands.json @@ -254,8 +251,7 @@ def GenerateCFiles(env): """ Generate vscode.code-workspace files """ - vsc_space_file = open('vscode.code-workspace', 'w') - if vsc_space_file: + with open('vscode.code-workspace', 'w') as vsc_space_file: info = utils.ProjectInfo(env) path_list = [] for i in info['CPPPATH']: @@ -274,7 +270,6 @@ def GenerateCFiles(env): json_obj = {} path_list = delete_repeatelist(path_list) path_list = sorted(path_list, key=lambda x: x["path"]) - target_path_list = [] for path in path_list: if path['path'] != '.': normalized_path = path['path'].replace('\\', os.path.sep) @@ -289,7 +284,7 @@ def GenerateCFiles(env): ] } vsc_space_file.write(json.dumps(json_obj, ensure_ascii=False, indent=4)) - vsc_space_file.close() + return def GenerateProjectFiles(env): @@ -300,8 +295,7 @@ def GenerateProjectFiles(env): os.mkdir('.vscode') project = env['project'] - vsc_file = open('.vscode/project.json', 'w') - if vsc_file: + with open('.vscode/project.json', 'w') as vsc_file: groups = [] for group in project: if len(group['src']) > 0: @@ -325,7 +319,6 @@ def GenerateProjectFiles(env): # write groups to project.json vsc_file.write(json.dumps(json_dict, ensure_ascii=False, indent=4)) - vsc_file.close() return @@ -416,8 +409,7 @@ def GenerateVSCodeWorkspace(env): if not os.path.exists(os.path.join(cwd, '.vscode')): os.mkdir(os.path.join(cwd, '.vscode')) - vsc_file = open(os.path.join(cwd, '.vscode/c_cpp_properties.json'), 'w') - if vsc_file: + with open(os.path.join(cwd, '.vscode/c_cpp_properties.json'), 'w') as vsc_file: info = utils.ProjectInfo(env) cc = os.path.join(rtconfig.EXEC_PATH, rtconfig.CC) @@ -452,7 +444,6 @@ def GenerateVSCodeWorkspace(env): json_obj['configurations'] = [config_obj] vsc_file.write(json.dumps(json_obj, ensure_ascii=False, indent=4)) - vsc_file.close() # generate .vscode/settings.json vsc_settings = {} @@ -462,8 +453,7 @@ def GenerateVSCodeWorkspace(env): # read the existing settings file and load to vsc_settings vsc_settings = json.load(f) - vsc_file = open(settings_path, 'w') - if vsc_file: + with open(settings_path, 'w') as vsc_file: vsc_settings['files.exclude'] = { "**/__pycache__": True, "tools/kconfig-frontends": True, @@ -482,7 +472,6 @@ def GenerateVSCodeWorkspace(env): vsc_settings['search.exclude'] = vsc_settings['files.exclude'] # write the settings to the file vsc_file.write(json.dumps(vsc_settings, ensure_ascii=False, indent=4)) - vsc_file.close() print('Done!')