Files
DarkRoom/docs/dev/macos.md
dtourolle ff4b30fbaa Link the inference engine for macOS in a zig container
`docker/macos` builds for aarch64-apple-darwin from Linux with
cargo-zigbuild. Zig carries libSystem and the C headers, so tract's SIMD
kernels compile and the engine's test binaries and examples link as Mach-O
arm64 — the check `cargo check --target` could not do, because tract's
build script needs a macOS C compiler. Crates that link an Apple framework
(dr-plat's keyring, and so the app) still need the Xcode SDK and fail at
the link; macos.md says so.
2026-10-03 16:50:37 -04:00

5.2 KiB
Raw Permalink Blame History

macOS

macOS is out of scope for v1 (requirements.md), and nobody working on DarkRoom has a Mac. This page records what exists anyway, and how a macOS build is set up so that someone who does have one can send back enough to fix what they hit.

1. What exists

  • Inference (inference.md §2). The macOS ladder is CoreML, then ONNX Runtime's CPU provider, then tract. CoreML is unmeasured. The probe decides whether it is used, and the crash guard (§4, attempt) covers the case where the provider takes the process down. The device fingerprint is the chip (machdep.cpu.brand_string) and the OS release, because CoreML ships with the OS.
  • Where files go (dr_plat::dirs). The Unix rules, except the state directory (the log and crash records), which is ~/Library/Logs/darkroom.
  • A diagnostic build, described in §3.

The rest is not built, packaged or run on macOS by anyone here. This covers the window, Metal through wgpu, the display profile (FR-DSP-8 asks X11 and Wayland), the keyring, the bundle, and signing. dr-plat sends every non-Android Unix to the X11/Wayland dependencies.

2. Building

docker/macos compiles and links for macOS from Linux, using zig as the linker (cargo-zigbuild). Zig carries libSystem's stubs and the C headers, so tract's SIMD kernels compile and anything that needs only libSystem links:

./docker/macos/build.sh cargo zigbuild --target aarch64-apple-darwin -p dr-inference-engine --features native --all-targets
./docker/macos/build.sh cargo-zigbuild clippy --target aarch64-apple-darwin -p dr-inference-engine --features native --all-targets -- -D warnings

That produces Mach-O arm64 test binaries and the ladder and ep_probe examples. Nothing runs them. Anything that links an Apple framework needs the Xcode SDK, which zig does not carry. That includes dr-plat (through the keyring's Security and CoreFoundation) and so the desktop app, and its link fails with unable to find framework. cargo check for those still works in the container.

Linking the app needs Apple's SDK, which means a Mac. On one:

cargo build --profile diagnostic -p darkroom-desktop
./tools/fetch-desktop-runtime.sh      # ONNX Runtime 1.29.0 with CoreML, Apple silicon only

The fetch script puts libonnxruntime.dylib in the user's runtime/ directory, next to the models. The app also looks in Contents/Frameworks of its own bundle, and in Homebrew's /opt/homebrew/lib and /usr/local/lib. Homebrew's build may not include CoreML; the probe reports that as a failed rung and uses the CPU.

For whoever packages it. A notarised app runs with the hardened runtime, whose library validation refuses to dlopen a library signed by another team. A bundled Contents/Frameworks/libonnxruntime.dylib must be signed with the app. A runtime the user fetched needs the com.apple.security.cs.disable-library-validation entitlement, or it will not load, and the app will be the tract build without saying why beyond one log line.

3. The diagnostic build

Every macOS build is in the hands of someone who can send a log but cannot attach a debugger, so it is set up to log like a debug build while running at release speed.

  • The log says more. With no RUST_LOG, the desktop's default filter is debug for every dr_* crate, for darkroom_desktop, and for onnxruntime. That last one is ONNX Runtime's own session log, which the engine forwards into log on every platform (session.rs, with_runtime_log). At debug it includes how many nodes each provider took. At trace (RUST_LOG=onnxruntime=trace) it lists every node's placement, which is long. The log cap is the same as everywhere (two files of 4 MiB).
  • Backtraces have line numbers. --profile diagnostic is release plus line tables. On macOS the tables go into a .dSYM beside the executable, and the backtrace in a crash record finds them only if the .dSYM stays next to the binary. Keep it in the bundle.

4. What to ask a Mac user for

~/Library/Logs/darkroom/darkroom.log, plus darkroom.log.1 if present, after the first launch and after the first scan with faces. Console.app lists it under Log Reports. The Settings diagnostics bundle collects the same files. The lines that answer the open questions are:

Line What it tells us
inference: ONNX Runtime … from … / inference: runtime tract Whether a runtime was found, and which one
inference: floor … ms on the CPU provider The CPU number for §2's table
inference: CoreML session built in … s CoreML's first compile of the probe model
inference: CoreML rejected: … / failed: … Why the CPU was kept
onnxruntime lines naming CoreMLExecutionProvider::GetCapability How much of the graph CoreML took
inference: the app died during … The crash guard fired, and on what
inference: compiling … for CoreML / ready on CoreML in … s Each model's compile, and any that CoreML refused

Also ask for the settings row (Settings › About › Inference), which is one line and says the same in short. When one of these logs comes back with CoreML numbers, they go into inference.md §1–2, and footnote ⁵ becomes a measurement.