C++编译—在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 -y qemu qemu-system qemu-user samba # 安装指定平台 qemu-system-aarch64 
or 
# 源码安装 
sudo apt install -y ninja-build libpixman-1-dev libcap-ng-dev libattr1-dev 
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 --enable-kvm --enable-virtfs  # 安装指定平台 --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系统

# 下载ubuntu20.04 arm镜像
mkdir qemu
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 -f raw ubuntu20.04.4-arm64.img 30g
# 安装arm虚拟系统(需要ssh登录的话,记得最后步骤选装下sshd server)
qemu-system-aarch64 -m 8096 -cpu cortex-a57 -smp 8 -M virt -bios QEMU_EFI.fd -nographic -drive if=none,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.4-arm64.img,id=hd0 -device virtio-blk-device,drive=hd0
qemu-img info ubuntu20.04.4-arm64.img
# 关闭后重新启动并进入系统
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.4-arm64.img,id=hd0 -device virtio-blk-device,drive=hd0 -netdev user,hostfwd=tcp::2222-:22,id=netdev0, -device e1000,netdev=netdev0
# 参数:9p协议挂载磁盘
-fsdev local,security_model=passthrough,id=fsdev0,path=/home/work -device virtio-9p-pci,id=fs0,fsdev=fsdev0,mount_tag=qemu_share
sudo mount -t 9p -o trans=virtio,version=9p2000.L qemu_share /mnt
# 参数:smb协议挂载磁盘
-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  #卸载挂载
# 镜像格式转换(qcow2格式不占空间但性能较低,磁盘大的话建议raw)
#qemu-img convert -f raw ubuntu20.04.4-arm64.img -O qcow2 ubuntu20.04.4-arm64.qcow2.img

qemu-system-aarch64命令参数解释如下:

-m 内存大小(这里为8G)
-cpu cpu型号(最新的a78e型号模拟不了)
-smp 核数目(最大模拟8核)
-nographic 不使用图形界面
-drive 驱动器映像文件
-device 设备
-netdev 网络设备(hostfwd:端口映射;smb磁盘挂载)
-fsdev 使用9p virtio支持virtfs共享,其中path参数为Host主机中共享目录的路径

三、arm编译

# 通过ssh进入系统 
ssh work@127.0.0.1 -p 2222
# 安装编译依赖
sudo apt install -y cmake build-essential net-tools libprotobuf-dev protobuf-compiler libjsoncpp-dev libzmq3-dev libgtest-dev libgflags-dev libglog-dev
# 编译
cd project/xxx
cmake ..
make 
make install

四、kvm加速

裸使用qemu明显感觉到速度有点慢,这是因为qemu自己用软件模拟了整套的虚拟机实现,包括处理器虚拟化、内存虚拟化以及I/O设备的虚拟化等,而linux内核有很好用的kvm来硬件模拟CPU和内存,性能要更好些,所以如果你的宿主机支持kvm,我们可以使用它来代替qemu的cpu/mem模拟功能,以提升虚拟机的性能。

所以简单直接的理解就是:QEMU是个计算机模拟器,而KVM为计算机的模拟提供加速功能。

检查宿主机是否支持kvm:

$ grep -E 'vmx|svm' /proc/cpuinfo    #如果有输出则表示硬件有虚拟化支持
$ lsmod | grep kvm      # 如果kvm_intel/kvm_amd、kvm模块被显示出来,则kvm模块已经加载
    kvm_intel             142999  0
    kvm                   444314  1 kvm_intel

创建镜像时指定参数:

qemu-img create -f raw ubuntu20.04.4-arm64.kvm.img 30g
qemu-system-aarch64 -enable-kvm -m 8096 -cpu cortex-a57 -smp 8 -M virt -bios QEMU_EFI.fd -nographic -drive if=none,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.4-arm64.kvm.img,id=hd0 -device virtio-blk-device,drive=hd0 -fsdev local,security_model=passthrough,id=fsdev0,path=/home/work -device virtio-9p-pci,id=fs0,fsdev=fsdev0,mount_tag=qemu_share

其他同上。

五、使用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++
/usr/bin/aarch64-linux-gnu-gcc --version

测试代码:

vim /home/work/test/test.c
  #include <stdio.h>
  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/
)

 

五、总结

至此,我们尝试了通过qemu搭建虚拟arm系统,也尝试了直接在x86下交叉编译arm产出。如果需要编译其他操作系统的话也可以采用本文的方法,只需要替换其中的操作系统类型即可。

 

yan 23.6.1

 

参考:

QEMU – Arch Linux

使用qemu在x86上模拟arm64环境

使用QEMU搭建ARM64实验环境

虚拟化技术之kvm磁盘管理工具qemu-img

欢迎关注下方“非著名资深码农“公众号进行交流~

发表评论

邮箱地址不会被公开。