最近需要使用RT-Thread smart 开发调试一些软件功能,由于软件功能平台无关,使用外部硬件操作,会耗费更多的时间在后台。
打算使用BSP qemu-virt64-aarch64搭建一个RT-Thread smart的开发调试环境,可以开发验证一些平台无关的软件功能
环境搭建
Win10 64位
VMware 工作站专业版
VS 代码(ssh 远程)
Ubuntu 20.04
RT-Thread master 最新支持: BSPqemu-virt64-aarch64
下载 RT-Thread
这里使用gitee的RT-Thread库,先通过fork的方式,把RT-Thread fork到自己的账号下
ubuntu 中安安装好git qemu,通过git 克隆一份 RT-Thread 最新代码
可以直接连接克隆RT-Thread 官方的git clone
scons 结构
进入rt-thread/bsp/qemu-virt64-aarch64,直接scons可能会提示scons找不到,如果找不到,就安装一下scons
Command ‘scons’ not found, but can be installed with:
sudo apt install scons
安装 scons 的方法:$ sudo apt install scons
运行$ scons --menuconfig,进入Kconfig 图形配置界面,第一步运行,会克隆 Linux下的RT-Thread env工具与packages软件包
交叉编译工具链
再次运行scons后,发现提示找不到 gcc 交叉编译工具链,aarch64-none-elf-gcc: not found
zhangsz@zhangsz:~/rtt/smart/rt-thread/bsp/qemu-virt64-aarch64$ scons
scons: Reading SConscript files 。。。
scons: done reading SConscript files.
scons: Building targets 。。。
scons: building associated VariantDir targets: build
CC build/applications/console.o sh: 1: aarch64-none-elf-gcc: not found
scons: *** [build/applications/console.o] Error 127
scons: building terminated because of errors.
下载工具链:可以使用get_toolchain.py下载,不过这个脚本默认没有在RT-Thread 工程里面,需要手动创建一个
在rt-thread/bsp/qemu-virt64-aarch64目录下,新建一个tools目录,然后进入这个rt-thread/bsp/qemu-virt64-aarch64/tools目录,创建get_toolchain.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2022, RT-Thread Development Team
#
# SPDX-License-Identifier: GPL-2.0
#
# Change Logs:
# Date Author Notes
# 2022-02-1 Bernard The first version
#
import os
import sys
import platform
from ci import CI
toolchains_config = {
‘arm’:
{
‘Linux’: ‘arm-linux-musleabi_for_x86_64-pc-linux-gnu_latest.tar.bz2’,
‘Windows’: ‘arm-linux-musleabi_for_i686-w64-mingw32_latest.zip’
},
‘aarch64’:
{
‘Linux’ : ‘aarch64-linux-musleabi_for_x86_64-pc-linux-gnu_latest.tar.bz2’,
‘Windows’ : ‘aarch64-linux-musleabi_for_i686-w64-mingw32_latest.zip’
},
‘riscv64’:
{
‘Linux’: ‘riscv64-linux-musleabi_for_x86_64-pc-linux-gnu_latest.tar.bz2’,
‘Windows’: ‘riscv64-linux-musleabi_for_i686-w64-mingw32_latest.zip’
}
}
if __name__ == ‘__main__’:
# download toolchain
if len(sys.argv) 》 1:
target = sys.argv[1]
else:
target = ‘arm’
ci = CI()
toolchain_path = os.path.join(os.path.abspath(‘。’), ‘gnu_gcc’)
platform = platform.system()
try:
zfile = toolchains_config[target][platform]
URL = + zfile
except:
print(‘not found target’)
exit(0)
ci.downloadFile(zfile, URL)
ci.extractZipFile(zfile, toolchain_path)
ci.delFile(zfile)
在rt-thread/bsp/qemu-virt64-aarch64/tools目录下,创建一个ci.py脚本
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2022, RT-Thread Development Team
#
# SPDX-License-Identifier: GPL-2.0
#
# Change Logs:
# Date Author Notes
# 2022-02-1 Bernard The first version
#
import os
import sys
import shutil
import platform
import requests
import time
import zipfile
class CI:
def downloadFile(self, name, url):
headers = {‘Proxy-Connection’:‘keep-alive’}
r = requests.get(url, stream=True, headers=headers)
length = float(r.headers[‘content-length’])
f = open(name, ‘wb’)
count = 0
count_tmp = 0
time1 = time.time()
for chunk in r.iter_content(chunk_size = 512):
if chunk:
f.write(chunk)
count += len(chunk)
if time.time() - time1 》 2:
p = count / length * 100
speed = (count - count_tmp) / 1024 / 1024 / 2
count_tmp = count
print(name + ‘: ’ + ‘{:.2f}’.format(p) + ‘%’)
time1 = time.time()
print(name + ‘: 100%’)
f.close()
def extractZipFile(self, zfile, folder):
# self.delTree(folder)
if not os.path.exists(folder):
os.makedirs(folder)
if platform.system() == ‘Windows’:
zip_file = zipfile.ZipFile(zfile)
zip_list = zip_file.namelist()
for item in zip_list:
print(item)
zip_file.extract(item, folder)
zip_file.close()
elif platform.system() == ‘Linux’:
if zfile.endswith(‘tar.gz’):
os.system(‘tar zxvf %s -C %s’ % (zfile, folder))
elif zfile.endswith(‘tar.bz2’):
os.system(‘tar jxvf %s -C %s’ % (zfile, folder))
elif zfile.endswith(‘.zip’):
os.system(‘unzip %s -d %s’ % (zfile, folder))
return
def zipFolder(self, folder, zfile):
zip_filename = os.path.join(folder)
zip = zipfile.ZipFile(zfile, ‘w’, compression=zipfile.ZIP_BZIP2)
pre_len = len(os.path.dirname(folder))
for parent, dirnames, filenames in os.walk(folder):
for filename in filenames:
pathfile = os.path.join(parent, filename)
arcname = pathfile[pre_len:].strip(os.path.sep)
zip.write(pathfile, arcname)
zip.close()
return
def touchDir(self, d):
if not os.path.exists(d):
os.makedirs(d)
def gitUpdate(self, url, folder, branch = ‘master’):
cwd = os.getcwd()
if os.path.exists(folder):
os.chdir(folder)
os.system(‘git pull origin’)
if branch != ‘master’:
os.system(‘git checkout -b %s origin/%s’ % (branch, branch))
os.system(‘git submodule init’)
os.system(‘git submodule update’)
else:
os.system(‘git clone %s %s’ % (url, folder))
os.chdir(folder)
os.system(‘git submodule init’)
os.system(‘git submodule update’)
os.chdir(cwd)
def installEnv(self, folder):
env_path = folder
cwd = os.getcwd()
os.chdir(env_path)
self.touchDir(os.path.join(env_path, ‘local_pkgs’))
self.touchDir(os.path.join(env_path, ‘packages’))
self.touchDir(os.path.join(env_path, ‘tools’))
self.gitUpdate(‘‘tools/script’)
self.gitUpdate( ‘packages/packages’)
kconfig = open(os.path.join(env_path, ‘packages’, ‘Kconfig’), ‘w’)
kconfig.write(‘source “$PKGS_DIR/packages/Kconfig”’)
kconfig.close()
os.chdir(cwd)
return
def pkgsUpdate(self, env_folder):
self.touchDir(env_folder)
self.installEnv(env_folder)
os.environ[‘PKGS_DIR’] = env_folder
os.system(‘python %s package --update’ % (os.path.join(env_folder, ‘tools’, ‘script’, ‘env.py’)))
return
def delTree(self, folder):
if os.path.exists(folder):
shutil.rmtree(folder)
def delFile(self, file):
if os.path.exists(file):
os.remove(file)
def appendFile(self, srcFile, otherFile):
f = open(otherFile, ‘r’)
s = f.read()
f.close()
f = open(srcFile, ‘a’)
f.write(s)
f.close()
def copyTree(self, srcTree, dstTree):
if os.path.exists(dstTree):
shutil.rmtree(dstTree)
shutil.copytree(srcTree, dstTree)
def run(self, cmds):
cwd = os.getcwd()
cmds = cmds.split(‘n’)
for item in cmds:
item = item.lstrip()
if item == ‘’:
continue
if item[0] == ‘-’:
os.system(item[1:].lstrip())
# keep current directory
os.chdir(cwd)
return
if __name__ == ‘__main__’:
ci = CI()
env_folder = os.path.abspath(os.path.join(‘。’, ‘env_test’))
# ci.pkgsUpdate(env_folder)
cmds = ‘’‘
# test
- dir
- dir tools
’‘’
ci.run(cmds)
下载gcc 交叉编译工具链:qemu-virt64-aarch64是aarch64平台
$ python3 get_toolchain.py aarch64就可以下载aarch64的gcc交叉编译工具链了
在rt-thread/bsp/qemu-virt64-aarch64目录下创建一个设置环境变量的 shell 脚本,如smart_env.sh
#!/bin/bash
# usage:
# source smart-env.sh [arch]
# example: source smart-env.sh # arm
# example: source smart-env.sh aarch64 # aarch64
# supported arch list
supported_arch=“arm aarch64 riscv64 i386”
def_arch=“unknown”
# find arch in arch list
if [ -z $1 ]
then
def_arch=“arm” # default arch is arm
else
for arch in $supported_arch
do
if [ $arch = $1 ]
then
def_arch=$arch
break
fi
done
fi
# set env
case $def_arch in
“arm”)
export RTT_CC=gcc
export RTT_EXEC_PATH=$(pwd)/tools/gnu_gcc/arm-linux-musleabi_for_x86_64-pc-linux-gnu/bin
export RTT_CC_PREFIX=arm-linux-musleabi-
;;
“aarch64”)
export RTT_CC=gcc
export RTT_EXEC_PATH=$(pwd)/tools/gnu_gcc/aarch64-linux-musleabi_for_x86_64-pc-linux-gnu/bin
export RTT_CC_PREFIX=aarch64-linux-musleabi-
;;
“riscv64”)
export RTT_CC=gcc
export RTT_EXEC_PATH=$(pwd)/tools/gnu_gcc/riscv64-linux-musleabi_for_x86_64-pc-linux-gnu/bin
export RTT_CC_PREFIX=riscv64-unknown-linux-musl-
;;
“i386”)
export RTT_CC=gcc
export RTT_EXEC_PATH=$(pwd)/tools/gnu_gcc/i386-linux-musleabi_for_x86_64-pc-linux-gnu/bin
export RTT_CC_PREFIX=i386-unknown-linux-musl-
;;
*) echo “unknown arch!”
return 1
esac
# export RTT_EXEC_PATH
export PATH=$PATH:$RTT_EXEC_PATH
echo “Arch =》 ${def_arch}”
echo “CC =》 ${RTT_CC}”
echo “PREFIX =》 ${RTT_CC_PREFIX}”
echo “EXEC_PATH =》 ${RTT_EXEC_PATH}”
下载gcc交叉编译工具链接后,在rt-thread/bsp/qemu-virt64-aarch64 运行
设置smart_env.sh的执行权限 $ chmod +x smart_env.sh
$ source smart_env.sh aarch64,即可设置qemu-virt64-aarch64 的gcc交叉编译工具链
编译qemu-virt64-aarch64
配置好gcc交叉编译工具链接后,就可以scons编译了
运行qemu
qemu-virt64-aarch64目录下有一个qemu.sh,可以在Linux shell里面直接运行
./qemu.sh
65536+0 records in
65536+0 records out
67108864 bytes (67 MB, 64 MiB) copied, 0.0898412 s, 747 MB/s
[I/libcpu.aarch64.cpu] Using MPID 0x0 as cpu 0
[I/libcpu.aarch64.cpu] Using MPID 0x1 as cpu 1
[I/libcpu.aarch64.cpu] Using MPID 0x2 as cpu 2
[I/libcpu.aarch64.cpu] Using MPID 0x3 as cpu 3
| /
- RT - Thread Operating System
/ | 5.0.0 build Mar 18 2023 19:11:05
2006 - 2022 Copyright by RT-Thread team
[I/libcpu.aarch64.cpu] Secondary CPU 1 booted
[I/libcpu.aarch64.cpu] Sec /》ry CPU 2 booted
[I/libcpu.aarch64.cpu] Secondary CPU 3 booted
m[0m
hello rt-thread
msh /》
msh /》ls
No such directory
msh /》QEMU: Terminated
退出qemu的方法:CTRL + a组合按一下,松开按键,再按一下x键即可退出qemu
小结
linux的的环境,如qemu之前之前安装安装安装,所以所以qemu-virt64-aarch64的交叉交叉编译环境环境搭建搭建起来起来并没有并没有并没有遇到太多,qemu如果 qemu-system-aarch64
当前RT-Thread master 支持的qemu-system-aarch64跑的是RT-Thread,而不是RT-Thread Smart,后面研究如何运行RT-Thread Smart,并用于软件组的开发调试。
原作者:张世争