bsp_detail.py 8.1 KB

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