在x86下搭建arm64编译环境

之前编写过一个小框架,最近需要为它编译一个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产出。如果需要编译其他操作系统的话也可以采用本文的方法,只需要替换其中的操作系统类型即可。