# # Copyright (c) 2024, RT-Thread Development Team # # SPDX-License-Identifier: Apache-2.0 # # Change Logs: # Date Author Notes # 2024-08-24 supperthomas the first version # # 这个文件会根据bsp中的信息生成对应的bsp_detail.yml文件,这个文件会包含bsp中的一些信息,比如是否有Kconfig文件,是否有template.uvprojx文件等等 # 根据生成的bsp_detail.yml文件,会生成一个toolchain_bsp.yml文件,这个文件会包含所有的gcc编译器的信息,以及对应的bsp文件夹 import os import pandas as pd import yaml from datetime import datetime import subprocess #pip install pandas #pip install tabulate #pip install pyyaml # 添加每个工具链的下载地址 download_urls = { 'arm-none-eabi-gcc': 'https://github.com/RT-Thread/toolchains-ci/releases/download/v1.3/gcc-arm-none-eabi-10-2020-q4-major-x86_64-linux.tar.bz2', 'mips-sde-elf-gcc': 'https://github.com/RT-Thread/toolchains-ci/releases/download/v1.6/gcc-arm-10.2-2020.11-x86_64-aarch64-none-elf.tar.xz', 'riscv64-unknown-elf-gcc': 'https://github.com/RT-Thread/toolchains-ci/releases/download/v1.4/riscv64-unknown-elf-toolchain-10.2.0-2020.12.8-x86_64-linux-ubuntu14.tar.gz', 'riscv32-unknown-elf-gcc': 'https://github.com/hpmicro/riscv-gnu-toolchain/releases/download/2022.05.15/riscv32-unknown-elf-newlib-multilib_2022.05.15_linux.tar.gz', 'llvm-arm': 'https://github.com/ARM-software/LLVM-embedded-toolchain-for-Arm/releases/download/release-16.0.0/LLVMEmbeddedToolchainForArm-16.0.0-Linux-x86_64.tar.gz', 'riscv-none-embed-gcc': 'https://github.com/RT-Thread/toolchains-ci/releases/download/v1.5/xpack-riscv-none-embed-gcc-8.3.0-2.3-linux-x64.tar.gz', 'riscv32-esp-elf-gcc': 'https://github.com/espressif/crosstool-NG/releases/download/esp-2022r1-RC1/riscv32-esp-elf-gcc11_2_0-esp-2022r1-RC1-linux-amd64.tar.xz', 'clang': 'https://github.com/ARM-software/LLVM-embedded-toolchain-for-Arm/releases/download/release-16.0.0/LLVMEmbeddedToolchainForArm-16.0.0-Linux-x86_64.tar.gz', # 添加其他工具链的下载地址 } # 产生toolchain.yml文件 def generate_toolchain_yaml(input_file, output_file, header_comment): with open(input_file, 'r', encoding='utf-8') as file: data = yaml.safe_load(file) toolchain_data = {} for folder, details in data.items(): gcc = details.get('gcc') if gcc: if gcc not in toolchain_data: toolchain_data[gcc] = {'bsp': []} toolchain_data[gcc]['bsp'].append(folder) # 添加每个工具链的个数 for gcc, details in toolchain_data.items(): details['count'] = len(details['bsp']) download_url = download_urls.get(gcc) if download_url: details['download_url'] = download_url with open(output_file, 'w', encoding='utf-8') as file: file.write(f"# {header_comment}\n") yaml.dump(toolchain_data, file, default_flow_style=False, allow_unicode=True) # 这个函数通过检查文件是否存在来检查bsp的支持情况 def check_files(root_dir, file_list): data = [] folders_checked = set() for projects in sconstruct_paths: found_arch = False # Flag to track if ARCH has been found found_cpu = False # Flag to track if ARCH has been found if projects not in folders_checked: #file_dict = {file: True if os.path.isfile(os.path.join(projects, file)) else '' for file in file_list} file_dict = {} for file in file_list: file_exists = os.path.isfile(os.path.join(projects, file)) if file == 'template.uvprojx': file_dict['mdk5'] = True if file_exists else False elif file == 'template.ewp': file_dict['iar'] = True if file_exists else False elif file == 'template.uvproj': file_dict['mdk4'] = True if file_exists else False elif file == 'template.Uv2': file_dict['mdk3'] = True if file_exists else False elif file == 'Kconfig': file_dict['menuconfig'] = True if file_exists else False else: file_dict[file] = True if file_exists else False # 提取 rtconfig.py 中的 PREFIX 信息 rtconfig_path = os.path.join(projects, 'rtconfig.py') if os.path.isfile(rtconfig_path): print(f"Reading {rtconfig_path}") with open(rtconfig_path, 'r') as f: for line in f: if not found_arch and line.strip().startswith('ARCH'): arch_value = line.split('=')[1].strip().strip("'\"") file_dict['arch'] = f"{arch_value}" print(f"Found ARCH: {arch_value} in {rtconfig_path}") found_arch = True # Set the flag to True # 解析CPU属性 if not found_cpu and line.strip().startswith('CPU'): cpu_value = line.split('=')[1].strip().strip("'\"") file_dict['cpu'] = f"{cpu_value}" print(f"Found CPU: {cpu_value} in {rtconfig_path}") found_cpu = True if line.strip().startswith('PREFIX'): prefix_value = line.split('=')[1].strip().strip("'\"") # 只提取实际的编译器前缀 if 'os.getenv' in prefix_value: prefix_value = prefix_value.split('or')[-1].strip().strip("'\"") file_dict['gcc'] = f"{prefix_value}gcc" print(f"Found PREFIX: {prefix_value} in {rtconfig_path}") break else: print(f"No PREFIX found in {rtconfig_path}") # 去掉路径中的 '/workspaces/rt-thread/bsp/' 部分 projects2 = projects.replace(root_dir + '/', '') file_dict['Folder'] = projects2 data.append(file_dict) #data.append({'Folder': projects2, **file_dict}) folders_checked.add(projects) df = pd.DataFrame(data) return df def find_sconstruct_paths(project_dir, exclude_paths): sconstruct_paths = [] for root, dirs, files in os.walk(project_dir): if all(exclude_path not in root for exclude_path in exclude_paths): if 'SConstruct' in files: sconstruct_paths.append(root) return sconstruct_paths def output_to_markdown(df, output_file): with open(output_file, 'w', encoding='utf-8') as file: file.write(df.to_markdown(index=False)) def output_to_yaml(dataframe, output_file, header_comment): data = dataframe.to_dict(orient='records') yaml_data = {} for item in data: folder = item.pop('Folder') filtered_item = {k: v for k, v in item.items() if v is True or isinstance(v, str)} yaml_data[folder] = filtered_item with open(output_file, 'w', encoding='utf-8') as file: file.write(f"# {header_comment}\n") yaml.dump(yaml_data, file, default_flow_style=False, allow_unicode=True) # Find the rt-thread root directory rtt_root = os.getcwd() while not os.path.exists(os.path.join(rtt_root, 'LICENSE')): rtt_root = os.path.dirname(rtt_root) bsp_root = os.path.join(rtt_root, 'bsp') exclude_paths = ['templates', 'doc'] files_to_check = ['README.md','rtconfig.h', '.config','Kconfig', 'template.uvprojx','template.ewp', 'README.md', 'README_ZH.md', 'template.Uv2','template.uvproj'] sconstruct_paths = find_sconstruct_paths(bsp_root, exclude_paths) result_table = check_files(bsp_root, files_to_check) print(result_table) output_file = 'output.md' output_to_markdown(result_table, output_file) # 将 output.yml 和 toolchain.yml 文件保存到 bsp 目录下 # 获取今天的日期 today_date = datetime.today().strftime('%Y-%m-%d') # 获取当前年份 current_year = datetime.today().year def get_git_user_name(): try: result = subprocess.run(['git', 'config', 'user.name'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) if result.returncode == 0: return result.stdout.strip() else: return "Unknown Author" except Exception as e: return "Unknown Author" # 获取 Git 用户名 author_name = get_git_user_name() # 头部注释 header_comment = f""" # Copyright (c) {current_year}, RT-Thread Development Team # # SPDX-License-Identifier: Apache-2.0 # # Change Logs: # Date Author Notes # {today_date} {author_name} the first version # """ # 将 output.yml 和 toolchain.yml 文件保存到 tools/ci 目录下 ci_dir = os.path.join(rtt_root, 'tools', 'ci') os.makedirs(ci_dir, exist_ok=True) bsp_detail_file = os.path.join(ci_dir, 'bsp_detail.yml') output_to_yaml(result_table, bsp_detail_file, header_comment) toolchain_output_file = os.path.join(ci_dir, 'toolchain_bsp.yml') generate_toolchain_yaml(bsp_detail_file, toolchain_output_file, header_comment)