在 CentOS 8 下编译 QEMU 以支持运行 macOS 虚拟机
背景⌗
由于项目组选择采用 Electron
构建跨平台客户端, 因此存在一个问题就是如何利用 CI/CD
进行自动构建与发布. 当前内部使用 Jenkins
进行自动构建, 但 Jenkins
仍需要 macOS
平台以便构建 DMG
包进行分发. 因此在不考虑实体机的情况下, 最便捷的方案便是可以能创建一台 macOS
的虚拟机了, 通过虚拟机可以方便地复制构建环境从而不和任意硬件货环境绑定.
但当前的问题一是默认情况下 CentOS 8
下提供的 4.2.0
版本的 QEMU
比较老了, 另一个问题则是 RHEL
在分发的时候移除了相当多的 QEMU
特性, 无法直接创建 macOS
虚拟机, 因此我们需要手动修改 QEMU
的代码并自行构建 RPM
包修复这两个问题.
步骤⌗
首先执行以下命令安装 yum-utils
和 rpm-build
两个包以便下载对应的 SRC
包同时进行编译
sudo yum install -y yum-utils rpm-build
yum-utils
包会提供一个 yumdownloader
命令, 此时再通过以下命令下载 qemu-kvm
的源代码即可:
yumdownloader --source qemu-kvm
yumdownloader
会下载对应版本的 SRC
包到当前目录, 当前 CentOS 8
系统提供的 qemu
版本为 6.0.0
, 因此下载得到的包为 qemu-kvm-6.0.0-33.el8.src.rpm
. 此时再通过以下命令安装 SRC
包即可:
rpm -ivh qemu-kvm-6.0.0-33.el8.src.rpm
同样, 安装以上命令执行完成后会新建一个与执行命令用户绑定的 $HOME/rpmbuild
目录, 所有相关文件都在该目录下所示:
[root@vm-centos-8 ~]# tree -L 1 $HOME/rpmbuild
/root/rpmbuild
├── SOURCES
└── SPECS
2 directories, 0 files
[root@vm-centos-8 ~]#
在编译前还需要安装相关的依赖库, 执行以下命令安装即可:
sudo yum install -y zlib-devel wget usbredir-devel texinfo systemtap-sdt-devel systemtap systemd-devel \
spice-server-devel spice-protocol snappy-devel rsync rdma-core-devel python3-sphinx python3-devel pixman-devel \
perl-podlators perl-Test-Harness pciutils-devel numactl-devel bluez-libs-devel brlapi-devel check-devel cpp \
cyrus-sasl-devel device-mapper-multipath-devel glib2-devel glusterfs-api-devel glusterfs-devel gnutls-devel \
iasl libaio-devel libattr-devel libcacard-devel libcap-ng-devel libcurl-devel libgcrypt-devel libiscsi-devel \
libpmem-devel libpng-devel librados-devel librbd-devel libseccomp-devel libssh-devel libtool libusbx-devel \
libuuid-devel lzo-devel ncurses-devel nss-devel meson ninja-build libepoxy libepoxy-devel libdrm libdrm-devel \
mesa-libgbm-devel libxkbcommon-devel
此时编译前的环境已经准备就绪了, 但因为 RedHat
在构建 qemu
时移除了一些虚拟设备, 因此我们还需要进一步修改刚刚得到的 $HOME/rpmbuild
目录下的问题. 具体修改的文件为 $HOME/rpmbuild/SOURCES/0006-Enable-disable-devices-for-RHEL.patch
, 主要是添加以下内容:
CONFIG_APPLESMC=y
CONFIG_VMXNET3_PCI=y
这里在增加 APPLESMC
支持以外还同时增加了 vmxnet3
虚拟网卡设备主要原因在于相较于 E1000/E1000E
而言 vmxnet3
可以提供更好的性能, 不使用 virtio
的原因则是 macOS
当前对 virtio
的支持还不太确定, 而 vmxnet3
则是官方支持的. 另外由于我们是直接修改 patch
文件, 因此需要遵守 patch
文件格式规范, 以上只是主要修改的内容. 如果修改没有问题此时我们执行以下命令进行编译:
cd $HOME/rpmbuild
rpmbuild --nocheck --define "debug_package %{nil}" -bb SPECS/qemu-kvm.spec
以上命令通过选项禁用了编译后的 test
以及 debuginfo
包的编译以便节约时间. 如果没有意外的话以上命令正常结束后会在 $HOME/rpmbuild/RPMS/$(uname -m)
目录下生成所有编译好的 rpm
包. 对于该目录下的 RPM
包我们可以选择性的安装也可以全部安装:
cd $HOME/rpmbuild/RPMS/$(uname -m)
yum localinstall -y ./*.rpm
也可将以上 RPM
包分发到其他 CentOS 8
的机器上安装.
补充⌗
在完成 RPM
编译后最好先确认下是否已将 apple
和 vmxnet3
设备的支持编译进去:
export QEMU_VERSION="6.0.0"
cd $HOME/rpmbuild
BUILD/qemu-${QEMU_VERSION}/qemu_kvm_build/qemu-system-x86_64 -device help | egrep -i "apple|vmxnet3"
如果没有问题的话会看到包含 isa-applesmc
和 vmxnet3
的两行输出.
另外一个问题是当前编译后的 RPM
包内没有包含 vmxnet3
的 rom
文件, 因此需要收到拷贝一下:
export QEMU_VERSION="6.0.0"
cd $HOME/rpmbuild
cp BUILD/qemu-${QEMU_VERSION}/pc-bios/efi-vmxnet3.rom /usr/share/qemu-kvm
此时在创建虚拟机时便可指定网卡类型为 vmxnet3
了.
再补充⌗
对于以上需要修改 patch
文件的步骤可以直接使用以下命令:
export PATCH_FILE="/tmp/devices-$(uuidgen).patch"
cd $HOME/rpmbuild
cat > "${PATCH_FILE}" << EOF
--- SOURCES/0006-Enable-disable-devices-for-RHEL.patch 2021-09-17 21:43:45.000000000 +0800
+++ 0006-Enable-disable-devices-for-RHEL.patch 2023-04-07 18:05:42.535508928 +0800
@@ -319,7 +319,7 @@
index 0000000000..9f41400530
--- /dev/null
+++ b/default-configs/devices/x86_64-rh-devices.mak
-@@ -0,0 +1,104 @@
+@@ -0,0 +1,106 @@
+include rh-virtio.mak
+
+CONFIG_AC97=y
@@ -424,6 +424,8 @@
+CONFIG_TPM_TIS_ISA=y
+CONFIG_TPM_EMULATOR=y
+CONFIG_TPM_PASSTHROUGH=y
++CONFIG_APPLESMC=y
++CONFIG_VMXNET3_PCI=y
diff --git a/default-configs/devices/x86_64-softmmu.mak b/default-configs/devices/x86_64-softmmu.mak
index 64b2ee2960..e57bcff7d9 100644
--- a/default-configs/devices/x86_64-softmmu.mak
EOF
patch SOURCES/0006-Enable-disable-devices-for-RHEL.patch "${PATCH_FILE}"