bsp_detail.py 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. #
  2. # Copyright (c) 2024, RT-Thread Development Team
  3. #
  4. # SPDX-License-Identifier: Apache-2.0
  5. #
  6. # Change Logs:
  7. # Date Author Notes
  8. # 2024-08-24 supperthomas the first version
  9. #
  10. # 这个文件会根据bsp中的信息生成对应的bsp_detail.yml文件,这个文件会包含bsp中的一些信息,比如是否有Kconfig文件,是否有template.uvprojx文件等等
  11. # 根据生成的bsp_detail.yml文件,会生成一个toolchain_bsp.yml文件,这个文件会包含所有的gcc编译器的信息,以及对应的bsp文件夹
  12. import os
  13. import pandas as pd
  14. import yaml
  15. from datetime import datetime
  16. import subprocess
  17. #pip install pandas
  18. #pip install tabulate
  19. #pip install pyyaml
  20. # 添加每个工具链的下载地址
  21. download_urls = {
  22. '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',
  23. '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',
  24. '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',
  25. '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',
  26. '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',
  27. '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',
  28. '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',
  29. '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',
  30. # 添加其他工具链的下载地址
  31. }
  32. # 产生toolchain.yml文件
  33. def generate_toolchain_yaml(input_file, output_file, header_comment):
  34. with open(input_file, 'r', encoding='utf-8') as file:
  35. data = yaml.safe_load(file)
  36. toolchain_data = {}
  37. for folder, details in data.items():
  38. gcc = details.get('gcc')
  39. if gcc:
  40. if gcc not in toolchain_data:
  41. toolchain_data[gcc] = {'bsp': []}
  42. toolchain_data[gcc]['bsp'].append(folder)
  43. # 添加每个工具链的个数
  44. for gcc, details in toolchain_data.items():
  45. details['count'] = len(details['bsp'])
  46. download_url = download_urls.get(gcc)
  47. if download_url:
  48. details['download_url'] = download_url
  49. with open(output_file, 'w', encoding='utf-8') as file:
  50. file.write(f"# {header_comment}\n")
  51. yaml.dump(toolchain_data, file, default_flow_style=False, allow_unicode=True)
  52. # 这个函数通过检查文件是否存在来检查bsp的支持情况
  53. def check_files(root_dir, file_list):
  54. data = []
  55. folders_checked = set()
  56. for projects in sconstruct_paths:
  57. found_arch = False # Flag to track if ARCH has been found
  58. found_cpu = False # Flag to track if ARCH has been found
  59. if projects not in folders_checked:
  60. #file_dict = {file: True if os.path.isfile(os.path.join(projects, file)) else '' for file in file_list}
  61. file_dict = {}
  62. for file in file_list:
  63. file_exists = os.path.isfile(os.path.join(projects, file))
  64. if file == 'template.uvprojx':
  65. file_dict['mdk5'] = True if file_exists else False
  66. elif file == 'template.ewp':
  67. file_dict['iar'] = True if file_exists else False
  68. elif file == 'template.uvproj':
  69. file_dict['mdk4'] = True if file_exists else False
  70. elif file == 'template.Uv2':
  71. file_dict['mdk3'] = True if file_exists else False
  72. elif file == 'Kconfig':
  73. file_dict['menuconfig'] = True if file_exists else False
  74. else:
  75. file_dict[file] = True if file_exists else False
  76. # 提取 rtconfig.py 中的 PREFIX 信息
  77. rtconfig_path = os.path.join(projects, 'rtconfig.py')
  78. if os.path.isfile(rtconfig_path):
  79. print(f"Reading {rtconfig_path}")
  80. with open(rtconfig_path, 'r') as f:
  81. for line in f:
  82. if not found_arch and line.strip().startswith('ARCH'):
  83. arch_value = line.split('=')[1].strip().strip("'\"")
  84. file_dict['arch'] = f"{arch_value}"
  85. print(f"Found ARCH: {arch_value} in {rtconfig_path}")
  86. found_arch = True # Set the flag to True
  87. # 解析CPU属性
  88. if not found_cpu and line.strip().startswith('CPU'):
  89. cpu_value = line.split('=')[1].strip().strip("'\"")
  90. file_dict['cpu'] = f"{cpu_value}"
  91. print(f"Found CPU: {cpu_value} in {rtconfig_path}")
  92. found_cpu = True
  93. if line.strip().startswith('PREFIX'):
  94. prefix_value = line.split('=')[1].strip().strip("'\"")
  95. # 只提取实际的编译器前缀
  96. if 'os.getenv' in prefix_value:
  97. prefix_value = prefix_value.split('or')[-1].strip().strip("'\"")
  98. file_dict['gcc'] = f"{prefix_value}gcc"
  99. print(f"Found PREFIX: {prefix_value} in {rtconfig_path}")
  100. break
  101. else:
  102. print(f"No PREFIX found in {rtconfig_path}")
  103. # 去掉路径中的 '/workspaces/rt-thread/bsp/' 部分
  104. projects2 = projects.replace(root_dir + '/', '')
  105. file_dict['Folder'] = projects2
  106. data.append(file_dict)
  107. #data.append({'Folder': projects2, **file_dict})
  108. folders_checked.add(projects)
  109. df = pd.DataFrame(data)
  110. return df
  111. def find_sconstruct_paths(project_dir, exclude_paths):
  112. sconstruct_paths = []
  113. for root, dirs, files in os.walk(project_dir):
  114. if all(exclude_path not in root for exclude_path in exclude_paths):
  115. if 'SConstruct' in files:
  116. sconstruct_paths.append(root)
  117. return sconstruct_paths
  118. def output_to_markdown(df, output_file):
  119. with open(output_file, 'w', encoding='utf-8') as file:
  120. file.write(df.to_markdown(index=False))
  121. def output_to_yaml(dataframe, output_file, header_comment):
  122. data = dataframe.to_dict(orient='records')
  123. yaml_data = {}
  124. for item in data:
  125. folder = item.pop('Folder')
  126. filtered_item = {k: v for k, v in item.items() if v is True or isinstance(v, str)}
  127. yaml_data[folder] = filtered_item
  128. with open(output_file, 'w', encoding='utf-8') as file:
  129. file.write(f"# {header_comment}\n")
  130. yaml.dump(yaml_data, file, default_flow_style=False, allow_unicode=True)
  131. # Find the rt-thread root directory
  132. rtt_root = os.getcwd()
  133. while not os.path.exists(os.path.join(rtt_root, 'LICENSE')):
  134. rtt_root = os.path.dirname(rtt_root)
  135. bsp_root = os.path.join(rtt_root, 'bsp')
  136. exclude_paths = ['templates', 'doc']
  137. files_to_check = ['README.md','rtconfig.h', '.config','Kconfig', 'template.uvprojx','template.ewp', 'README.md', 'README_ZH.md', 'template.Uv2','template.uvproj']
  138. sconstruct_paths = find_sconstruct_paths(bsp_root, exclude_paths)
  139. result_table = check_files(bsp_root, files_to_check)
  140. print(result_table)
  141. output_file = 'output.md'
  142. output_to_markdown(result_table, output_file)
  143. # 将 output.yml 和 toolchain.yml 文件保存到 bsp 目录下
  144. # 获取今天的日期
  145. today_date = datetime.today().strftime('%Y-%m-%d')
  146. # 获取当前年份
  147. current_year = datetime.today().year
  148. def get_git_user_name():
  149. try:
  150. result = subprocess.run(['git', 'config', 'user.name'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
  151. if result.returncode == 0:
  152. return result.stdout.strip()
  153. else:
  154. return "Unknown Author"
  155. except Exception as e:
  156. return "Unknown Author"
  157. # 获取 Git 用户名
  158. author_name = get_git_user_name()
  159. # 头部注释
  160. header_comment = f"""
  161. # Copyright (c) {current_year}, RT-Thread Development Team
  162. #
  163. # SPDX-License-Identifier: Apache-2.0
  164. #
  165. # Change Logs:
  166. # Date Author Notes
  167. # {today_date} {author_name} the first version
  168. #
  169. """
  170. # 将 output.yml 和 toolchain.yml 文件保存到 tools/ci 目录下
  171. ci_dir = os.path.join(rtt_root, 'tools', 'ci')
  172. os.makedirs(ci_dir, exist_ok=True)
  173. bsp_detail_file = os.path.join(ci_dir, 'bsp_detail.yml')
  174. output_to_yaml(result_table, bsp_detail_file, header_comment)
  175. toolchain_output_file = os.path.join(ci_dir, 'toolchain_bsp.yml')
  176. generate_toolchain_yaml(bsp_detail_file, toolchain_output_file, header_comment)