之前编写过一个小框架,最近需要为它编译一个arm64的产出,但是由于arm板子不在手上,只能在x86上编译出arm的产出后再发给对方部署。
本文就以此场景为例,讲解如何通过qemu、gcc交叉编译等方法,在x86机器上搭建arm64的编译环境并完成arm编译。
测试环境信息和版本如下:
- x86平台:x86 ubuntu22.04
- arm平台:arm64 ubuntu20.04
- arm gcc version :9.5.0
- qemu版本:6.2.0
- 交叉编译工具链:aarch64-linux-gnu
一、安装qemu
我们可以下载QEMU的源码通过编译的方式安装,也可以直接apt方式安装:
# apt安装
sudo apt install qemu qemu-system qemu-user # 安装指定平台 qemu-system-aarch64
or
# 源码安装
sudo wget https://download.qemu.org/qemu-6.2.0.tar.xz
tar xvJf qemu-6.2.0.tar.xz
cd qemu-6.2.0
./configure # 安装指定平台参数
–target-list=aarch64-softmmu
make && make install
查看版本号:
$ qemu-system-aarch64 --version
QEMU emulator version 6.2.0 (Debian 1:6.2+dfsg-2ubuntu6.8)
Copyright (c) 2003-2021 Fabrice Bellard and the QEMU Project developers
二、构建arm系统
mkdir qemu
# 下载ubuntu arm镜像
wget http://cdimage.ubuntu.com/ubuntu-legacy-server/releases/20.04/release/ubuntu-20.04.1-legacy-server-arm64.iso
# 下载uefi驱动
wget http://releases.linaro.org/components/kernel/uefi-linaro/latest/release/qemu64/QEMU_EFI.fd
# 格式化出一个系统盘
qemu-img create ubuntu20.04.4arm64.img 30g
# 安装arm虚拟系统
qemu-system-aarch64 -m 8096 -cpu cortex-a57 -smp 8 -M virt -bios QEMU_EFI.fd -nographic -drive if=none,format=raw,file=ubuntu-20.04.1-legacy-server-arm64.iso,id=cdrom,media=cdrom -device virtio-scsi-device -device scsi-cd,drive=cdrom -drive if=none,file=ubuntu20.04.4arm64.img,id=hd0 -device virtio-blk-device,drive=hd0
# 关闭后重新启动并进入系统
sudo apt install samba # 宿主机运行
qemu-system-aarch64 -m 8096 -cpu cortex-a57 -smp 8 -M virt -bios QEMU_EFI.fd -nographic -drive if=none,format=raw,file=ubuntu20.04.4arm64.img,id=hd0 -device virtio-blk-device,drive=hd0 -netdev user,hostfwd=tcp::2222-:22,id=netdev0, -device e1000,netdev=netdev0 -net nic -net user,smb=/home/work
apt update && apt install cifs-utils # arm虚拟机运行
sudo mount -t cifs //10.0.2.4/qemu/ /mnt # 别修改ip,原样执行即可把smb参数的路径挂载到虚拟机的/mnt目录(注意这里要输入两次密码,一次是sudo需要的当前登陆密码,一次是mount需要的root密码;ubuntu系统的默认密码为ubuntu)
#sudo umount -a -t cifs -l #卸载挂载
qemu-system-aarch64命令参数解释如下:
-m 内存大小(这里为8G)
-cpu cpu型号(最新的a78e型号模拟不了)
-smp 核数目(最大模拟8核)
-nographic 不使用图形界面
-drive 驱动器映像文件
-device 设备
-netdev 网络设备(hostfwd:端口映射;smb磁盘挂载)
三、arm编译
# 通过ssh进入系统
ssh work@127.0.0.1 -p 2222
# 安装编译依赖
sudo apt install -y cmake build-essential net-tools
sudo apt install -y libprotobuf-dev protobuf-compiler libjsoncpp-dev libzmq3-dev libgtest-dev libgflags-dev libglog-dev
# 编译
cd project/xxx
cmake ..
make
make install
四、使用gcc-aarch64交叉编译
除了使用qemu以外,我们也可以在x86系统里安装arrch64版本的gcc,并在x86下编译出arm的产出。
可以通过命令”apt-cache search aarch64″ 查看系统源中有哪些安装包可供安装:
apt-cache search aarch64
... ...
gcc-9-aarch64-linux-gnu - GNU C compiler (cross compiler for arm64 architecture)
gcc-10-aarch64-linux-gnu - GNU C compiler (cross compiler for arm64 architecture)
gcc-11-aarch64-linux-gnu - GNU C compiler (cross compiler for arm64 architecture)
gcc-12-aarch64-linux-gnu - GNU C compiler (cross compiler for arm64 architecture)
... ...
为了确保跟arm硬件上的gcc保持一直,这里选择”gcc-9-aarch64-linux-gnu”进行安装:
sudo apt-get install gcc-9-aarch64-linux-gnu g++-9-aarch64-linux-gnu # 注意apt安装版本是gcc9.5+glibc2.34,需要与自己arm硬件上的glibc版本匹配
# 为方便使用可以软连接
sudo ln -s /usr/bin/aarch64-linux-gnu-gcc-9 /usr/bin/aarch64-linux-gnu-gcc
sudo ln -s /usr/bin/aarch64-linux-gnu-g++-9 /usr/bin/aarch64-linux-gnu-g++
aarch64-linux-gnu-gcc --version
测试代码:
vim /home/work/test/test.c
#include
int main(int argc, char **argv){
printf("build arm succ!\n");
return 0;
}
编译:
aarch64-linux-gnu-gcc test.c -o test
到arm对应挂载磁盘下运行:
work@qemu-ubuntu-arm:/mnt/test$ ./test
build arm succ!
使用cmake编译时的参数:
# arch
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=armv8-a -mtune=cortex-a72 -mcpu=cortex-a72")
set(CMAKE_C_COMPILER /usr/bin/aarch64-linux-gnu-gcc CACHE FILEPATH "")
set(CMAKE_CXX_COMPILER /usr/bin/aarch64-linux-gnu-g++ CACHE FILEPATH "")
set(CMAKE_STRIP /usr/bin/aarch64-linux-gnu-strip CACHE FILEPATH "")
set(CMAKE_RANLIB /usr/bin/aarch64-linux-gnu-ranlib CACHE FILEPATH "")
set(CMAKE_AR /usr/bin/aarch64-linux-gnu-ar CACHE FILEPATH "")
include_directories(
/usr/aarch64-linux-gnu/include/
)
link_directories(
/usr/aarch64-linux-gnu/lib/
)
work@qemu-ubuntu-arm:/mnt/test$ ./test
build arm succ!
五、总结
至此,我们尝试了通过qemu搭建虚拟arm系统,也尝试了直接在x86下交叉编译arm产出。如果需要编译其他操作系统的话也可以采用本文的方法,只需要替换其中的操作系统类型即可。