Files
2025-11-03 08:43:47 +01:00

430 lines
13 KiB
Nix

{
config,
stdenv,
fetchurl,
fetchpatch,
callPackage,
lib,
acpica-tools,
dev86,
pam,
libxslt,
libxml2,
libX11,
xorgproto,
libXext,
libXcursor,
libXfixes,
libXmu,
SDL2,
libcap,
libGL,
libGLU,
libpng,
glib,
lvm2,
libXrandr,
libXinerama,
libopus,
libtpms,
qt6,
pkg-config,
which,
docbook_xsl,
docbook_xml_dtd_43,
alsa-lib,
curl,
libvpx,
net-tools,
dbus,
replaceVars,
gsoap,
zlib,
xz,
yasm,
glslang,
nixosTests,
# If open-watcom-bin is not passed, VirtualBox will fall back to use
# the shipped alternative sources (assembly).
open-watcom-bin,
makeself,
perl,
javaBindings ? true,
jdk, # Almost doesn't affect closure size
pythonBindings ? false,
python3,
extensionPack ? null,
fakeroot,
pulseSupport ? config.pulseaudio or stdenv.hostPlatform.isLinux,
libpulseaudio,
enableHardening ? false,
headless ? false,
enable32bitGuests ? true,
enableWebService ? false,
enableKvm ? false,
extraConfigureFlags ? "",
}:
# The web services use Java infrastructure.
assert enableWebService -> javaBindings;
let
buildType = "release";
# Use maintainers/scripts/update.nix to update the version and all related hashes or
# change the hashes in extpack.nix and guest-additions/default.nix as well manually.
virtualboxVersion = "7.2.4";
virtualboxSubVersion = "";
virtualboxSha256 = "d281ec981b5f580211a0cedd1b75a1adcb0fbfcbb768d8c2bf4429f4763e8bbd";
kvmPatchVboxVersion = "7.2.4";
kvmPatchVersion = "20251103";
kvmPatchHash = "sha256-VhSuRYiZLg8hIGatf27u/nBBBtB1zz4ePxtiRYy84Hw=";
# The KVM build is not compatible to VirtualBox's kernel modules. So don't export
# modsrc at all.
withModsrc = !enableKvm;
virtualboxGuestAdditionsIso = callPackage guest-additions-iso/default.nix {
inherit virtualboxVersion;
};
inherit (lib)
optional
optionals
optionalString
getDev
getLib
;
inherit (qt6)
qtbase
qttools
qtsvg
qtwayland
qtscxml
wrapQtAppsHook
;
in
stdenv.mkDerivation (finalAttrs: {
pname = "virtualbox";
version = "${finalAttrs.virtualboxVersion}${finalAttrs.virtualboxSubVersion}";
inherit
buildType
virtualboxVersion
virtualboxSubVersion
virtualboxSha256
kvmPatchVersion
kvmPatchHash
virtualboxGuestAdditionsIso
;
src = fetchurl {
url = "https://download.virtualbox.org/virtualbox/${finalAttrs.virtualboxVersion}/VirtualBox-${finalAttrs.virtualboxVersion}${finalAttrs.virtualboxSubVersion}.tar.bz2";
sha256 = finalAttrs.virtualboxSha256;
};
outputs = [ "out" ] ++ optional withModsrc "modsrc";
nativeBuildInputs = [
pkg-config
which
docbook_xsl
docbook_xml_dtd_43
yasm
glslang
]
++ optional (!headless) wrapQtAppsHook;
# Wrap manually because we wrap just a small number of executables.
dontWrapQtApps = true;
buildInputs = [
acpica-tools
dev86
libxslt
libxml2
xorgproto
libX11
libXext
libXcursor
libcap
glib
lvm2
alsa-lib
curl
libvpx
pam
makeself
perl
libXmu
libXrandr
libpng
libopus
libtpms
python3
xz
libGL
]
++ optional javaBindings jdk
++ optional pythonBindings python3 # Python is needed even when not building bindings
++ optional pulseSupport libpulseaudio
++ optionals (!headless) [
qtbase
qttools
qtscxml
libXinerama
SDL2
libGLU
]
++ optionals enableWebService [
gsoap
zlib
];
hardeningDisable = [
"format"
"fortify"
"pic"
"stackprotector"
];
prePatch = ''
set -x
sed -e 's@MKISOFS --version@MKISOFS -version@' \
-e 's@PYTHONDIR=.*@PYTHONDIR=${optionalString pythonBindings python3}@' \
-e 's@CXX_FLAGS="\(.*\)"@CXX_FLAGS="-std=c++11 \1"@' \
${
optionalString (!headless) ''
-e 's@TOOLQT6BIN=.*@TOOLQT6BIN="${getDev qttools}/bin"@' \
''
} -i configure
ls kBuild/bin/linux.x86/k* tools/linux.x86/bin/* | xargs -n 1 patchelf --set-interpreter ${stdenv.cc.libc}/lib/ld-linux.so.2
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
grep 'libpulse\.so\.0' src include -rI --files-with-match | xargs sed -i -e '
${optionalString pulseSupport ''s@"libpulse\.so\.0"@"${libpulseaudio.out}/lib/libpulse.so.0"@g''}'
grep 'libdbus-1\.so\.3' src include -rI --files-with-match | xargs sed -i -e '
s@"libdbus-1\.so\.3"@"${dbus.lib}/lib/libdbus-1.so.3"@g'
grep 'libXfixes\.so\.3' src include -rI --files-with-match | xargs sed -i -e '
s@"libXfixes\.so\.3"@"${libXfixes.out}/lib/libXfixes.so.3"@g'
grep 'libasound\.so\.2' src include -rI --files-with-match | xargs sed -i -e '
s@"libasound\.so\.2"@"${alsa-lib.out}/lib/libasound.so.2"@g'
substituteInPlace src/VBox/Devices/Graphics/DevVGA-SVGA3d-glLdr.cpp \
--replace-fail \"libGL.so.1\" \"${libGL.out}/lib/libGL.so.1\"
export USER=nix
set +x
'';
patches =
optional enableHardening ./hardened.patch
# Since VirtualBox 7.0.8, VBoxSDL requires SDL2, but the build framework uses SDL1
++ optionals (!headless) [
./fix-sdl.patch
# No update patch disables check for update function
# https://bugs.launchpad.net/ubuntu/+source/virtualbox-ose/+bug/272212
(fetchpatch {
url = "https://salsa.debian.org/pkg-virtualbox-team/virtualbox/-/raw/8028d88e6876ca5977de13c58b54e243229efe98/debian/patches/16-no-update.patch";
hash = "sha256-AGtFsRjwd8Yw296eqX3NC2TUptAhpFTRaOMutiheQ6Y=";
})
]
++ [ ./extra_symbols.patch ]
# When hardening is enabled, we cannot use wrapQtApp to ensure that VirtualBoxVM sees
# the correct environment variables needed for Qt to work, specifically QT_PLUGIN_PATH.
# This is because VirtualBoxVM would detect that it is wrapped that and refuse to run,
# and also because it would unset QT_PLUGIN_PATH for security reasons. We work around
# these issues by patching the code to set QT_PLUGIN_PATH to the necessary paths,
# after the code that unsets it. Note that qtsvg is included so that SVG icons from
# the user's icon theme can be loaded.
++ optional (!headless && enableHardening) (
replaceVars ./qt-env-vars.patch {
qtPluginPath = "${qtbase}/bin/${qtbase.qtPluginPrefix}:${qtsvg}/bin/${qtbase.qtPluginPrefix}:${qtwayland}/bin/${qtbase.qtPluginPrefix}";
}
)
# While the KVM patch should not break any other behavior if --with-kvm is not specified,
# we don't take any chances and only apply it if people actually want to use KVM support.
++ optional enableKvm (fetchpatch {
name = "virtualbox-${finalAttrs.virtualboxVersion}-kvm-dev-${finalAttrs.kvmPatchVersion}.patch";
url = "https://github.com/cyberus-technology/virtualbox-kvm/releases/download/dev-${finalAttrs.kvmPatchVersion}/kvm-backend-${kvmPatchVboxVersion}-dev-${finalAttrs.kvmPatchVersion}.patch";
hash = finalAttrs.kvmPatchHash;
})
++ [
./qt-dependency-paths.patch
# https://github.com/NixOS/nixpkgs/issues/123851
./fix-audio-driver-loading.patch
# curl 8.16 upgrade breakage
(fetchpatch {
url = "https://salsa.debian.org/pkg-virtualbox-team/virtualbox/-/raw/dbf9a6ef75380ebd2705df0198c6ac8073d0b4cb/debian/patches/new-curl.patch";
hash = "sha256-WWnCWdXlJo9jTr8yXA0NxcDQBScryuu/53wyX0rhszk=";
})
];
postPatch = ''
sed -i -e 's|/sbin/ifconfig|${net-tools}/bin/ifconfig|' \
src/VBox/HostDrivers/adpctl/VBoxNetAdpCtl.cpp
'';
# first line: ugly hack, and it isn't yet clear why it's a problem
configurePhase = ''
NIX_CFLAGS_COMPILE=$(echo "$NIX_CFLAGS_COMPILE" | sed 's,\-isystem ${lib.getDev stdenv.cc.libc}/include,,g')
cat >> LocalConfig.kmk <<LOCAL_CONFIG
VBOX_WITH_TESTCASES :=
VBOX_WITH_TESTSUITE :=
VBOX_WITH_VALIDATIONKIT :=
VBOX_WITH_DOCS :=
VBOX_WITH_WARNINGS_AS_ERRORS :=
VBOX_WITH_ORIGIN :=
VBOX_PATH_APP_PRIVATE_ARCH_TOP := $out/share/virtualbox
VBOX_PATH_APP_PRIVATE_ARCH := $out/libexec/virtualbox
VBOX_PATH_SHARED_LIBS := $out/libexec/virtualbox
VBOX_WITH_RUNPATH := $out/libexec/virtualbox
VBOX_PATH_APP_PRIVATE := $out/share/virtualbox
VBOX_PATH_APP_DOCS := $out/doc
VBOX_WITH_UPDATE_AGENT :=
${optionalString javaBindings ''
VBOX_JAVA_HOME := ${jdk}
''}
${optionalString (!headless) ''
VBOX_WITH_VBOXSDL := 1
PATH_QT6_TOOLS_LIB := ${getLib qttools}/lib
PATH_QT6_TOOLS_INC := ${getLib qttools}/include
PATH_QT6_SCXML_LIB := ${getLib qtscxml}/lib
PATH_QT6_SCXML_INC := ${getLib qtscxml}/include
VBOX_PATH_QT := ${getLib qttools}/
''}
${optionalString enableWebService ''
# fix gsoap missing zlib include and produce errors with --as-needed
VBOX_GSOAP_CXX_LIBS := gsoapssl++ z
''}
TOOL_QT6_LRC := ${getLib qttools}/bin/lrelease
LOCAL_CONFIG
./configure \
${optionalString headless "--build-headless"} \
${optionalString (!javaBindings) "--disable-java"} \
${optionalString (!pythonBindings) "--disable-python"} \
${optionalString (!pulseSupport) "--disable-pulse"} \
${optionalString (!enableHardening) "--disable-hardening"} \
${optionalString (!enable32bitGuests) "--disable-vmmraw"} \
${optionalString enableWebService "--enable-webservice"} \
${optionalString (open-watcom-bin != null) "--with-ow-dir=${open-watcom-bin}"} \
${optionalString enableKvm "--with-kvm"} \
${extraConfigureFlags} \
--disable-kmods
sed -e 's@PKG_CONFIG_PATH=.*@PKG_CONFIG_PATH=${glib.dev}/lib/pkgconfig@' \
-i AutoConfig.kmk
sed -e 's@arch/x86/@@' \
-i Config.kmk
substituteInPlace Config.kmk --replace-fail "VBOX_WITH_TESTCASES = 1" "#"
'';
enableParallelBuilding = true;
buildPhase = ''
source env.sh
kmk -j $NIX_BUILD_CORES BUILD_TYPE="${finalAttrs.buildType}"
'';
installPhase = ''
libexec="$out/libexec/virtualbox"
share="${if enableHardening then "$out/share/virtualbox" else "$libexec"}"
# Install VirtualBox files
mkdir -p "$libexec"
find out/linux.*/${finalAttrs.buildType}/bin -mindepth 1 -maxdepth 1 \
-name src -o -exec cp -avt "$libexec" {} +
mkdir -p $out/bin
for file in ${
optionalString (!headless) "VirtualBox VBoxSDL"
} ${optionalString enableWebService "vboxwebsrv"} VBoxManage VBoxBalloonCtrl VBoxHeadless; do
echo "Linking $file to /bin"
test -x "$libexec/$file"
ln -s "$libexec/$file" $out/bin/$file
done
${optionalString (extensionPack != null) ''
mkdir -p "$share"
"${fakeroot}/bin/fakeroot" "${stdenv.shell}" <<EOF
"$libexec/VBoxExtPackHelperApp" install \
--base-dir "$share/ExtensionPacks" \
--cert-dir "$share/ExtPackCertificates" \
--name "Oracle VirtualBox Extension Pack" \
--tarball "${extensionPack}" \
--sha-256 "${extensionPack.outputHash}"
EOF
''}
${optionalString (!headless) ''
# Create and fix desktop item
mkdir -p $out/share/applications
sed -i -e "s|Icon=VBox|Icon=$libexec/VBox.png|" $libexec/virtualbox.desktop
ln -sfv $libexec/virtualbox.desktop $out/share/applications
# Icons
mkdir -p $out/share/icons/hicolor
for size in `ls -1 $libexec/icons`; do
mkdir -p $out/share/icons/hicolor/$size/apps
ln -s $libexec/icons/$size/*.png $out/share/icons/hicolor/$size/apps
done
# Translation
mkdir -p "$out/share/virtualbox"
ln -sv $libexec/nls "$out/share/virtualbox/nls"
''}
${optionalString withModsrc ''
cp -rv out/linux.*/${finalAttrs.buildType}/bin/src "$modsrc"
''}
mkdir -p "$out/share/virtualbox"
cp -rv src/VBox/Main/UnattendedTemplates "$out/share/virtualbox"
ln -s "${finalAttrs.virtualboxGuestAdditionsIso}" "$out/share/virtualbox/VBoxGuestAdditions.iso"
'';
preFixup =
optionalString (!headless) ''
wrapQtApp $out/bin/VirtualBox
''
# If hardening is disabled, wrap the VirtualBoxVM binary instead of patching
# the source code (see postPatch).
+ optionalString (!headless && !enableHardening) ''
wrapQtApp $out/libexec/virtualbox/VirtualBoxVM
'';
passthru = {
inherit extensionPack; # for inclusion in profile to prevent gc
tests = nixosTests.virtualbox;
updateScript = ./update.sh;
};
meta = {
description = "PC emulator";
longDescription = ''
VirtualBox is an x86 and AMD64/Intel64 virtualization product for enterprise and home use.
To install on NixOS, please use the option `virtualisation.virtualbox.host.enable = true`.
Please also check other options under `virtualisation.virtualbox`.
'';
sourceProvenance = with lib.sourceTypes; [
fromSource
binaryNativeCode
];
license = lib.licenses.gpl3Only;
homepage = "https://www.virtualbox.org/";
maintainers = with lib.maintainers; [
sander
friedrichaltheide
blitz
];
platforms = [ "x86_64-linux" ];
mainProgram = "VirtualBox";
};
})