add a README.md to lib #52

Open
opened 2026-05-22 13:10:25 +00:00 by rc · 0 comments
Owner

libvmz

libvmz is the bridge layer that lets Zig boot a macOS
Virtualization.framework Linux VM without writing the VM host in Swift.

The Swift side owns the real VZVirtualMachine. The Zig side talks to it
through the small C ABI declared in libvmz.h.

Files

  • libvmz.swift: Swift implementation. It builds and starts the
    VZVirtualMachine, handles Virtualization.framework callbacks, and exports C symbols with @_cdecl.
  • libvmz.h: C header consumed by Zig, C, or C-compatible callers. This is the public ABI for the bridge.
  • examples/: standalone Zig example that links the Swift bridge directly.
  • extra/: older/minimal standalone Swift launcher and helper scripts. This is
    useful for comparing the pure Swift flow with the Zig-plus-bridge flow.

Why It Exists

Apple's VM APIs are exposed through Swift/Objective-C frameworks. vmz is a Zig
CLI, so it needs a narrow native bridge for the parts that must talk to
Virtualization.framework.

libvmz keeps that boundary small:

  • Zig handles CLI parsing, downloads, terminal mode, serial input forwarding, and user-facing VM options.
  • Swift handles VZLinuxBootLoader, VZVirtualMachineConfiguration,
    VZVirtualMachine, NAT networking, serial attachment, delegate callbacks, and
    the run loop needed for Virtualization.framework callbacks.

API Shape

The C API is intentionally opaque:

  • VMZConfig describes the VM: kernel path, initrd path, kernel command line, serial input pipe fd, CPU count, memory size, and NAT networking.
  • VMZHandle is an opaque Swift-managed VM engine pointer.
  • VMZErrorRef is an opaque Swift-managed error pointer.
  • vmz_validate_config() checks whether Virtualization.framework accepts aconfiguration.
  • vmz_create() creates the Swift VM engine and returns a VMZHandle.
  • vmz_start() starts the VM asynchronously.
  • vmz_request_stop() asks the guest to shut down gracefully.
  • vmz_force_stop() force-stops the VM asynchronously.
  • vmz_run_loop() enters the platform run loop so async VM callbacks can fire.

Callbacks report startup completion, graceful guest shutdown, and VM runtime errors.

Typical Lifecycle

  1. Create a host pipe for guest serial input.
  2. Fill VMZConfig, passing the pipe's read fd as read_pipe_fd.
  3. Call vmz_validate_config().
  4. Call vmz_create() and keep the returned VMZHandle.
  5. Register guest stop/error callbacks.
  6. Forward host terminal input into the pipe's write fd.
  7. Call vmz_start().
  8. Call vmz_run_loop() on the main thread.
  9. On exit, restore terminal state and free any returned VMZErrorRef.

See src/vmz.zig for the production caller and examples/main.zig for a smaller direct example.

Ownership Rules

  • Strings inside VMZConfig must be valid null-terminated UTF-8 strings for the
    duration of the call that receives the struct.
  • VMZHandle is owned by the Swift bridge. Callers must treat it as opaque and
    never dereference or free it directly.
  • VMZErrorRef values returned through callbacks or out-parameters are owned by
    the caller and must be released with vmz_error_free().
  • vmz_error_message() returns memory owned by the error object. Do not free the
    message pointer directly.
  • After a successful vmz_force_stop(), treat the VMZHandle as invalid.
  • Callback function pointers must remain valid for the lifetime of the VM.

Building

The top-level zig build compiles libvmz.swift into a static Swift library,
links it into the Zig executable, links the required Swift runtime libraries and
Apple frameworks, then signs the executable with the virtualization entitlement.

zig build
zig build run -- run

To build the standalone example:

cd lib/examples
zig build

The VM host requires Apple silicon macOS with Virtualization.framework
available and the app signed with the virtualization entitlement.

