1{ lib, stdenv, fetchurl, fetchpatch, python3Packages, zlib, pkg-config, glib, buildPackages
2, pixman, vde2, alsa-lib, texinfo, flex
3, bison, lzo, snappy, libaio, libtasn1, gnutls, nettle, curl, ninja, meson, sigtool
4, makeWrapper, runtimeShell, removeReferencesTo
5, attr, libcap, libcap_ng, socat, libslirp
6, CoreServices, Cocoa, Hypervisor, rez, setfile, vmnet
7, guestAgentSupport ? with stdenv.hostPlatform; isLinux || isNetBSD || isOpenBSD || isSunOS || isWindows
8, numaSupport ? stdenv.isLinux && !stdenv.isAarch32, numactl
9, seccompSupport ? stdenv.isLinux, libseccomp
10, alsaSupport ? lib.hasSuffix "linux" stdenv.hostPlatform.system && !nixosTestRunner
11, pulseSupport ? !stdenv.isDarwin && !nixosTestRunner, libpulseaudio
12, sdlSupport ? !stdenv.isDarwin && !nixosTestRunner, SDL2, SDL2_image
13, jackSupport ? !stdenv.isDarwin && !nixosTestRunner, libjack2
14, gtkSupport ? !stdenv.isDarwin && !xenSupport && !nixosTestRunner, gtk3, gettext, vte, wrapGAppsHook
15, vncSupport ? !nixosTestRunner, libjpeg, libpng
16, smartcardSupport ? !nixosTestRunner, libcacard
17, spiceSupport ? true && !nixosTestRunner, spice, spice-protocol
18, ncursesSupport ? !nixosTestRunner, ncurses
19, usbredirSupport ? spiceSupport, usbredir
20, xenSupport ? false, xen
21, cephSupport ? false, ceph
22, glusterfsSupport ? false, glusterfs, libuuid
23, openGLSupport ? sdlSupport, mesa, libepoxy, libdrm
24, virglSupport ? openGLSupport, virglrenderer
25, libiscsiSupport ? true, libiscsi
26, smbdSupport ? false, samba
27, tpmSupport ? true
28, uringSupport ? stdenv.isLinux, liburing
29, canokeySupport ? false, canokey-qemu
30, capstoneSupport ? true, capstone
31, enableDocs ? true
32, hostCpuOnly ? false
33, hostCpuTargets ? (if hostCpuOnly
34 then (lib.optional stdenv.isx86_64 "i386-softmmu"
35 ++ ["${stdenv.hostPlatform.qemuArch}-softmmu"])
36 else null)
37, nixosTestRunner ? false
38, doCheck ? false
39, qemu # for passthru.tests
40}:
41
42let
43 hexagonSupport = hostCpuTargets == null || lib.elem "hexagon" hostCpuTargets;
44in
45
46stdenv.mkDerivation rec {
47 pname = "qemu"
48 + lib.optionalString xenSupport "-xen"
49 + lib.optionalString hostCpuOnly "-host-cpu-only"
50 + lib.optionalString nixosTestRunner "-for-vm-tests";
51 version = "8.0.0";
52
53 src = fetchurl {
54 url = "https://download.qemu.org/qemu-${version}.tar.xz";
55 sha256 = "u2DwNBUxGB1sw5ad0ZoBPQQnqH+RgZOXDZrbkRMeVtA=";
56 };
57
58 depsBuildBuild = [ buildPackages.stdenv.cc ]
59 ++ lib.optionals hexagonSupport [ pkg-config ];
60
61 nativeBuildInputs = [
62 makeWrapper removeReferencesTo
63 pkg-config flex bison meson ninja
64
65 # Don't change this to python3 and python3.pkgs.*, breaks cross-compilation
66 python3Packages.python python3Packages.sphinx python3Packages.sphinx-rtd-theme
67 ]
68 ++ lib.optionals gtkSupport [ wrapGAppsHook ]
69 ++ lib.optionals hexagonSupport [ glib ]
70 ++ lib.optionals stdenv.isDarwin [ sigtool ];
71
72 buildInputs = [ zlib glib pixman
73 vde2 texinfo lzo snappy libtasn1
74 gnutls nettle curl libslirp
75 ]
76 ++ lib.optionals ncursesSupport [ ncurses ]
77 ++ lib.optionals stdenv.isDarwin [ CoreServices Cocoa Hypervisor rez setfile vmnet ]
78 ++ lib.optionals seccompSupport [ libseccomp ]
79 ++ lib.optionals numaSupport [ numactl ]
80 ++ lib.optionals alsaSupport [ alsa-lib ]
81 ++ lib.optionals pulseSupport [ libpulseaudio ]
82 ++ lib.optionals sdlSupport [ SDL2 SDL2_image ]
83 ++ lib.optionals jackSupport [ libjack2 ]
84 ++ lib.optionals gtkSupport [ gtk3 gettext vte ]
85 ++ lib.optionals vncSupport [ libjpeg libpng ]
86 ++ lib.optionals smartcardSupport [ libcacard ]
87 ++ lib.optionals spiceSupport [ spice-protocol spice ]
88 ++ lib.optionals usbredirSupport [ usbredir ]
89 ++ lib.optionals stdenv.isLinux [ libaio libcap_ng libcap attr ]
90 ++ lib.optionals xenSupport [ xen ]
91 ++ lib.optionals cephSupport [ ceph ]
92 ++ lib.optionals glusterfsSupport [ glusterfs libuuid ]
93 ++ lib.optionals openGLSupport [ mesa libepoxy libdrm ]
94 ++ lib.optionals virglSupport [ virglrenderer ]
95 ++ lib.optionals libiscsiSupport [ libiscsi ]
96 ++ lib.optionals smbdSupport [ samba ]
97 ++ lib.optionals uringSupport [ liburing ]
98 ++ lib.optionals canokeySupport [ canokey-qemu ]
99 ++ lib.optionals capstoneSupport [ capstone ];
100
101 dontUseMesonConfigure = true; # meson's configurePhase isn't compatible with qemu build
102
103 outputs = [ "out" ] ++ lib.optional guestAgentSupport "ga";
104 # On aarch64-linux we would shoot over the Hydra's 2G output limit.
105 separateDebugInfo = !(stdenv.isAarch64 && stdenv.isLinux);
106
107 patches = [
108 ./fix-qemu-ga.patch
109
110 # QEMU upstream does not demand compatibility to pre-10.13, so 9p-darwin
111 # support on nix requires utimensat fallback. The patch adding this fallback
112 # set was removed during the process of upstreaming this functionality, and
113 # will still be needed in nix until the macOS SDK reaches 10.13+.
114 ./provide-fallback-for-utimensat.patch
115 # Cocoa clipboard support only works on macOS 10.14+
116 ./revert-ui-cocoa-add-clipboard-support.patch
117 # Standard about panel requires AppKit and macOS 10.13+
118 (fetchpatch {
119 url = "https://gitlab.com/qemu-project/qemu/-/commit/99eb313ddbbcf73c1adcdadceba1423b691c6d05.diff";
120 sha256 = "sha256-gTRf9XENAfbFB3asYCXnw4OV4Af6VE1W56K2xpYDhgM=";
121 revert = true;
122 })
123 # Workaround for upstream issue with nested virtualisation: https://gitlab.com/qemu-project/qemu/-/issues/1008
124 (fetchpatch {
125 url = "https://gitlab.com/qemu-project/qemu/-/commit/3e4546d5bd38a1e98d4bd2de48631abf0398a3a2.diff";
126 sha256 = "sha256-oC+bRjEHixv1QEFO9XAm4HHOwoiT+NkhknKGPydnZ5E=";
127 revert = true;
128 })
129 ]
130 ++ lib.optional nixosTestRunner ./force-uid0-on-9p.patch;
131
132 postPatch = ''
133 # Otherwise tries to ensure /var/run exists.
134 sed -i "/install_emptydir(get_option('localstatedir') \/ 'run')/d" \
135 qga/meson.build
136 '';
137
138 preConfigure = ''
139 unset CPP # intereferes with dependency calculation
140 # this script isn't marked as executable b/c it's indirectly used by meson. Needed to patch its shebang
141 chmod +x ./scripts/shaderinclude.py
142 patchShebangs .
143 # avoid conflicts with libc++ include for <version>
144 mv VERSION QEMU_VERSION
145 substituteInPlace configure \
146 --replace '$source_path/VERSION' '$source_path/QEMU_VERSION'
147 substituteInPlace meson.build \
148 --replace "'VERSION'" "'QEMU_VERSION'"
149 '';
150
151 configureFlags = [
152 "--disable-strip" # We'll strip ourselves after separating debug info.
153 (lib.enableFeature enableDocs "docs")
154 "--enable-tools"
155 "--localstatedir=/var"
156 "--sysconfdir=/etc"
157 # Always use our Meson, not the bundled version, which doesn't
158 # have our patches and will be subtly broken because of that.
159 "--meson=meson"
160 "--cross-prefix=${stdenv.cc.targetPrefix}"
161 (lib.enableFeature guestAgentSupport "guest-agent")
162 ] ++ lib.optional numaSupport "--enable-numa"
163 ++ lib.optional seccompSupport "--enable-seccomp"
164 ++ lib.optional smartcardSupport "--enable-smartcard"
165 ++ lib.optional spiceSupport "--enable-spice"
166 ++ lib.optional usbredirSupport "--enable-usb-redir"
167 ++ lib.optional (hostCpuTargets != null) "--target-list=${lib.concatStringsSep "," hostCpuTargets}"
168 ++ lib.optionals stdenv.isDarwin [ "--enable-cocoa" "--enable-hvf" ]
169 ++ lib.optional stdenv.isLinux "--enable-linux-aio"
170 ++ lib.optional gtkSupport "--enable-gtk"
171 ++ lib.optional xenSupport "--enable-xen"
172 ++ lib.optional cephSupport "--enable-rbd"
173 ++ lib.optional glusterfsSupport "--enable-glusterfs"
174 ++ lib.optional openGLSupport "--enable-opengl"
175 ++ lib.optional virglSupport "--enable-virglrenderer"
176 ++ lib.optional tpmSupport "--enable-tpm"
177 ++ lib.optional libiscsiSupport "--enable-libiscsi"
178 ++ lib.optional smbdSupport "--smbd=${samba}/bin/smbd"
179 ++ lib.optional uringSupport "--enable-linux-io-uring"
180 ++ lib.optional canokeySupport "--enable-canokey"
181 ++ lib.optional capstoneSupport "--enable-capstone";
182
183 dontWrapGApps = true;
184
185 # QEMU attaches entitlements with codesign and strip removes those,
186 # voiding the entitlements and making it non-operational.
187 # The alternative is to re-sign with entitlements after stripping:
188 # * https://github.com/qemu/qemu/blob/v6.1.0/scripts/entitlement.sh#L25
189 dontStrip = stdenv.isDarwin;
190
191 postFixup = ''
192 # the .desktop is both invalid and pointless
193 rm -f $out/share/applications/qemu.desktop
194 '' + lib.optionalString guestAgentSupport ''
195 # move qemu-ga (guest agent) to separate output
196 mkdir -p $ga/bin
197 mv $out/bin/qemu-ga $ga/bin/
198 ln -s $ga/bin/qemu-ga $out/bin
199 remove-references-to -t $out $ga/bin/qemu-ga
200 '' + lib.optionalString gtkSupport ''
201 # wrap GTK Binaries
202 for f in $out/bin/qemu-system-*; do
203 wrapGApp $f
204 done
205 '';
206 preBuild = "cd build";
207
208 # tests can still timeout on slower systems
209 inherit doCheck;
210 nativeCheckInputs = [ socat ];
211 preCheck = ''
212 # time limits are a little meagre for a build machine that's
213 # potentially under load.
214 substituteInPlace ../tests/unit/meson.build \
215 --replace 'timeout: slow_tests' 'timeout: 50 * slow_tests'
216 substituteInPlace ../tests/qtest/meson.build \
217 --replace 'timeout: slow_qtests' 'timeout: 50 * slow_qtests'
218 substituteInPlace ../tests/fp/meson.build \
219 --replace 'timeout: 90)' 'timeout: 300)'
220
221 # point tests towards correct binaries
222 substituteInPlace ../tests/unit/test-qga.c \
223 --replace '/bin/echo' "$(type -P echo)"
224 substituteInPlace ../tests/unit/test-io-channel-command.c \
225 --replace '/bin/socat' "$(type -P socat)"
226
227 # combined with a long package name, some temp socket paths
228 # can end up exceeding max socket name len
229 substituteInPlace ../tests/qtest/bios-tables-test.c \
230 --replace 'qemu-test_acpi_%s_tcg_%s' '%s_%s'
231
232 # get-fsinfo attempts to access block devices, disallowed by sandbox
233 sed -i -e '/\/qga\/get-fsinfo/d' -e '/\/qga\/blacklist/d' \
234 ../tests/unit/test-qga.c
235 '' + lib.optionalString stdenv.isDarwin ''
236 # skip test that stalls on darwin, perhaps due to subtle differences
237 # in fifo behaviour
238 substituteInPlace ../tests/unit/meson.build \
239 --replace "'test-io-channel-command'" "#'test-io-channel-command'"
240 '';
241
242 # Add a ‘qemu-kvm’ wrapper for compatibility/convenience.
243 postInstall = ''
244 ln -s $out/bin/qemu-system-${stdenv.hostPlatform.qemuArch} $out/bin/qemu-kvm
245 '';
246
247 passthru = {
248 qemu-system-i386 = "bin/qemu-system-i386";
249 tests = {
250 qemu-tests = qemu.override { doCheck = true; };
251 };
252 };
253
254 # Builds in ~3h with 2 cores, and ~20m with a big-parallel builder.
255 requiredSystemFeatures = [ "big-parallel" ];
256
257 meta = with lib; {
258 homepage = "http://www.qemu.org/";
259 description = "A generic and open source machine emulator and virtualizer";
260 license = licenses.gpl2Plus;
261 mainProgram = "qemu-kvm";
262 maintainers = with maintainers; [ eelco qyliss ];
263 platforms = platforms.unix;
264 };
265}