-
Notifications
You must be signed in to change notification settings - Fork 5.1k
/
Copy pathmanual_bsp_build_all.py
338 lines (295 loc) · 12.1 KB
/
manual_bsp_build_all.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
#
# Copyright (c) 2006-2024, RT-Thread Development Team
#
# SPDX-License-Identifier: Apache-2.0
#
# Change Logs:
# Date Author Notes
# 2024-07-25 supperthomas the first version
#
"""
这个脚本用来编译所有的bsp
这里的脚本是用的arm-none-eabi-gcc, 默认根据本机已经安装的gcc来编译
其他的工具链暂时不支持,其实主要根据运行的环境中支持不支持,目前只打算支持主流的
失败的bsp会存到failed_bsp.log里面
"""
import os
import sys
import shutil
import multiprocessing
from multiprocessing import Process
import yaml
#help说明
def usage():
print('%s all -- build all GCC bsp' % os.path.basename(sys.argv[0]))
print('%s clean -- clean all bsp' % os.path.basename(sys.argv[0]))
print('%s update -- update all prject files' % os.path.basename(sys.argv[0]))
def add_summary(text):
"""
add summary to github action.
"""
os.system(f'echo "{text}" >> $GITHUB_STEP_SUMMARY ;')
def run_cmd(cmd, output_info=True):
"""
这个函数用来执行命令
run command and return output and result.
"""
print('\033[1;32m' + cmd + '\033[0m ' + os.getcwd())
output_str_list = []
res = 0
if output_info:
res = os.system(cmd + " > output.txt 2>&1")
else:
res = os.system(cmd + " > /dev/null 2>output.txt")
try:
with open("output.txt", "r") as file:
output_str_list = file.readlines()
except FileNotFoundError:
with open("output.txt", "w") as file:
file.write("new file")
for line in output_str_list:
print(line, end='')
os.remove("output.txt")
return output_str_list, res
def build_bsp(bsp, scons_args=''):
"""
build bsp.
cd {rtt_root}
scons -C bsp/{bsp} --pyconfig-silent > /dev/null
cd {rtt_root}/bsp/{bsp}
pkgs --update > /dev/null
pkgs --list
cd {rtt_root}
scons -C bsp/{bsp} -j{nproc} {scons_args}
cd {rtt_root}/bsp/{bsp}
scons -c > /dev/null
rm -rf packages
"""
success = True
pwd = os.getcwd()
print('======pwd==='+ os.getcwd()+'===bsp:=='+bsp)
os.chdir(rtt_root)
#有Kconfig 说明可以执行menuconfig
if os.path.exists(f"{rtt_root}/bsp/{bsp}/Kconfig"):
os.chdir(rtt_root)
print('======pwd==='+ os.getcwd()+'===bsp:=='+bsp)
run_cmd(f'scons -C bsp/{bsp} --pyconfig-silent', output_info=True)
os.chdir(f'{rtt_root}/bsp/{bsp}')
print('======pwd222==='+ os.getcwd()+'===bsp:=='+bsp)
run_cmd('pkgs --update', output_info=True)
run_cmd('pkgs --list')
nproc = multiprocessing.cpu_count()
os.chdir(rtt_root)
cmd = f'scons -C bsp/{bsp} -j{nproc} {scons_args}'
result_log, res = run_cmd(cmd, output_info=True)
if res != 0:
# 将失败的bsp写入特定的txt文件
with open(os.path.join(rtt_root, 'failed_bsp_list.txt'), 'a') as file:
file.write(bsp + '\n')
# 打印失败的bsp的log,把它放到对应的文件名文bsp的txt文件中
with open(os.path.join(rtt_root, 'failed_bsp.log'), 'a') as file:
file.write(f'===================={bsp}====================\n')
for line in result_log:
file.write(line)
print(f"::error::build {bsp} failed")
add_summary(f"- ❌ build {bsp} failed.")
success = False
else:
# 如果没有Kconfig直接执行scons
os.chdir(f'{rtt_root}/bsp/{bsp}')
run_cmd('scons', output_info=True)
# 删除packages文件夹
pkg_dir = os.path.join(rtt_root, 'bsp', bsp, 'packages')
shutil.rmtree(pkg_dir, ignore_errors=True)
#恢复到原目录
os.chdir(pwd)
return success
#判断参数是否是2个
if len(sys.argv) != 2:
usage()
sys.exit(0)
#更新MDK等文件
def update_project_file(project_dir):
if os.path.isfile(os.path.join(project_dir, 'template.Uv2')):
print('prepare MDK3 project file on ' + project_dir)
command = ' --target=mdk -s'
os.system('scons --directory=' + project_dir + command + ' > 1.txt')
if os.path.isfile(os.path.join(project_dir, 'template.uvproj')):
print('prepare MDK4 project file on ' + project_dir)
command = ' --target=mdk4 -s'
os.system('scons --directory=' + project_dir + command + ' > 1.txt')
if os.path.isfile(os.path.join(project_dir, 'template.uvprojx')):
print('prepare MDK5 project file on ' + project_dir)
command = ' --target=mdk5 -s'
os.system('scons --directory=' + project_dir + command + ' > 1.txt')
if os.path.isfile(os.path.join(project_dir, 'template.ewp')):
print('prepare IAR project file on ' + project_dir)
command = ' --target=iar -s'
os.system('scons --directory=' + project_dir + command + ' > 1.txt')
#更新所有可以scons的文件夹文件,先执行menuconfig --silent 再执行scons --target=mdk5
#处理带有sconstruct的文件夹
def update_all_project_files(sconstruct_paths):
for projects in sconstruct_paths:
try:
# update rtconfig.h and .config
#执行menuconfig
if os.path.isfile(os.path.join(projects, 'Kconfig')):
if "win32" in sys.platform:
retval = os.getcwd()
os.chdir(projects)
os.system("menuconfig --silent")
os.chdir(retval)
else:
os.system('scons --pyconfig-silent -C {0}'.format(projects))
print('==menuconfig=======projects='+ projects)
else:
print('==no kconfig=in==!!!!!=projects='+ projects)
# update mdk, IAR etc file
update_project_file(projects)
except Exception as e:
print("error message: {}".format(e))
sys.exit(-1)
#找到带有Sconstruct的文件夹
def find_sconstruct_paths(project_dir, exclude_paths, include_paths):
sconstruct_paths = []
bsp_detail_path = os.path.join(rtt_root, 'tools', 'ci', 'bsp_detail.yml')
if os.path.exists(bsp_detail_path):
with open(bsp_detail_path, 'r') as file:
bsp_detail = yaml.safe_load(file)
for root, dirs, files in os.walk(project_dir):
if include_paths:
if any(include_path in root for include_path in include_paths) and all(exclude_path not in root for exclude_path in exclude_paths):
if 'SConstruct' in files:
bsp_name = os.path.relpath(root, bsp_root)
if bsp_name in bsp_detail and bsp_detail[bsp_name].get('gcc') == 'arm-none-eabi-gcc':
sconstruct_paths.append(root)
else:
if all(exclude_path not in root for exclude_path in exclude_paths):
if 'SConstruct' in files:
bsp_name = os.path.relpath(root, bsp_root)
if bsp_name in bsp_detail and bsp_detail[bsp_name].get('gcc') == 'arm-none-eabi-gcc':
sconstruct_paths.append(root)
return sconstruct_paths
#检查EXE命令是否存在,判断环境
def check_command_availability(cmd):
"""
Check if a command is available.
"""
cmd_path = shutil.which(cmd)
if cmd_path is not None:
#print(f"{cmd} command is available at {cmd_path}")
return True
else:
print(f"{cmd} command is not available")
return False
# 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', 'libraries', 'Libraries', 'template']
include_paths = []#['nrf5x','qemu-vexpress-a9', 'ESP32_C3','simulator']
sconstruct_paths = find_sconstruct_paths(bsp_root, exclude_paths,include_paths)
# get command options
command = ''
command_clean_flag = False
print(rtt_root)
if sys.argv[1] == 'all':
if os.path.exists(os.path.join(rtt_root, 'failed_bsp_list.txt')):
os.remove(os.path.join(rtt_root, 'failed_bsp_list.txt'))
if os.path.exists(os.path.join(rtt_root, 'failed_bsp.log')):
os.remove(os.path.join(rtt_root, 'failed_bsp.log'))
command = ' '
#更新所有的工程
print('begin to update all the bsp projects')
update_all_project_files(sconstruct_paths)
#iarbuild .\project.ewp -clean rt-thread
elif sys.argv[1] == 'clean':
command = ' -c'
command_clean_flag = True
print('begin to clean all the bsp projects')
# 执行所有其他IDE的 update 但是不编译,这个一般不会出错
elif sys.argv[1] == 'update':
print('begin to update all the bsp projects')
#更新所有的工程
update_all_project_files(sconstruct_paths)
print('finished!')
sys.exit(0)
else:
usage()
sys.exit(0)
if sconstruct_paths:
print("包含 'SConstruct' 文件的路径:")
for path in sconstruct_paths:
print(path)
else:
print("未找到包含 'SConstruct' 文件的路径")
#遍历所有的sconstruct_paths 路径中的文件夹
def bsp_scons_worker(project_dir):
print('=========project_dir===='+ project_dir)
#判断有没有SConstruct 文件,
if os.path.isfile(os.path.join(project_dir, 'SConstruct')):
print('==menuconfig=======rtt_root='+ rtt_root)
print('==project_dir=======project_dir='+ project_dir)
# 去掉 'bsp' 前面的三级目录
parts = project_dir.split(os.sep)
if 'bsp' in parts:
bsp_index = parts.index('bsp')
new_project_dir = os.sep.join(parts[bsp_index+1:])
else:
new_project_dir = project_dir
print('==project_dir=======new_project_dir='+ new_project_dir)
#开始编译bsp
build_bsp(new_project_dir)
# 发现有keil相关的,执行keil相关的命令,先检查一下UV4.exe命令有没有,然后执行UV4.exe
if check_command_availability('UV4.exe') :
"""
UV4.exe -b project.uvprojx -q -j0 -t rt-thread -o action_runner.log
ls
sleep 10
cat action_runner.log
"""
if os.path.isfile(os.path.join(project_dir, 'template.uvprojx')):
if check_command_availability('UV4.exe'):
print('Start to build keil project======')
os.chdir(f'{project_dir}')
print('clean keil project======')
run_cmd('UV4.exe -c project.uvprojx -q')
___, res = run_cmd('UV4.exe -b project.uvprojx -q -j0 -t rt-thread -o keil.log')
os.chdir(f'{rtt_root}')
else:
print('UV4.exe is not available, please check your keil installation')
if check_command_availability('iarbuild.exe') :
"""
iarbuild .\project.ewp rt-thread
"""
if os.path.isfile(os.path.join(project_dir, 'template.ewp')):
if check_command_availability('iarbuild.exe'):
print('Start to build iar project======')
os.chdir(f'{project_dir}')
___, res = run_cmd('iarbuild .\project.ewp -clean rt-thread')
if res != 0:
print('run clean failed!!')
___, res = run_cmd('iarbuild .\project.ewp rt-thread > iar.log')
if res != 0:
print('run_cmd1 failed!!')
os.chdir(f'{rtt_root}')
else:
print('iarbuild is not available, please check your iar installation')
processes = []
for project_dir in sconstruct_paths:
bsp_scons_worker(project_dir)
#p = Process(target=bsp_scons_worker, args=(project_dir,))
#p.start()
#processes.append(p)
#for p in processes:
# p.join() # 等待所有进程完成
print('finished!')
# 将failed_bsp_list.txt的内容追加到failed_bsp.log文件中
if os.path.exists(os.path.join(rtt_root, 'failed_bsp_list.txt')):
with open(os.path.join(rtt_root, 'failed_bsp_list.txt'), 'r') as file:
failed_bsp_list = file.read()
if os.path.exists(os.path.join(rtt_root, 'failed_bsp.log')):
with open(os.path.join(rtt_root, 'failed_bsp.log'), 'a') as file:
file.write(failed_bsp_list)