1{ config, stdenv, fetchurl, lib, acpica-tools, dev86, pam, libxslt, libxml2, wrapQtAppsHook
2, libX11, xorgproto, libXext, libXcursor, libXmu, libIDL, SDL, libcap, libGL
3, libpng, glib, lvm2, libXrandr, libXinerama, libopus, qtbase, qtx11extras
4, qttools, qtsvg, qtwayland, pkg-config, which, docbook_xsl, docbook_xml_dtd_43
5, alsa-lib, curl, libvpx, nettools, dbus, substituteAll, gsoap, zlib
6# If open-watcom-bin is not passed, VirtualBox will fall back to use
7# the shipped alternative sources (assembly).
8, open-watcom-bin
9, makeself, perl
10, javaBindings ? true, jdk # Almost doesn't affect closure size
11, pythonBindings ? false, python3
12, extensionPack ? null, fakeroot
13, pulseSupport ? config.pulseaudio or stdenv.isLinux, libpulseaudio
14, enableHardening ? false
15, headless ? false
16, enable32bitGuests ? true
17, enableWebService ? false
18}:
19
20with lib;
21
22let
23 buildType = "release";
24 # Use maintainers/scripts/update.nix to update the version and all related hashes or
25 # change the hashes in extpack.nix and guest-additions/default.nix as well manually.
26 version = "6.1.28";
27in stdenv.mkDerivation {
28 pname = "virtualbox";
29 inherit version;
30
31 src = fetchurl {
32 url = "https://download.virtualbox.org/virtualbox/${version}/VirtualBox-${version}.tar.bz2";
33 sha256 = "8d34993d8e9c0cf35e7bd44dd26c8c757f17a3b7d5a64052f945d00fd798ebfe";
34 };
35
36 outputs = [ "out" "modsrc" ];
37
38 nativeBuildInputs = [ pkg-config which docbook_xsl docbook_xml_dtd_43 ]
39 ++ optional (!headless) wrapQtAppsHook;
40
41 # Wrap manually because we wrap just a small number of executables.
42 dontWrapQtApps = true;
43
44 buildInputs = [
45 acpica-tools dev86 libxslt libxml2 xorgproto libX11 libXext libXcursor libIDL
46 libcap glib lvm2 alsa-lib curl libvpx pam makeself perl
47 libXmu libpng libopus python3 ]
48 ++ optional javaBindings jdk
49 ++ optional pythonBindings python3 # Python is needed even when not building bindings
50 ++ optional pulseSupport libpulseaudio
51 ++ optionals headless [ libXrandr libGL ]
52 ++ optionals (!headless) [ qtbase qtx11extras libXinerama SDL ]
53 ++ optionals enableWebService [ gsoap zlib ];
54
55 hardeningDisable = [ "format" "fortify" "pic" "stackprotector" ];
56
57 prePatch = ''
58 set -x
59 sed -e 's@MKISOFS --version@MKISOFS -version@' \
60 -e 's@PYTHONDIR=.*@PYTHONDIR=${lib.optionalString pythonBindings python3}@' \
61 -e 's@CXX_FLAGS="\(.*\)"@CXX_FLAGS="-std=c++11 \1"@' \
62 ${optionalString (!headless) ''
63 -e 's@TOOLQT5BIN=.*@TOOLQT5BIN="${getDev qtbase}/bin"@' \
64 ''} -i configure
65 ls kBuild/bin/linux.x86/k* tools/linux.x86/bin/* | xargs -n 1 patchelf --set-interpreter ${stdenv.glibc.out}/lib/ld-linux.so.2
66 ls kBuild/bin/linux.amd64/k* tools/linux.amd64/bin/* | xargs -n 1 patchelf --set-interpreter ${stdenv.glibc.out}/lib/ld-linux-x86-64.so.2
67
68 grep 'libpulse\.so\.0' src include -rI --files-with-match | xargs sed -i -e '
69 ${optionalString pulseSupport
70 ''s@"libpulse\.so\.0"@"${libpulseaudio.out}/lib/libpulse.so.0"@g''}'
71
72 grep 'libdbus-1\.so\.3' src include -rI --files-with-match | xargs sed -i -e '
73 s@"libdbus-1\.so\.3"@"${dbus.lib}/lib/libdbus-1.so.3"@g'
74
75 grep 'libasound\.so\.2' src include -rI --files-with-match | xargs sed -i -e '
76 s@"libasound\.so\.2"@"${alsa-lib.out}/lib/libasound.so.2"@g'
77
78 export USER=nix
79 set +x
80 '';
81
82 patches =
83 optional enableHardening ./hardened.patch
84 ++ [ ./extra_symbols.patch ]
85 # When hardening is enabled, we cannot use wrapQtApp to ensure that VirtualBoxVM sees
86 # the correct environment variables needed for Qt to work, specifically QT_PLUGIN_PATH.
87 # This is because VirtualBoxVM would detect that it is wrapped that and refuse to run,
88 # and also because it would unset QT_PLUGIN_PATH for security reasons. We work around
89 # these issues by patching the code to set QT_PLUGIN_PATH to the necessary paths,
90 # after the code that unsets it. Note that qtsvg is included so that SVG icons from
91 # the user's icon theme can be loaded.
92 ++ optional (!headless && enableHardening) (substituteAll {
93 src = ./qt-env-vars.patch;
94 qtPluginPath = "${qtbase.bin}/${qtbase.qtPluginPrefix}:${qtsvg.bin}/${qtbase.qtPluginPrefix}:${qtwayland.bin}/${qtbase.qtPluginPrefix}";
95 })
96 ++ [
97 ./qtx11extras.patch
98 # https://github.com/NixOS/nixpkgs/issues/123851
99 ./fix-audio-driver-loading.patch
100 ];
101
102 postPatch = ''
103 sed -i -e 's|/sbin/ifconfig|${nettools}/bin/ifconfig|' \
104 src/VBox/HostDrivers/adpctl/VBoxNetAdpCtl.cpp
105 '' + optionalString headless ''
106 # Fix compile error in version 6.1.6
107 substituteInPlace src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-x11-stubs.cpp \
108 --replace PSHCLFORMATDATA PSHCLFORMATS
109 '';
110
111 # first line: ugly hack, and it isn't yet clear why it's a problem
112 configurePhase = ''
113 NIX_CFLAGS_COMPILE=$(echo "$NIX_CFLAGS_COMPILE" | sed 's,\-isystem ${lib.getDev stdenv.cc.libc}/include,,g')
114
115 cat >> LocalConfig.kmk <<LOCAL_CONFIG
116 VBOX_WITH_TESTCASES :=
117 VBOX_WITH_TESTSUITE :=
118 VBOX_WITH_VALIDATIONKIT :=
119 VBOX_WITH_DOCS :=
120 VBOX_WITH_WARNINGS_AS_ERRORS :=
121
122 VBOX_WITH_ORIGIN :=
123 VBOX_PATH_APP_PRIVATE_ARCH_TOP := $out/share/virtualbox
124 VBOX_PATH_APP_PRIVATE_ARCH := $out/libexec/virtualbox
125 VBOX_PATH_SHARED_LIBS := $out/libexec/virtualbox
126 VBOX_WITH_RUNPATH := $out/libexec/virtualbox
127 VBOX_PATH_APP_PRIVATE := $out/share/virtualbox
128 VBOX_PATH_APP_DOCS := $out/doc
129 ${optionalString javaBindings ''
130 VBOX_JAVA_HOME := ${jdk}
131 ''}
132 ${optionalString (!headless) ''
133 PATH_QT5_X11_EXTRAS_LIB := ${getLib qtx11extras}/lib
134 PATH_QT5_X11_EXTRAS_INC := ${getDev qtx11extras}/include
135 TOOL_QT5_LRC := ${getDev qttools}/bin/lrelease
136 ''}
137 ${optionalString enableWebService ''
138 # fix gsoap missing zlib include and produce errors with --as-needed
139 VBOX_GSOAP_CXX_LIBS := gsoapssl++ z
140 ''}
141 LOCAL_CONFIG
142
143 ./configure \
144 ${optionalString headless "--build-headless"} \
145 ${optionalString (!javaBindings) "--disable-java"} \
146 ${optionalString (!pythonBindings) "--disable-python"} \
147 ${optionalString (!pulseSupport) "--disable-pulse"} \
148 ${optionalString (!enableHardening) "--disable-hardening"} \
149 ${optionalString (!enable32bitGuests) "--disable-vmmraw"} \
150 ${optionalString enableWebService "--enable-webservice"} \
151 ${optionalString (open-watcom-bin != null) "--with-ow-dir=${open-watcom-bin}"} \
152 --disable-kmods
153 sed -e 's@PKG_CONFIG_PATH=.*@PKG_CONFIG_PATH=${libIDL}/lib/pkgconfig:${glib.dev}/lib/pkgconfig ${libIDL}/bin/libIDL-config-2@' \
154 -i AutoConfig.kmk
155 sed -e 's@arch/x86/@@' \
156 -i Config.kmk
157 substituteInPlace Config.kmk --replace "VBOX_WITH_TESTCASES = 1" "#"
158 '';
159
160 enableParallelBuilding = true;
161
162 buildPhase = ''
163 source env.sh
164 kmk -j $NIX_BUILD_CORES BUILD_TYPE="${buildType}"
165 '';
166
167 installPhase = ''
168 libexec="$out/libexec/virtualbox"
169 share="${if enableHardening then "$out/share/virtualbox" else "$libexec"}"
170
171 # Install VirtualBox files
172 mkdir -p "$libexec"
173 find out/linux.*/${buildType}/bin -mindepth 1 -maxdepth 1 \
174 -name src -o -exec cp -avt "$libexec" {} +
175
176 mkdir -p $out/bin
177 for file in ${optionalString (!headless) "VirtualBox VBoxSDL rdesktop-vrdp"} ${optionalString enableWebService "vboxwebsrv"} VBoxManage VBoxBalloonCtrl VBoxHeadless; do
178 echo "Linking $file to /bin"
179 test -x "$libexec/$file"
180 ln -s "$libexec/$file" $out/bin/$file
181 done
182
183 ${optionalString (extensionPack != null) ''
184 mkdir -p "$share"
185 "${fakeroot}/bin/fakeroot" "${stdenv.shell}" <<EOF
186 "$libexec/VBoxExtPackHelperApp" install \
187 --base-dir "$share/ExtensionPacks" \
188 --cert-dir "$share/ExtPackCertificates" \
189 --name "Oracle VM VirtualBox Extension Pack" \
190 --tarball "${extensionPack}" \
191 --sha-256 "${extensionPack.outputHash}"
192 EOF
193 ''}
194
195 ${optionalString (!headless) ''
196 # Create and fix desktop item
197 mkdir -p $out/share/applications
198 sed -i -e "s|Icon=VBox|Icon=$libexec/VBox.png|" $libexec/virtualbox.desktop
199 ln -sfv $libexec/virtualbox.desktop $out/share/applications
200 # Icons
201 mkdir -p $out/share/icons/hicolor
202 for size in `ls -1 $libexec/icons`; do
203 mkdir -p $out/share/icons/hicolor/$size/apps
204 ln -s $libexec/icons/$size/*.png $out/share/icons/hicolor/$size/apps
205 done
206 ''}
207
208 cp -rv out/linux.*/${buildType}/bin/src "$modsrc"
209 '';
210
211 preFixup = optionalString (!headless) ''
212 wrapQtApp $out/bin/VirtualBox
213 ''
214 # If hardening is disabled, wrap the VirtualBoxVM binary instead of patching
215 # the source code (see postPatch).
216 + optionalString (!headless && !enableHardening) ''
217 wrapQtApp $out/libexec/virtualbox/VirtualBoxVM
218 '';
219
220 passthru = {
221 inherit version; # for guest additions
222 inherit extensionPack; # for inclusion in profile to prevent gc
223 updateScript = ./update.sh;
224 };
225
226 meta = {
227 description = "PC emulator";
228 license = licenses.gpl2;
229 homepage = "https://www.virtualbox.org/";
230 maintainers = with maintainers; [ sander ];
231 platforms = [ "x86_64-linux" ];
232 };
233}