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