`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.
87 lines
5.2 KiB
Markdown
87 lines
5.2 KiB
Markdown
# macOS
|
||
|
||
macOS is out of scope for v1 ([requirements.md](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](inference.md)). 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`](../../platform/dr-plat/src/dirs.rs)). 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](inference.md), and footnote ⁵ becomes a measurement.
|