123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338 |
- #
- # 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)
|