From 5b5640a83aa5de30c137c3a7cdb612955f7906cf Mon Sep 17 00:00:00 2001 From: Roberto Nibali Date: Wed, 8 Jul 2026 13:13:09 +0200 Subject: [PATCH 1/3] doc: add macOS Arm runnable build notes Document a local macOS/Arm workflow for configuring, building selected host-side targets, staging a runnable app bundle, and applying the signing order and entitlement choices needed for developer testing. This is explicitly a local non-packaging workflow and leaves the Darwin installer and release signing paths unchanged. Signed-off-by: Roberto Nibali --- doc/technical/DarwinArmRunnableBuild.wiki | 185 ++++++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 doc/technical/DarwinArmRunnableBuild.wiki diff --git a/doc/technical/DarwinArmRunnableBuild.wiki b/doc/technical/DarwinArmRunnableBuild.wiki new file mode 100644 index 000000000000..342c9d7671a7 --- /dev/null +++ b/doc/technical/DarwinArmRunnableBuild.wiki @@ -0,0 +1,185 @@ +Please feel free to send documentation patches to the vbox-dev [https://www.virtualbox.org/wiki/Mailing_lists mailing list]. + += Local macOS/Arm runnable build notes = + +These notes describe a local workflow for building and running a test +!VirtualBox.app on macOS/Arm while iterating on host-side code. This is not a +distribution packaging recipe. The official packaging and release signing path +remains in `src/VBox/Installer/darwin/Makefile.kmk`. + +The workflow below is intended for non-hardened OSE developer builds using +Xcode command line tools, Homebrew packages and ad-hoc or local Developer ID +signing. + +== Configure == + +Configure once and source the generated environment file before running `kmk`. + +{{{ +./configure.py \ + --disable-hardening \ + --with-kbuild-path="$PWD/kBuild/kBuild" \ + --with-macossdk-path="$(xcrun --sdk macosx --show-sdk-path)" \ + --with-xcode-path=/Library/Developer/CommandLineTools \ + --with-qt-path=/opt/homebrew + +source ./env.sh +}}} + +The generated `env.sh` must be valid to source even when the host environment +contains paths with spaces. + +== Local tool overrides == + +The source tree normally expects Oracle-style bundled tool trees under +`tools/darwin.arm64`, including a `clang/v*` tree and SDK directory names such +as `MacOSX11.0.sdk` and `MacOSX14.5.sdk`. A local Xcode-only machine can still +build selected host-side targets by making those paths explicit. + +{{{ +SDK="$(xcrun --sdk macosx --show-sdk-path)" +XCBIN="$(dirname "$(xcrun --find clang)")" + +KMK_DARWIN_ARM_LOCAL=" +PATH_SDK_MACOSX110=$SDK +PATH_SDK_MACOSX145=$SDK +PATH_TOOL_VBoxXClangMacho=$XCBIN +TOOL_VBoxXClangMacho_AR=$XCBIN/ar +TOOL_VBoxXClangMacho_STRIP=$XCBIN/strip +" +}}} + +== Build a target == + +For example, to build the host-side DXMT library with a specific LLVM +installation: + +{{{ +source ./env.sh + +kmk VBoxDxMt \ + VBOX_LLVM_PATH=/opt/homebrew/opt/llvm@15 \ + VBOX_LLVM_CONFIG=/opt/homebrew/opt/llvm@15/bin/llvm-config \ + $KMK_DARWIN_ARM_LOCAL +}}} + +The resulting library is installed into: + +{{{ +out/darwin.arm64/release/dist/VirtualBox.app/Contents/MacOS/VBoxDxMt.dylib +}}} + +== Stage a runnable app == + +For a fresh local run, copy the staged app bundle out of the build tree: + +{{{ +RUNROOT=/tmp/vbox-local-run +APP="$RUNROOT/VirtualBox.app" + +rm -rf "$RUNROOT" +mkdir -p "$RUNROOT" +ditto out/darwin.arm64/release/dist/VirtualBox.app "$APP" +}}} + +For a fast single-library refresh into an already copied app, replace only the +rebuilt image: + +{{{ +install -m 755 \ + out/darwin.arm64/release/dist/VirtualBox.app/Contents/MacOS/VBoxDxMt.dylib \ + "$APP/Contents/MacOS/VBoxDxMt.dylib" +}}} + +Do not replace binaries in a running VM process. Shut the VM down first. + +== Signing and entitlements == + +macOS VM execution needs the VM process entitlements generated by the build +system: + +{{{ +out/darwin.arm64/release/Entitlements.plist +out/darwin.arm64/release/EntitlementsVM.plist +}}} + +For normal ad-hoc kBuild signing, use `VBOX_SIGNING_MODE=adhoc`. The build +system signs VM process binaries with `EntitlementsVM.plist` and the Darwin +installer makefile signs bundles from the inside out. The installer makefile +also documents the important hardened-runtime detail: `--deep` can lose +entitlements, so VM and app bundles are signed again without `--deep`. + +For a local copied test app that loads locally rebuilt dylibs under hardened +runtime, the VM process may also need library validation disabled. Use a local +VM entitlement file like this one: + +{{{ +cat > /tmp/vbox-local-vm.entitlements.plist <<'EOF' + + + + + com.apple.security.cs.allow-jit + com.apple.security.cs.allow-unsigned-executable-memory + com.apple.security.cs.disable-executable-page-protection + com.apple.security.cs.disable-library-validation + com.apple.security.device.audio-input + com.apple.security.device.camera + com.apple.security.device.usb + com.apple.security.hypervisor + + +EOF +}}} + +Do not add `com.apple.vm.device-access` or `com.apple.vm.networking` to ad-hoc +or local Developer ID test entitlements. They are release-signing entitlements +reserved for specifically provisioned vendors and can make local builds fail +with code signing errors. + +Sign changed Mach-O images first, then nested VM bundles, then the outer app +bundle. Use `-` for ad-hoc signing, or set `IDENTITY` to a local Developer ID +identity when that is useful for testing. + +{{{ +IDENTITY="${IDENTITY:--}" +VM_ENT=/tmp/vbox-local-vm.entitlements.plist +APP_ENT=out/darwin.arm64/release/Entitlements.plist + +codesign --force --options runtime --timestamp=none \ + --sign "$IDENTITY" \ + "$APP/Contents/MacOS/VBoxDxMt.dylib" + +codesign --force --options runtime --timestamp=none \ + --sign "$IDENTITY" \ + --entitlements "$VM_ENT" \ + "$APP/Contents/Resources/VirtualBoxVM.app/Contents/MacOS/VirtualBoxVM" + +codesign --force --options runtime --timestamp=none \ + --sign "$IDENTITY" \ + --entitlements "$VM_ENT" \ + "$APP/Contents/Resources/VirtualBoxVM.app" + +codesign --force --options runtime --timestamp=none \ + --sign "$IDENTITY" \ + --entitlements "$APP_ENT" \ + "$APP" +}}} + +== Verify and run == + +Inspect the final signatures and selected dynamic library links: + +{{{ +codesign -d -vv --entitlements :- \ + "$APP/Contents/Resources/VirtualBoxVM.app/Contents/MacOS/VirtualBoxVM" + +otool -L "$APP/Contents/MacOS/VBoxDxMt.dylib" +}}} + +Then start a test VM from the copied app bundle: + +{{{ +"$APP/Contents/MacOS/VBoxManage" startvm "" --type gui +}}} From 12193cd55d9d6702b461f531b4e094f75897a845 Mon Sep 17 00:00:00 2001 From: Roberto Nibali Date: Thu, 9 Jul 2026 01:03:50 +0200 Subject: [PATCH 2/3] doc: mention Homebrew Qt libexec tools Signed-off-by: Roberto Nibali --- doc/technical/DarwinArmRunnableBuild.wiki | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/technical/DarwinArmRunnableBuild.wiki b/doc/technical/DarwinArmRunnableBuild.wiki index 342c9d7671a7..b627a5155662 100644 --- a/doc/technical/DarwinArmRunnableBuild.wiki +++ b/doc/technical/DarwinArmRunnableBuild.wiki @@ -39,6 +39,7 @@ build selected host-side targets by making those paths explicit. {{{ SDK="$(xcrun --sdk macosx --show-sdk-path)" XCBIN="$(dirname "$(xcrun --find clang)")" +QTBIN=/opt/homebrew/share/qt/libexec KMK_DARWIN_ARM_LOCAL=" PATH_SDK_MACOSX110=$SDK @@ -46,9 +47,15 @@ PATH_SDK_MACOSX145=$SDK PATH_TOOL_VBoxXClangMacho=$XCBIN TOOL_VBoxXClangMacho_AR=$XCBIN/ar TOOL_VBoxXClangMacho_STRIP=$XCBIN/strip +PATH_TOOL_QT6_BIN=$QTBIN " }}} +Some Homebrew Qt installations expose `moc`, `rcc` and `uic` through +`/opt/homebrew/share/qt/libexec` rather than `/opt/homebrew/bin`. If `kmk` +fails while generating Qt resources with `/opt/homebrew/bin/rcc: Command not +found`, keep `PATH_TOOL_QT6_BIN` pointed at the libexec directory above. + == Build a target == For example, to build the host-side DXMT library with a specific LLVM From 0cc0945b54139bdbd43de9c4be673fd9a671d304 Mon Sep 17 00:00:00 2001 From: Roberto Nibali Date: Thu, 9 Jul 2026 09:41:26 +0200 Subject: [PATCH 3/3] doc: prefer stable signing for local runs Signed-off-by: Roberto Nibali --- doc/technical/DarwinArmRunnableBuild.wiki | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/doc/technical/DarwinArmRunnableBuild.wiki b/doc/technical/DarwinArmRunnableBuild.wiki index b627a5155662..a37df95bde36 100644 --- a/doc/technical/DarwinArmRunnableBuild.wiki +++ b/doc/technical/DarwinArmRunnableBuild.wiki @@ -8,8 +8,7 @@ distribution packaging recipe. The official packaging and release signing path remains in `src/VBox/Installer/darwin/Makefile.kmk`. The workflow below is intended for non-hardened OSE developer builds using -Xcode command line tools, Homebrew packages and ad-hoc or local Developer ID -signing. +Xcode command line tools, Homebrew packages and ad-hoc or local code signing. == Configure == @@ -87,8 +86,13 @@ APP="$RUNROOT/VirtualBox.app" rm -rf "$RUNROOT" mkdir -p "$RUNROOT" ditto out/darwin.arm64/release/dist/VirtualBox.app "$APP" +rm -rf "$APP/Contents/MacOS/testcase" }}} +The testcase payload is not needed for a copied GUI VM run. Removing it keeps +the local app-signing step focused on runnable product binaries and avoids +recursive signing failures on non-code testcase directories. + For a fast single-library refresh into an already copied app, replace only the rebuilt image: @@ -141,16 +145,21 @@ EOF }}} Do not add `com.apple.vm.device-access` or `com.apple.vm.networking` to ad-hoc -or local Developer ID test entitlements. They are release-signing entitlements +or ordinary local test entitlements. They are release-signing entitlements reserved for specifically provisioned vendors and can make local builds fail with code signing errors. Sign changed Mach-O images first, then nested VM bundles, then the outer app -bundle. Use `-` for ad-hoc signing, or set `IDENTITY` to a local Developer ID -identity when that is useful for testing. +bundle. Prefer a stable local code-signing identity for repeated local runs. +Identity-aware network filters such as Little Snitch track ad-hoc-signed +programs by code hash, so every rebuilt `VirtualBoxVM` can otherwise look like +a modified program and trigger a network identity warning. If no local signing +identity is available, the snippet falls back to ad-hoc signing. {{{ -IDENTITY="${IDENTITY:--}" +IDENTITY="${IDENTITY:-$(security find-identity -v -p codesigning | \ + sed -n 's/.*"\([^"]*\)".*/\1/p' | head -n 1)}" +: "${IDENTITY:=-}" VM_ENT=/tmp/vbox-local-vm.entitlements.plist APP_ENT=out/darwin.arm64/release/Entitlements.plist