# libvmz `libvmz` is the bridge layer that lets Zig boot a macOS `Virtualization.framework` Linux VM without writing the VM host in Swift. The Swift side owns the real `VZVirtualMachine`. The Zig side talks to it through the small C ABI declared in `libvmz.h`. ## Files - `libvmz.swift`: Swift implementation. It builds and starts the `VZVirtualMachine`, handles Virtualization.framework callbacks, and exports C symbols with `@_cdecl`. - `libvmz.h`: C header consumed by Zig, C, or C-compatible callers. This is the public ABI for the bridge. - `examples/`: standalone Zig example that links the Swift bridge directly. - `extra/`: older/minimal standalone Swift launcher and helper scripts. This is useful for comparing the pure Swift flow with the Zig-plus-bridge flow. ## Why It Exists Apple's VM APIs are exposed through Swift/Objective-C frameworks. `vmz` is a Zig CLI, so it needs a narrow native bridge for the parts that must talk to `Virtualization.framework`. `libvmz` keeps that boundary small: - Zig handles CLI parsing, downloads, terminal mode, serial input forwarding, and user-facing VM options. - Swift handles `VZLinuxBootLoader`, `VZVirtualMachineConfiguration`, `VZVirtualMachine`, NAT networking, serial attachment, delegate callbacks, and the run loop needed for Virtualization.framework callbacks. ## API Shape The C API is intentionally opaque: - `VMZConfig` describes the VM: kernel path, initrd path, kernel command line, serial input pipe fd, CPU count, memory size, and NAT networking. - `VMZHandle` is an opaque Swift-managed VM engine pointer. - `VMZErrorRef` is an opaque Swift-managed error pointer. - `vmz_validate_config()` checks whether Virtualization.framework accepts aconfiguration. - `vmz_create()` creates the Swift VM engine and returns a `VMZHandle`. - `vmz_start()` starts the VM asynchronously. - `vmz_request_stop()` asks the guest to shut down gracefully. - `vmz_force_stop()` force-stops the VM asynchronously. - `vmz_run_loop()` enters the platform run loop so async VM callbacks can fire. Callbacks report startup completion, graceful guest shutdown, and VM runtime errors. ## Typical Lifecycle 1. Create a host pipe for guest serial input. 2. Fill `VMZConfig`, passing the pipe's read fd as `read_pipe_fd`. 3. Call `vmz_validate_config()`. 4. Call `vmz_create()` and keep the returned `VMZHandle`. 5. Register guest stop/error callbacks. 6. Forward host terminal input into the pipe's write fd. 7. Call `vmz_start()`. 8. Call `vmz_run_loop()` on the main thread. 9. On exit, restore terminal state and free any returned `VMZErrorRef`. See `src/vmz.zig` for the production caller and `examples/main.zig` for a smaller direct example. ## Ownership Rules - Strings inside `VMZConfig` must be valid null-terminated UTF-8 strings for the duration of the call that receives the struct. - `VMZHandle` is owned by the Swift bridge. Callers must treat it as opaque and never dereference or free it directly. - `VMZErrorRef` values returned through callbacks or out-parameters are owned by the caller and must be released with `vmz_error_free()`. - `vmz_error_message()` returns memory owned by the error object. Do not free the message pointer directly. - After a successful `vmz_force_stop()`, treat the `VMZHandle` as invalid. - Callback function pointers must remain valid for the lifetime of the VM. ## Building The top-level `zig build` compiles `libvmz.swift` into a static Swift library, links it into the Zig executable, links the required Swift runtime libraries and Apple frameworks, then signs the executable with the virtualization entitlement. ```sh zig build zig build run -- run ``` To build the standalone example: ```sh cd lib/examples zig build ``` The VM host requires Apple silicon macOS with `Virtualization.framework` available and the app signed with the virtualization entitlement.
Sign in to join this conversation.
No labels
highprio
lowprio
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
rc/vmz#52
No description provided.