Skip to content

Building releases

The release build process is driven by scripts/build-release.sh. This script compiles all native dependencies from source, builds the Swift application in release mode, assembles the daemon install layout with all helper binaries and firmware, bundles dynamic libraries, code signs everything with the appropriate entitlements, and creates a distributable .pkg installer and standalone archive. Optionally, it notarizes the DMG with Apple.

Install the required build tools and libraries:

Terminal window
brew install meson ninja pkg-config glib pixman dylibbundler \
gnutls jpeg-turbo libpng libssh libusb zstd lzo snappy \
autoconf automake libtool json-glib

The script also checks for gawk and glibtoolize at runtime and will error with an install suggestion if any are missing.

A Python virtual environment is created automatically using uv. The distlib package is installed into it (required by the libtpms/swtpm build). You must have uv available on your PATH.

The frontend is built with bun. Ensure bun is installed before running the script.

  • APPLE_TEAM_ID — Your Apple Developer Team ID. This is injected into Sources/BarkVisorHelperProtocol/HelperProtocol.swift at build time so the XPC privileged helper can verify the code signature of the main app. The script will abort if this is not set.

The script performs the following steps in order:

Checks that all required CLI tools are present (meson, ninja, pkg-config, dylibbundler, autoconf, automake, glibtoolize, gawk). Creates a Python venv with distlib if one does not already exist.

Downloads and compiles QEMU (default version 10.2.2) configured for:

  • Target: aarch64-softmmu only
  • HVF (Hypervisor.framework) acceleration
  • VNC with JPEG and PNG support
  • Compression: zstd, lzo, snappy
  • libssh, libusb, and QEMU tools enabled
  • GUI backends disabled (no SDL, GTK, Cocoa, OpenGL, SPICE)
  • Docs and guest agent disabled

The build uses all available CPU cores. Homebrew keg-only package paths are automatically collected and passed to the configure step.

Downloads and compiles xz-utils (default version 5.8.2) as a static library. This provides the xz binary used for decompressing downloaded images.

Clones and builds libtpms (with OpenSSL and TPM2 support) and swtpm from their upstream GitHub repositories. A macOS-specific patch is applied to swtpm to replace SOCK_CLOEXEC (which does not exist on macOS) with 0.

Clones and builds socket_vmnet from the lima-vm project. This provides bridged networking for VMs via the macOS vmnet framework. The built socket_vmnet and socket_vmnet_client binaries are copied into the deps prefix.

Downloads the AAVMF secure boot firmware (AAVMF_CODE.secboot.fd) from an Ubuntu .deb package. The deb is extracted in a temporary directory and the firmware file is placed in the QEMU share directory.

Runs bun install and bun run build in the frontend/ directory to produce the static web UI assets.

Injects the real APPLE_TEAM_ID into HelperProtocol.swift (replacing the DEVELOPMENT placeholder) and the release version into Config.version via scripts/lib/inject-version.sh (replacing the in-tree 0.0.0-dev default, derived from the git tag / BARKVISOR_VERSION). Then runs swift build -c release. Both source files are restored afterward so the working tree stays clean.

Linux packages: the same inject runs before swift build in .github/workflows/linux-packages.yml and in Docker builds (BARKVISOR_VERSION / VERSION). Package metadata version alone does not change the binary; inject must happen at compile time.

This produces two executables:

  • .build/release/BarkVisorApp — the main application
  • .build/release/BarkVisorHelper — the privileged XPC helper daemon

Creates the staged install layout under build/stage/:

usr/local/
bin/
barkvisor (main server daemon)
libexec/barkvisor/
qemu-system-aarch64
qemu-img
swtpm
socket_vmnet
socket_vmnet_client
xz
mkisofs
lib/barkvisor/ (bundled dylibs, populated in step 9)
share/barkvisor/
templates.json
frontend/dist/ (web UI)
qemu/
edk2-aarch64-code.fd
AAVMF_CODE.secboot.fd
vgabios-ramfb.bin
vgabios-virtio.bin
efi-virtio.rom
keymaps/
Library/
LaunchDaemons/
dev.barkvisor.plist
dev.barkvisor.helper.plist
PrivilegedHelperTools/
dev.barkvisor.helper (XPC helper)

