0ef5fcb1c5
Security / Dependency audit (pip-audit) (push) Has been cancelled
Security / CodeQL (javascript-typescript) (push) Has been cancelled
Security / CodeQL (python) (push) Has been cancelled
Security / Secret scan (gitleaks) (push) Has been cancelled
rust / test (ubuntu) (push) Has been cancelled
rust / simulator e2e (macos-latest) (push) Has been cancelled
rust / simulator e2e (ubuntu-latest) (push) Has been cancelled
rust / simulator e2e (windows-latest) (push) Has been cancelled
rust / wheels (aarch64-apple-darwin) (push) Has been cancelled
rust / wheels (x86_64-unknown-linux-gnu) (push) Has been cancelled
rust / wheels (x86_64-apple-darwin) (push) Has been cancelled
rust / audit (push) Has been cancelled
rust / parity (nightly, allowed to fail during Phase 0) (push) Has been cancelled
CI / commitlint (push) Has been skipped
Dev Containers / validate (.devcontainer/devcontainer.json, default) (push) Failing after 0s
Dev Containers / validate (.devcontainer/memory-stack/devcontainer.json, memory-stack) (push) Failing after 0s
Dev Containers / validate-worktree (push) Failing after 0s
CI / changes (push) Failing after 4s
Deploy Documentation / validate (push) Has been skipped
Deploy Documentation / deploy (push) Failing after 1s
Init Native E2E / init-native (ubuntu-latest, claude) (push) Failing after 1s
Init Native E2E / init-native (ubuntu-latest, codex) (push) Failing after 1s
Install Native E2E / install-native (ubuntu-latest) (push) Failing after 1s
OpenCode Plugin / typecheck + build + test (push) Failing after 1s
Init Native E2E / init-native (ubuntu-latest, copilot) (push) Failing after 1s
Release Please / release-please (push) Failing after 1s
Wrap E2E / docker-wrap-e2e (push) Failing after 1s
Wrap Native E2E / wrap-native (ubuntu-latest) (push) Failing after 1s
Init E2E / docker-init-e2e (push) Failing after 4s
Merge Conflicts / merge-conflicts (push) Failing after 4s
CI / lint (push) Has been cancelled
CI / build-wheel (push) Has been cancelled
CI / build-wheel-windows (push) Has been cancelled
CI / prefetch-model (push) Has been cancelled
CI / test-dashboard-ui (push) Has been cancelled
CI / test (1) (push) Has been cancelled
CI / test (2) (push) Has been cancelled
CI / test (3) (push) Has been cancelled
CI / test (4) (push) Has been cancelled
CI / test-extras (push) Has been cancelled
CI / test-agno (push) Has been cancelled
CI / build (push) Has been cancelled
CI / workflow-validation (push) Has been cancelled
CI / docker-native-e2e (push) Has been cancelled
CI / windows-native-wrapper (push) Has been cancelled
CI / macos-native-wrapper (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-code-nonroot name:code-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-code-slim name:code-slim]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-code-slim-nonroot name:code-slim-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-nonroot name:nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-slim name:slim]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-slim-nonroot name:slim-nonroot]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime name:]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-code name:code]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-code-nonroot name:code-nonroot]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-code-slim name:code-slim]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-code-slim-nonroot name:code-slim-nonroot]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-nonroot name:nonroot]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-slim name:slim]) (push) Has been cancelled
Docker / docker-manifest (map[bake_target:runtime-slim-nonroot name:slim-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime name:]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-code name:code]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-code-nonroot name:code-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-code-slim name:code-slim]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-code-slim-nonroot name:code-slim-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-nonroot name:nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-slim name:slim]) (push) Has been cancelled
Docker / docker-build (map[name:amd64 platform:linux/amd64 runs_on:ubuntu-24.04], map[bake_target:runtime-slim-nonroot name:slim-nonroot]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime name:]) (push) Has been cancelled
Docker / docker-build (map[name:arm64 platform:linux/arm64 runs_on:ubuntu-24.04-arm], map[bake_target:runtime-code name:code]) (push) Has been cancelled
Docker / promote-latest (push) Has been cancelled
Init Native E2E / init-native (macos-latest, claude) (push) Has been cancelled
Init Native E2E / init-native (macos-latest, codex) (push) Has been cancelled
Init Native E2E / init-native (macos-latest, copilot) (push) Has been cancelled
Install Native E2E / install-native (macos-latest) (push) Has been cancelled
Wrap Native E2E / wrap-native (macos-latest) (push) Has been cancelled
129 lines
4.8 KiB
Python
129 lines
4.8 KiB
Python
"""Pin the ONNX Runtime dylib for the Rust core on dynamic-ORT platforms.
|
|
|
|
Why this module exists
|
|
----------------------
|
|
On Windows and Intel macOS (``x86_64-apple-darwin``), ``headroom._core``
|
|
consumers of the ``ort`` crate (magika content detection, fastembed
|
|
embeddings) are built with ``ort-load-dynamic``: the native ONNX Runtime
|
|
library is resolved at *runtime*.
|
|
|
|
Windows: unless ``ORT_DYLIB_PATH`` is set, ort falls back to a bare
|
|
``LoadLibrary("onnxruntime.dll")`` and the Windows DLL search order
|
|
applies — and ``C:\\Windows\\System32`` wins. Windows 11 24H2+ ships
|
|
``System32\\onnxruntime.dll`` as part of Windows ML (observed:
|
|
1.17.2603 "os-germanium"). Initializing an ort 2.x session against that
|
|
OS build does not fail — it deadlocks indefinitely at 0% CPU, which the
|
|
tiered detection fallback cannot catch (a hang is not an ``Err``).
|
|
Reproduced and bracketed with ``scripts/diag_magika_windows.py``: the
|
|
identical session inits in ~400ms when ``ORT_DYLIB_PATH`` points at the
|
|
``onnxruntime`` pip package's DLL (which ``headroom-ai[proxy]`` already
|
|
depends on).
|
|
|
|
Intel macOS: ``ort-sys 2.0.0-rc.12`` does not ship prebuilt ONNX Runtime
|
|
binaries for ``x86_64-apple-darwin``, so the wheel/sdist build uses
|
|
``ort-load-dynamic`` and expects a pip-installed ``onnxruntime`` dylib
|
|
at runtime (same contract as Windows).
|
|
|
|
The fix: before anything can import ``headroom._core``, resolve the
|
|
pip-installed ``onnxruntime`` native library and export it via
|
|
``ORT_DYLIB_PATH``. ``headroom/__init__.py`` calls this hook, which
|
|
guarantees ordering for every package-level consumer.
|
|
|
|
Behavior contract
|
|
-----------------
|
|
- Active on Windows and Intel macOS only; a no-op elsewhere.
|
|
- Respects a pre-set ``ORT_DYLIB_PATH`` (user override wins).
|
|
- Locates the ``onnxruntime`` package via ``find_spec`` WITHOUT
|
|
importing it (importing would load its native code; this hook must
|
|
stay ~microseconds and side-effect free).
|
|
- Never raises: import-time failure of an optional accelerator must
|
|
not break ``import headroom``. Without a pin, detection still
|
|
degrades gracefully through HEADROOM_MAGIKA_INIT_TIMEOUT_SECS and
|
|
the non-ML tiers.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import importlib.util
|
|
import logging
|
|
import os
|
|
import platform
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
_ENV_VAR = "ORT_DYLIB_PATH"
|
|
|
|
# Tri-state module cache: unset sentinel / resolved path / None (no pin).
|
|
_UNSET = object()
|
|
_pinned: object = _UNSET
|
|
|
|
|
|
def ensure_ort_dylib_pinned() -> str | None:
|
|
"""Export ``ORT_DYLIB_PATH`` for the Rust core's ort runtime.
|
|
|
|
Returns the effective dylib path (pinned now or already present in
|
|
the environment), or ``None`` when no pin applies (platforms that
|
|
bundle ORT at build time, or no ``onnxruntime`` package to point at).
|
|
Idempotent and exception-free.
|
|
"""
|
|
global _pinned
|
|
if _pinned is not _UNSET:
|
|
return _pinned # type: ignore[return-value]
|
|
_pinned = _resolve_and_pin()
|
|
return _pinned # type: ignore[return-value]
|
|
|
|
|
|
def _needs_ort_dylib_pin() -> bool:
|
|
if sys.platform.startswith("win"):
|
|
return True
|
|
return sys.platform == "darwin" and platform.machine() == "x86_64"
|
|
|
|
|
|
def _resolve_ort_native_library(capi_dir: Path) -> Path | None:
|
|
if sys.platform.startswith("win"):
|
|
candidate = capi_dir / "onnxruntime.dll"
|
|
return candidate if candidate.is_file() else None
|
|
|
|
matches = sorted(capi_dir.glob("libonnxruntime*.dylib"))
|
|
return matches[0] if matches else None
|
|
|
|
|
|
def _resolve_and_pin() -> str | None:
|
|
if not _needs_ort_dylib_pin():
|
|
return None
|
|
|
|
try:
|
|
existing = os.environ.get(_ENV_VAR)
|
|
if existing:
|
|
logger.debug("%s already set; respecting user override: %s", _ENV_VAR, existing)
|
|
return existing
|
|
|
|
spec = importlib.util.find_spec("onnxruntime")
|
|
if spec is None or not spec.origin:
|
|
logger.debug(
|
|
"onnxruntime package not found; %s left unset. Rust ML detection "
|
|
"needs a pip-installed onnxruntime on this platform (install "
|
|
"headroom-ai[proxy] or set %s explicitly).",
|
|
_ENV_VAR,
|
|
_ENV_VAR,
|
|
)
|
|
return None
|
|
|
|
native = _resolve_ort_native_library(Path(spec.origin).parent / "capi")
|
|
if native is None:
|
|
logger.debug(
|
|
"onnxruntime package found but no native library under %s; %s left unset",
|
|
Path(spec.origin).parent / "capi",
|
|
_ENV_VAR,
|
|
)
|
|
return None
|
|
|
|
os.environ[_ENV_VAR] = str(native)
|
|
logger.info("Pinned %s to bundled ONNX Runtime: %s", _ENV_VAR, native)
|
|
return str(native)
|
|
except Exception as exc: # never break `import headroom` over an accelerator pin
|
|
logger.debug("ort dylib pin skipped: %s: %s", type(exc).__name__, exc)
|
|
return None
|