qemu 的 configure 并没有使用 Autotools 那一套,而是手写的 configure shell 脚本,但是命令行选项模拟了 Autotools 的实现,如显式启用、禁用特性:

--enable-foo, --disable-foo

configure 原理

特性的控制当前分两部分,一部分是 configure 脚本实现,一部分是 meson 构建工具实现,但最终会统一至 meson,如对 rbd 特性的修改:

rbd: convert to meson
https://github.com/qemu/qemu/commit/fabd1e93d93ef90ddf8574a42aee406314cc47c4

configure 脚本实现的开关

yes/no/""/default_feature,如:libpmem="$default_feature"

default_feature 默认为 ""

--without-default-features 选项将设置 default_featureno

1
2
3
4
5
6
7
8
9
10
default_feature=""
# parse CC options second
for opt do
optarg=$(expr "x$opt" : 'x[^=]*=\(.*\)')
case "$opt" in
--without-default-features)
default_feature="no"
;;
esac
done

以 rdma 为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
## qemu/configure

rdma="$default_feature"

--enable-rdma) rdma="yes"
;;
--disable-rdma) rdma="no"
;;

# RDMA needs OpenFabrics libraries
if test "$rdma" != "no" ; then
cat > $TMPC <<EOF
#include <rdma/rdma_cma.h>
int main(void) { return 0; }
EOF
rdma_libs="-lrdmacm -libverbs -libumad"
if compile_prog "" "$rdma_libs" ; then
rdma="yes"
else
if test "$rdma" = "yes" ; then
error_exit \
" OpenFabrics librdmacm/libibverbs/libibumad not present." \
" Your options:" \
" (1) Fast: Install infiniband packages (devel) from your distro." \
" (2) Cleanest: Install libraries from www.openfabrics.org" \
" (3) Also: Install softiwarp if you don't have RDMA hardware"
fi
rdma="no"
fi
fi

meson 构建选项实现的开关

enabled/disabled/auto,如:vnc="enabled"

If the value of a feature option is set to auto, that value is overridden by the global auto_features option (which defaults to auto). This is intended to be used by packagers who want to have full control on which dependencies are required and which are disabled, and not rely on build-deps being installed (at the right version) to get a feature enabled. They could set auto_features=enabled to enable all features and disable explicitly only the few they don’t want, if any.

Build options
https://mesonbuild.com/Build-options.html

1
2
3
4
## qemu/configure

NINJA=$ninja $meson setup \
$(if test "$default_feature" = no; then echo "-Dauto_features=disabled"; fi)

configure: Fix –without-default-features propagation to meson
https://github.com/qemu/qemu/commit/332008e0b9da33dee2c765db3e4e16b3c3ba3a92

显然,--without-default-features 选项决定了 auto_features 的行为。

以 rbd 为例:

1
2
3
4
5
6
7
8
9
10
11
## qemu/configure

rbd="auto"

--disable-rbd) rbd="disabled"
;;
--enable-rbd) rbd="enabled"
;;

NINJA=$ninja $meson setup \
-Drbd=$rbd
1
2
3
4
## qemu/meson_options.txt

option('rbd', type : 'feature', value : 'auto',
description: 'Ceph block device driver')
1
2
3
## qemu/configure

echo "TARGET_DIRS=$target_list" >> $config_host_mak
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
## qemu/meson.build

target_dirs = config_host['TARGET_DIRS'].split()
have_user = false
have_system = false
foreach target : target_dirs
have_user = have_user or target.endswith('-user')
have_system = have_system or target.endswith('-softmmu')
endforeach
have_tools = 'CONFIG_TOOLS' in config_host
have_block = have_system or have_tools

rbd = not_found
if not get_option('rbd').auto() or have_block
librados = cc.find_library('rados', required: get_option('rbd'),
kwargs: static_kwargs)
librbd = cc.find_library('rbd', has_headers: ['rbd/librbd.h'],
required: get_option('rbd'),
kwargs: static_kwargs)
if librados.found() and librbd.found()
if cc.links('''
#include <stdio.h>
#include <rbd/librbd.h>
int main(void) {
rados_t cluster;
rados_create(&cluster, NULL);
return 0;
}''', dependencies: [librbd, librados])
rbd = declare_dependency(dependencies: [librbd, librados])
elif get_option('rbd').enabled()
error('could not link librados')
else
warning('could not link librados, disabling')
endif
endif
endif

上面的判断 if not get_option('rbd').auto() 让人有点意外,看上去是个明显的错误(特别是对照 configure 版本的处理来看),当然,由于 have_block 的存在使得这个条件存在与否基本上无关紧要。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
## qemu/block/meson.build

block_modules = {}

modsrc = []
foreach m : [
[curl, 'curl', [curl, glib], 'curl.c'],
[glusterfs, 'gluster', glusterfs, 'gluster.c'],
[libiscsi, 'iscsi', libiscsi, 'iscsi.c'],
[libnfs, 'nfs', libnfs, 'nfs.c'],
[libssh, 'ssh', libssh, 'ssh.c'],
[rbd, 'rbd', rbd, 'rbd.c'],
]
if m[0].found()
if enable_modules
modsrc += files(m[3])
endif
module_ss = ss.source_set()
module_ss.add(when: m[2], if_true: files(m[3]))
block_modules += {m[1] : module_ss}
endif
endforeach

configure & build

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
$ wget https://download.qemu.org/qemu-6.1.0.tar.xz
$ tar xJf qemu-6.1.0.tar.xz
$ cd qemu-6.1.0/
$ mkdir build
$ cd build/
$ ../configure --prefix=$PWD/qemu-bin --target-list='x86_64-softmmu,aarch64-softmmu' --enable-kvm --enable-tools --without-default-features --enable-linux-aio --enable-rbd --enable-vnc --enable-vnc-png
$ make install
$ tree -L 2 qemu-bin/
qemu-bin/
├── bin
│   ├── qemu-edid
│   ├── qemu-img
│   ├── qemu-io
│   ├── qemu-nbd
│   ├── qemu-pr-helper
│   ├── qemu-storage-daemon
│   ├── qemu-system-aarch64
│   └── qemu-system-x86_64
├── libexec
│   └── qemu-bridge-helper
└── share
├── applications
├── icons
└── qemu
$ tree -L 1 qemu-bin/share/qemu/
qemu-bin/share/qemu/
├── bamboo.dtb
├── bios-256k.bin
├── bios.bin
├── bios-microvm.bin
├── canyonlands.dtb
├── edk2-aarch64-code.fd
├── edk2-arm-code.fd
├── edk2-arm-vars.fd
├── edk2-i386-code.fd
├── edk2-i386-secure-code.fd
├── edk2-i386-vars.fd
├── edk2-licenses.txt
├── edk2-x86_64-code.fd
├── edk2-x86_64-secure-code.fd
...

由于 --without-default-features 将可选特性都设置成了禁用,因此需要显式的使能 kvm, tools, aio, rbd, vnc 等可选特性。

qemu-bin/ 文件夹拷贝至合适的地方,然后既可以将 qemu-bin/bin/ 加入 PATH,也可以直接以绝对定位的方式运行 qemu 工具。