树莓派是arm64架构的,需要一个软件,但是这个软件目前只有源码。树莓派本身性能和内存都不高,在树莓派上自行编译可行性不大。解决方案也很简单,在x86_64的PC上交叉编译,编译出arm64的这个软件即可。
交叉编译?交叉个屁!
配置一堆工具链,还要写一堆编译参数,配置文件,烦都烦死。
最近还要忙着春招,以及毕业设计,没有时间倒腾复杂的交叉编译。日后有时间了再细细研究,在此先用一种取巧的方法解决燃眉之急,这种方法也可以认为是交叉编译arm64架构软件的通解。
目前摸索出来的可行方法有两个,但法一存在尚未解决的问题,有待进一步探索方案,法二是实践证明成功了的。
法一 qemu模拟arm64环境
基本思想是,在x86的PC宿主机使用qemu运行arm64_Linux虚拟机,在虚拟机上安装编译工具链,编译arm64软件,再取回宿主机或直接传至树莓派等arm64设备。
程序员的宿主机一般CPU较强,内存较多,因此尽管模拟arm会有性能损失,但也是可以接受的。
目前的问题是,在arm虚拟机中编译好的软件,拿不回宿主机。我尝试了 挂载镜像,共享文件夹,网络 三种方式,均未成功。
首先安装qemu。能直接apt为什么要编译源码来安装
sudo apt install qemu-system
下载一个arm64的linux系统镜像,我使用了ubuntu-18.04.6-server-arm64。
创建一个虚拟机的虚拟硬盘,其实就是个镜像文件
qemu-img create ubuntuimg.img 40G
#qemu-img是指令,在上面安装过程中一起安装的
#create是操作,创建镜像
#ubuntuimg.img是创建的虚拟硬盘名,就是个镜像文件
#40G是大小。这里40G分大了,其实20G就足够
然后启动虚拟机。下面的指令,将注释去掉后,合并成一行再执行
qemu-system-aarch64
-m 4096 #内存大小,单位MB,可自定义
-cpu cortex-a72 #处理器核心架构名
-smp 4 #核心数量
-M virt #表示虚拟机
-bios QEMU_EFI.fd #BIOS文件,可以在/usr/share/qemu-efi-aarch64目录下找到,把它拷到当前目录
-nographic #非图形化界面
-drive if=none,file=ubuntu-18.04.6-server-arm64.img,id=cdrom,media=cdrom #中间file=xxx这里填系统镜像
-device virtio-scsi-device
-device scsi-cd,drive=cdrom
-drive if=none,file=ubuntuimg.img,id=hd0 #中间file=xxx填上一步创建的虚拟硬盘镜像
-device virtio-blk-device,drive=hd0
然后便以ubuntu镜像启动了qemu虚拟机,进行系统安装的操作。装系统的过程比较漫长,大概半个钟罢。
装好后自动重启,就进入了ubuntu系统中,此时虚拟机中的ubuntu,是arm64环境,可以通过apt安装编译工具链,编译代码了。
sudo apt install build-essential
cd 代码目录
./configure
make
make install
关闭虚拟机后,若想再次启动,则在启动指令中,删除跟ubuntu系统镜像相关的参数即可,以免再次以镜像启动,执行安装。
qemu-system-aarch64
-m 4096
-cpu cortex-a72
-smp 4
-M virt
-bios QEMU_EFI.fd
-nographic
-device virtio-scsi-device
-drive if=none,file=ubuntuimg.img,id=hd0
-device virtio-blk-device,drive=hd0
麻烦就在于,如何把编译好的东西拿回宿主机。
我尝试了三个方法,皆以失败告终。
第一个是直接读虚拟硬盘镜像,即挂载到系统中。但它这个镜像在安装系统时被格式化成一个陌生的分区格式,挂载不了。所以没法这样读虚拟机中的文件。
分区的格式化操作是在安装系统的时候进行的,因此在安装系统时,手动指定格式化成常见格式,比如fat32,exfat,ntfs,ext4之类的,或许能避免该问题。我大抵是安装时花了眼,没看清
第二个是共享文件夹。即在启动qemu虚拟机时,指定一个宿主机上的目录,用于共享。在虚拟机中,将宿主机共享的文件夹挂载/映射到自己的目录,进行读写。
这个方法是我从CSDN中找来的
共享文件夹的挂载是成功了,但数据的传输似乎是单向的。宿主机放在共享文件夹中的文件,虚拟机可以读到,可以删除。但是虚拟机无法创建文件,没法往其中丢文件,让宿主机读取,原因是Permission Denied。
我猜想是宿主机的权限问题,但并没有去深究。
第三个法子是网络,只要虚拟机和宿主机能网络互通,那法子可太多了,ftp, ssh, http...
问题在于,虚拟机的ip,NAT后是10开头的那种ip。它能访问到宿主机,但宿主机访问不到它。我目前还不知道怎么配置qemu的虚拟网卡,日后解决了虚拟网卡的配置问题,就解决了这个麻烦。
但事实上单向网络访问也足够传输文件了,只是我懒得在虚拟机里用命令行操作
法二 安卓手机
不要忘了,现在的智能手机,芯片可都是arm64架构的,而且普遍性能都很高(高主频,制程小,内存大),是编译arm64自身软件的不二之选。
因此需要在Android上运行起Linux,再安装编译工具链。
Termux,官方对其的定义是
Termux is an Android terminal emulator and Linux environment app that works directly with no rooting or setup required.
借助它,在Android上运行起Linux。
Termux官方团队提供了一个proot-distro,用来安装和运行常见的Linux发行版。
在Termux中通过pkg安装
pkg update
pkg install proot-distro
然后利用proot-distro list
列出所有可用的Linux发行版。其中可以看到常用的debian, ubuntu, arch都在
在使用前,需要通过proot-distro install {Linux发行版名字}
,这里linux发行版名字的可选项就是上面列出的,我使用的是debian。安装内容是从github下载的,因此需要通过一点特殊手段以加快下载。
安装完成后,即可proot-distro login {下载的Linux}
,Linux,启动!
然后就能下载编译工具链,configure, make...进行编译了
编译完毕后,将生成的文件从Termux的内部存储区复制到外部存储区(需要赋予读写文件权限),然后就可以传到电脑或者直接传到目标arm64设备了。
顺带一提,安装的Linux目录相对于Termux目录以及手机自身目录的位置如下
通过此方法编译出的软件,在树莓派成功运行。
用同平台编译的方式,避免了交叉编译的麻烦。此方法可以视为编译arm64软件源码的通解,只要有一台手机即可。
但局限性也很明显,将交叉编译转化为同平台编译,对于另外一些鲜有物理硬件设备的架构如riscv,mips,则束手无策,还是得交叉编译。