1{
2 config,
3 stdenv,
4 fetchurl,
5 fetchpatch,
6 callPackage,
7 lib,
8 acpica-tools,
9 dev86,
10 pam,
11 libxslt,
12 libxml2,
13 libX11,
14 xorgproto,
15 libXext,
16 libXcursor,
17 libXfixes,
18 libXmu,
19 SDL2,
20 libcap,
21 libGL,
22 libGLU,
23 libpng,
24 glib,
25 lvm2,
26 libXrandr,
27 libXinerama,
28 libopus,
29 libtpms,
30 qt6,
31 pkg-config,
32 which,
33 docbook_xsl,
34 docbook_xml_dtd_43,
35 alsa-lib,
36 curl,
37 libvpx,
38 net-tools,
39 dbus,
40 replaceVars,
41 gsoap,
42 zlib,
43 xz,
44 yasm,
45 glslang,
46 nixosTests,
47 # If open-watcom-bin is not passed, VirtualBox will fall back to use
48 # the shipped alternative sources (assembly).
49 open-watcom-bin,
50 makeself,
51 perl,
52 vulkan-loader,
53 javaBindings ? true,
54 jdk, # Almost doesn't affect closure size
55 pythonBindings ? false,
56 python3,
57 extensionPack ? null,
58 fakeroot,
59 pulseSupport ? config.pulseaudio or stdenv.hostPlatform.isLinux,
60 libpulseaudio,
61 enableHardening ? false,
62 headless ? false,
63 enable32bitGuests ? true,
64 enableWebService ? false,
65 enableKvm ? false,
66 extraConfigureFlags ? "",
67}:
68
69# The web services use Java infrastructure.
70assert enableWebService -> javaBindings;
71
72let
73 buildType = "release";
74 # Use maintainers/scripts/update.nix to update the version and all related hashes or
75 # change the hashes in extpack.nix and guest-additions/default.nix as well manually.
76 virtualboxVersion = "7.1.12";
77 virtualboxSubVersion = "";
78 virtualboxSha256 = "6f9618f39168898134975f51df7c2d6d5129c0aa82b6ae11cf47f920c70df276";
79
80 kvmPatchVersion = "20250207";
81 kvmPatchHash = "sha256-GzRLIXhzWL1NLvaGKcWVBCdvay1IxgJUE4koLX1ze7Y=";
82
83 # The KVM build is not compatible to VirtualBox's kernel modules. So don't export
84 # modsrc at all.
85 withModsrc = !enableKvm;
86
87 virtualboxGuestAdditionsIso = callPackage guest-additions-iso/default.nix {
88 inherit virtualboxVersion;
89 };
90
91 inherit (lib)
92 optional
93 optionals
94 optionalString
95 getDev
96 getLib
97 ;
98 inherit (qt6)
99 qtbase
100 qttools
101 qtsvg
102 qtwayland
103 qtscxml
104 wrapQtAppsHook
105 ;
106in
107stdenv.mkDerivation (finalAttrs: {
108 pname = "virtualbox";
109 version = "${finalAttrs.virtualboxVersion}${finalAttrs.virtualboxSubVersion}";
110
111 inherit
112 buildType
113 virtualboxVersion
114 virtualboxSubVersion
115 virtualboxSha256
116 kvmPatchVersion
117 kvmPatchHash
118 virtualboxGuestAdditionsIso
119 ;
120
121 src = fetchurl {
122 url = "https://download.virtualbox.org/virtualbox/${finalAttrs.virtualboxVersion}/VirtualBox-${finalAttrs.virtualboxVersion}${finalAttrs.virtualboxSubVersion}.tar.bz2";
123 sha256 = finalAttrs.virtualboxSha256;
124 };
125
126 outputs = [ "out" ] ++ optional withModsrc "modsrc";
127
128 nativeBuildInputs = [
129 pkg-config
130 which
131 docbook_xsl
132 docbook_xml_dtd_43
133 yasm
134 glslang
135 ]
136 ++ optional (!headless) wrapQtAppsHook;
137
138 # Wrap manually because we wrap just a small number of executables.
139 dontWrapQtApps = true;
140
141 buildInputs = [
142 acpica-tools
143 dev86
144 libxslt
145 libxml2
146 xorgproto
147 libX11
148 libXext
149 libXcursor
150 libcap
151 glib
152 lvm2
153 alsa-lib
154 curl
155 libvpx
156 pam
157 makeself
158 perl
159 libXmu
160 libXrandr
161 libpng
162 libopus
163 libtpms
164 python3
165 xz
166 ]
167 ++ optional javaBindings jdk
168 ++ optional pythonBindings python3 # Python is needed even when not building bindings
169 ++ optional pulseSupport libpulseaudio
170 ++ optionals headless [ libGL ]
171 ++ optionals (!headless) [
172 qtbase
173 qttools
174 qtscxml
175 libXinerama
176 SDL2
177 libGLU
178 ]
179 ++ optionals enableWebService [
180 gsoap
181 zlib
182 ];
183
184 hardeningDisable = [
185 "format"
186 "fortify"
187 "pic"
188 "stackprotector"
189 ];
190
191 prePatch = ''
192 set -x
193 sed -e 's@MKISOFS --version@MKISOFS -version@' \
194 -e 's@PYTHONDIR=.*@PYTHONDIR=${optionalString pythonBindings python3}@' \
195 -e 's@CXX_FLAGS="\(.*\)"@CXX_FLAGS="-std=c++11 \1"@' \
196 ${
197 optionalString (!headless) ''
198 -e 's@TOOLQT6BIN=.*@TOOLQT6BIN="${getDev qttools}/bin"@' \
199 ''
200 } -i configure
201 ls kBuild/bin/linux.x86/k* tools/linux.x86/bin/* | xargs -n 1 patchelf --set-interpreter ${stdenv.cc.libc}/lib/ld-linux.so.2
202 ls kBuild/bin/linux.amd64/k* tools/linux.amd64/bin/* | xargs -n 1 patchelf --set-interpreter ${stdenv.cc.libc}/lib/ld-linux-x86-64.so.2
203
204 grep 'libpulse\.so\.0' src include -rI --files-with-match | xargs sed -i -e '
205 ${optionalString pulseSupport ''s@"libpulse\.so\.0"@"${libpulseaudio.out}/lib/libpulse.so.0"@g''}'
206
207 grep 'libdbus-1\.so\.3' src include -rI --files-with-match | xargs sed -i -e '
208 s@"libdbus-1\.so\.3"@"${dbus.lib}/lib/libdbus-1.so.3"@g'
209
210 grep 'libXfixes\.so\.3' src include -rI --files-with-match | xargs sed -i -e '
211 s@"libXfixes\.so\.3"@"${libXfixes.out}/lib/libXfixes.so.3"@g'
212
213 grep 'libasound\.so\.2' src include -rI --files-with-match | xargs sed -i -e '
214 s@"libasound\.so\.2"@"${alsa-lib.out}/lib/libasound.so.2"@g'
215
216 export USER=nix
217 set +x
218 '';
219
220 patches =
221 optional enableHardening ./hardened.patch
222 # Since VirtualBox 7.0.8, VBoxSDL requires SDL2, but the build framework uses SDL1
223 ++ optionals (!headless) [
224 ./fix-sdl.patch
225 # No update patch disables check for update function
226 # https://bugs.launchpad.net/ubuntu/+source/virtualbox-ose/+bug/272212
227 (fetchpatch {
228 url = "https://salsa.debian.org/pkg-virtualbox-team/virtualbox/-/raw/42a1ca1291fde365bfba140cb21a8a074aaccce2/debian/patches/16-no-update.patch";
229 hash = "sha256-qM2e4DkkpmA18Z76OUsnY1MhcGb1dT2PG68JUy6fZEE=";
230 })
231 ]
232 ++ [ ./extra_symbols.patch ]
233 # When hardening is enabled, we cannot use wrapQtApp to ensure that VirtualBoxVM sees
234 # the correct environment variables needed for Qt to work, specifically QT_PLUGIN_PATH.
235 # This is because VirtualBoxVM would detect that it is wrapped that and refuse to run,
236 # and also because it would unset QT_PLUGIN_PATH for security reasons. We work around
237 # these issues by patching the code to set QT_PLUGIN_PATH to the necessary paths,
238 # after the code that unsets it. Note that qtsvg is included so that SVG icons from
239 # the user's icon theme can be loaded.
240 ++ optional (!headless && enableHardening) (
241 replaceVars ./qt-env-vars.patch {
242 qtPluginPath = "${qtbase}/bin/${qtbase.qtPluginPrefix}:${qtsvg}/bin/${qtbase.qtPluginPrefix}:${qtwayland}/bin/${qtbase.qtPluginPrefix}";
243 }
244 )
245 # While the KVM patch should not break any other behavior if --with-kvm is not specified,
246 # we don't take any chances and only apply it if people actually want to use KVM support.
247 ++ optional enableKvm (
248 let
249 patchVboxVersion =
250 # There is no updated patch for 7.1.12 yet, but the older one still applies.
251 if finalAttrs.virtualboxVersion == "7.1.12" then "7.1.6" else finalAttrs.virtualboxVersion;
252 in
253 fetchpatch {
254 name = "virtualbox-${finalAttrs.virtualboxVersion}-kvm-dev-${finalAttrs.kvmPatchVersion}.patch";
255 url = "https://github.com/cyberus-technology/virtualbox-kvm/releases/download/dev-${finalAttrs.kvmPatchVersion}/kvm-backend-${patchVboxVersion}-dev-${finalAttrs.kvmPatchVersion}.patch";
256 hash = finalAttrs.kvmPatchHash;
257 }
258 )
259 ++ [
260 ./qt-dependency-paths.patch
261 # https://github.com/NixOS/nixpkgs/issues/123851
262 ./fix-audio-driver-loading.patch
263 ];
264
265 postPatch = ''
266 sed -i -e 's|/sbin/ifconfig|${net-tools}/bin/ifconfig|' \
267 src/VBox/HostDrivers/adpctl/VBoxNetAdpCtl.cpp
268 '';
269
270 # first line: ugly hack, and it isn't yet clear why it's a problem
271 configurePhase = ''
272 NIX_CFLAGS_COMPILE=$(echo "$NIX_CFLAGS_COMPILE" | sed 's,\-isystem ${lib.getDev stdenv.cc.libc}/include,,g')
273
274 cat >> LocalConfig.kmk <<LOCAL_CONFIG
275 VBOX_WITH_TESTCASES :=
276 VBOX_WITH_TESTSUITE :=
277 VBOX_WITH_VALIDATIONKIT :=
278 VBOX_WITH_DOCS :=
279 VBOX_WITH_WARNINGS_AS_ERRORS :=
280
281 VBOX_WITH_ORIGIN :=
282 VBOX_PATH_APP_PRIVATE_ARCH_TOP := $out/share/virtualbox
283 VBOX_PATH_APP_PRIVATE_ARCH := $out/libexec/virtualbox
284 VBOX_PATH_SHARED_LIBS := $out/libexec/virtualbox
285 VBOX_WITH_RUNPATH := $out/libexec/virtualbox
286 VBOX_PATH_APP_PRIVATE := $out/share/virtualbox
287 VBOX_PATH_APP_DOCS := $out/doc
288
289 VBOX_WITH_UPDATE_AGENT :=
290
291 ${optionalString javaBindings ''
292 VBOX_JAVA_HOME := ${jdk}
293 ''}
294 ${optionalString (!headless) ''
295 VBOX_WITH_VBOXSDL := 1
296 PATH_QT6_TOOLS_LIB := ${getLib qttools}/lib
297 PATH_QT6_TOOLS_INC := ${getLib qttools}/include
298 PATH_QT6_SCXML_LIB := ${getLib qtscxml}/lib
299 PATH_QT6_SCXML_INC := ${getLib qtscxml}/include
300 VBOX_PATH_QT := ${getLib qttools}/
301 ''}
302 ${optionalString enableWebService ''
303 # fix gsoap missing zlib include and produce errors with --as-needed
304 VBOX_GSOAP_CXX_LIBS := gsoapssl++ z
305 ''}
306 TOOL_QT6_LRC := ${getLib qttools}/bin/lrelease
307 LOCAL_CONFIG
308
309 ./configure \
310 ${optionalString headless "--build-headless"} \
311 ${optionalString (!javaBindings) "--disable-java"} \
312 ${optionalString (!pythonBindings) "--disable-python"} \
313 ${optionalString (!pulseSupport) "--disable-pulse"} \
314 ${optionalString (!enableHardening) "--disable-hardening"} \
315 ${optionalString (!enable32bitGuests) "--disable-vmmraw"} \
316 ${optionalString enableWebService "--enable-webservice"} \
317 ${optionalString (open-watcom-bin != null) "--with-ow-dir=${open-watcom-bin}"} \
318 ${optionalString (enableKvm) "--with-kvm"} \
319 ${extraConfigureFlags} \
320 --disable-kmods
321 sed -e 's@PKG_CONFIG_PATH=.*@PKG_CONFIG_PATH=${glib.dev}/lib/pkgconfig@' \
322 -i AutoConfig.kmk
323 sed -e 's@arch/x86/@@' \
324 -i Config.kmk
325 substituteInPlace Config.kmk --replace-fail "VBOX_WITH_TESTCASES = 1" "#"
326 '';
327
328 enableParallelBuilding = true;
329
330 buildPhase = ''
331 source env.sh
332 kmk -j $NIX_BUILD_CORES BUILD_TYPE="${finalAttrs.buildType}"
333 '';
334
335 installPhase = ''
336 libexec="$out/libexec/virtualbox"
337 share="${if enableHardening then "$out/share/virtualbox" else "$libexec"}"
338
339 # Install VirtualBox files
340 mkdir -p "$libexec"
341 find out/linux.*/${finalAttrs.buildType}/bin -mindepth 1 -maxdepth 1 \
342 -name src -o -exec cp -avt "$libexec" {} +
343
344 mkdir -p $out/bin
345 for file in ${
346 optionalString (!headless) "VirtualBox VBoxSDL"
347 } ${optionalString enableWebService "vboxwebsrv"} VBoxManage VBoxBalloonCtrl VBoxHeadless; do
348 echo "Linking $file to /bin"
349 test -x "$libexec/$file"
350 ln -s "$libexec/$file" $out/bin/$file
351 done
352
353 ${optionalString (extensionPack != null) ''
354 mkdir -p "$share"
355 "${fakeroot}/bin/fakeroot" "${stdenv.shell}" <<EOF
356 "$libexec/VBoxExtPackHelperApp" install \
357 --base-dir "$share/ExtensionPacks" \
358 --cert-dir "$share/ExtPackCertificates" \
359 --name "Oracle VirtualBox Extension Pack" \
360 --tarball "${extensionPack}" \
361 --sha-256 "${extensionPack.outputHash}"
362 EOF
363 ''}
364
365 ${optionalString (!headless) ''
366 # Create and fix desktop item
367 mkdir -p $out/share/applications
368 sed -i -e "s|Icon=VBox|Icon=$libexec/VBox.png|" $libexec/virtualbox.desktop
369 ln -sfv $libexec/virtualbox.desktop $out/share/applications
370 # Icons
371 mkdir -p $out/share/icons/hicolor
372 for size in `ls -1 $libexec/icons`; do
373 mkdir -p $out/share/icons/hicolor/$size/apps
374 ln -s $libexec/icons/$size/*.png $out/share/icons/hicolor/$size/apps
375 done
376 # Translation
377 mkdir -p "$out/share/virtualbox"
378 ln -sv $libexec/nls "$out/share/virtualbox/nls"
379 ''}
380
381 ${optionalString withModsrc ''
382 cp -rv out/linux.*/${finalAttrs.buildType}/bin/src "$modsrc"
383 ''}
384
385 mkdir -p "$out/share/virtualbox"
386 cp -rv src/VBox/Main/UnattendedTemplates "$out/share/virtualbox"
387 ln -s "${finalAttrs.virtualboxGuestAdditionsIso}" "$out/share/virtualbox/VBoxGuestAdditions.iso"
388 '';
389
390 preFixup =
391 optionalString (!headless) ''
392 wrapQtApp $out/bin/VirtualBox
393 ''
394 # If hardening is disabled, wrap the VirtualBoxVM binary instead of patching
395 # the source code (see postPatch).
396 + optionalString (!headless && !enableHardening) ''
397 wrapQtApp $out/libexec/virtualbox/VirtualBoxVM \
398 --prefix LD_LIBRARY_PATH : "${lib.makeLibraryPath [ vulkan-loader ]}"
399 '';
400
401 passthru = {
402 inherit extensionPack; # for inclusion in profile to prevent gc
403 tests = nixosTests.virtualbox;
404 updateScript = ./update.sh;
405 };
406
407 meta = {
408 description = "PC emulator";
409 longDescription = ''
410 VirtualBox is an x86 and AMD64/Intel64 virtualization product for enterprise and home use.
411
412 To install on NixOS, please use the option `virtualisation.virtualbox.host.enable = true`.
413 Please also check other options under `virtualisation.virtualbox`.
414 '';
415 sourceProvenance = with lib.sourceTypes; [
416 fromSource
417 binaryNativeCode
418 ];
419 license = lib.licenses.gpl3Only;
420 homepage = "https://www.virtualbox.org/";
421 maintainers = with lib.maintainers; [
422 sander
423 friedrichaltheide
424 blitz
425 ];
426 platforms = [ "x86_64-linux" ];
427 mainProgram = "VirtualBox";
428 };
429})