Runs dylibbundler against all Mach-O binaries in the staged layout (main executable, helper, and all helper binaries). This copies required dynamic libraries into lib/barkvisor/ and rewrites load paths. Extended attributes are stripped before and after this step, and duplicate LC_RPATH entries are deduplicated.

If SIGNING_IDENTITY is set, performs a full Developer ID code signing pass. If not set and --no-sign is not passed, ad-hoc signing is performed instead (sufficient for local use but not for distribution).

The entitlements applied to both the main app and helper binaries are:

  • com.apple.security.hypervisor — required for QEMU to use HVF
  • com.apple.security.network.server — required for the Vapor HTTP server
  • com.apple.security.network.client — required for outbound connections (image downloads, repository sync)

Signing order: shared libraries in lib/barkvisor/ first, then helper binaries in libexec/barkvisor/, then the XPC helper, then the main executable.

Creates a compressed tarball at build/BarkVisor-VERSION-standalone.tar.gz containing the staged install layout for manual extraction.

Builds a macOS installer package at build/BarkVisor-VERSION.pkg. The .pkg installs files to their system locations and can be signed with an INSTALLER_IDENTITY if provided. If SIGNING_IDENTITY, APPLE_ID, and APPLE_TEAM_ID are all set, the package is submitted for notarization using xcrun notarytool with the barkvisor-notarize keychain profile, and the notarization ticket is stapled. If credentials are missing and --require-notarize is passed, the script fails.

FlagEffect
--skip-depsSkip dependency builds; use previously cached artifacts
--no-signSkip all code signing
--no-pkgSkip installer .pkg creation
--require-notarizeFail if notarization credentials are missing
VariableRequiredDefaultDescription
APPLE_TEAM_IDYesApple Developer Team ID for XPC verification
SIGNING_IDENTITYNo(empty)Developer ID signing identity (e.g. "Developer ID Application: Name (TEAMID)")
APPLE_IDNo(empty)Apple ID email for notarization
BARKVISOR_VERSIONNo1.0.0Version string embedded in Info.plist and DMG name
QEMU_VERSIONNo10.2.2QEMU source version to download and build
XZ_VERSIONNo5.8.2xz-utils source version to download and build
QEMU_SHA256No(empty)Expected SHA-256 of the QEMU source tarball
XZ_SHA256No(empty)Expected SHA-256 of the xz source tarball

Variables can also be placed in a .env file at the project root. The script sources it if present, but explicit environment variables take precedence.

After a successful build, the following artifacts are produced:

  • build/stage/ — the staged install layout
  • build/BarkVisor-VERSION-standalone.tar.gz — standalone archive for manual installation
  • build/BarkVisor-VERSION.pkg — macOS installer package (unless --no-pkg was passed)

The build summary printed at the end includes the app bundle size, bundled helpers, framework count, and firmware file count.

Linux packages (deb / rpm / tarball / Arch)

Section titled “Linux packages (deb / rpm / tarball / Arch)”

macOS .pkg builds are separate from Linux multi-format packages. On a Linux build host (or via Docker from macOS):

Terminal window
swift build -c release --product BarkVisorApp
./scripts/linux-frontend-serve.sh
./scripts/build-linux-packages.sh
# → build/linux-packages/*.deb *.rpm *.tar.gz (+ Arch PKGBUILD)
# From macOS / CI with Docker (Ubuntu 24.04 builder):
./scripts/build-linux-packages.sh --docker
FormatTypical targets
.debUbuntu, Debian
.rpmFedora, Rocky, Alma, RHEL
.tar.gzAny glibc host (+ install.sh)
Arch PKGBUILDArch / Arch ARM

CI workflow Linux Packages (.github/workflows/linux-packages.yml) builds on tag v* or manual dispatch. Full install matrix, layout, and runtime notes: getting-started-linux.md and packaging/linux/README.md.

Linux packages ship the daemon, SPA, and Swift runtime. QEMU/OVMF come from the distro (Recommends). Bridged networking uses the host bridge path (no separate helper binary to bundle).