Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[tools] generate workspace by compile_commands.json #9781

Merged
merged 1 commit into from
Dec 13, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 171 additions & 1 deletion tools/vsc.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
# Date Author Notes
# 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
"""
Utils for VSCode
"""
Expand All @@ -32,6 +32,169 @@
import rtconfig

from utils import _make_path_relative
def find_first_node_with_two_children(tree):
for key, subtree in tree.items():
if len(subtree) >= 2:
return key, subtree
result = find_first_node_with_two_children(subtree)
if result:
return result
return None, None


def filt_tree(tree):
key, subtree = find_first_node_with_two_children(tree)
if key:
return {key: subtree}
return {}


def add_path_to_tree(tree, path):
parts = path.split(os.sep)
current_level = tree
for part in parts:
if part not in current_level:
current_level[part] = {}
current_level = current_level[part]


def build_tree(paths):
tree = {}
current_working_directory = os.getcwd()
current_folder_name = os.path.basename(current_working_directory)
#过滤异常和不存在的路径
relative_dirs = []
for path in paths:
normalized_path = os.path.normpath(path)
try:
rel_path = os.path.relpath(normalized_path, start=current_working_directory)
add_path_to_tree(tree, normalized_path)
except ValueError:
print(f"Remove unexcpect dir:{path}")

return tree

def print_tree(tree, indent=''):
for key, subtree in sorted(tree.items()):
print(indent + key)
print_tree(subtree, indent + ' ')


def extract_source_dirs(compile_commands):
source_dirs = set()

for entry in compile_commands:
file_path = os.path.abspath(entry['file'])

if file_path.endswith('.c'):
dir_path = os.path.dirname(file_path)
source_dirs.add(dir_path)
# command 或者arguments
command = entry.get('command') or entry.get('arguments')

if isinstance(command, str):
parts = command.split()
else:
parts = command
# 读取-I或者/I
for i, part in enumerate(parts):
if part.startswith('-I'):
include_dir = part[2:] if len(part) > 2 else parts[i + 1]
source_dirs.add(os.path.abspath(include_dir))
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)


def is_path_in_tree(path, tree):
parts = path.split(os.sep)
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:
for i in range(index_start, length):
current_level = current_level[parts[i]]
return True
except KeyError:
return False


def generate_code_workspace_file(source_dirs,command_json_path,root_path):
current_working_directory = os.getcwd()
current_folder_name = os.path.basename(current_working_directory)

relative_dirs = []
for dir_path in source_dirs:
try:
rel_path = os.path.relpath(dir_path, root_path)
relative_dirs.append(rel_path)
except ValueError:
continue

root_rel_path = os.path.relpath(root_path, current_working_directory)
command_json_path = os.path.relpath(current_working_directory, root_path) + os.sep
workspace_data = {
"folders": [
{
"path": f"{root_rel_path}"
}
],
"settings": {
"clangd.arguments": [
f"--compile-commands-dir={command_json_path}",
"--header-insertion=never"
],
"files.exclude": {dir.replace('\\','/'): True for dir in sorted(relative_dirs)}
}
}
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)

print(f'Workspace file {workspace_filename} created.')

def command_json_to_workspace(root_path,command_json_path):

with open('compile_commands.json', 'r') as f:
compile_commands = json.load(f)

source_dirs = extract_source_dirs(compile_commands)
tree = build_tree(source_dirs)
#print_tree(tree)
filtered_tree = filt_tree(tree)
print("Filtered Directory Tree:")
#print_tree(filtered_tree)

# 打印filtered_tree的root节点的相对路径
root_key = list(filtered_tree.keys())[0]
print(f"Root node relative path: {root_key}")

# 初始化exclude_fold集合
exclude_fold = set()

# os.chdir(root_path)
# 轮询root文件夹下面的每一个文件夹和子文件夹
for root, dirs, files in os.walk(root_path):
# 检查当前root是否在filtered_tree中
if not is_path_in_tree(root, filtered_tree):
exclude_fold.add(root)
dirs[:] = [] # 不往下轮询子文件夹
continue
for dir in dirs:
dir_path = os.path.join(root, dir)
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):
temp_dict = set([str(item) for item in data])
Expand Down Expand Up @@ -83,6 +246,13 @@ def GenerateCFiles(env):
vsc_file.close()

"""
Generate vscode.code-workspace files by compile_commands.json
"""
if os.path.exists('compile_commands.json'):

command_json_to_workspace(env['RTT_ROOT'],'compile_commands.json')
return
"""
Generate vscode.code-workspace files
"""
vsc_space_file = open('vscode.code-workspace', 'w')
Expand Down
Loading