diff --git a/doc/technical/DarwinArmRunnableBuild.wiki b/doc/technical/DarwinArmRunnableBuild.wiki new file mode 100644 index 000000000000..a37df95bde36 --- /dev/null +++ b/doc/technical/DarwinArmRunnableBuild.wiki @@ -0,0 +1,201 @@ +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 code 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)")" +QTBIN=/opt/homebrew/share/qt/libexec + +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 +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 +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" +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: + +{{{ +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 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. 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:-$(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 + +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 +}}}