Skip to content

雪岭轻舟,musl 同渡 · Add musl platform packages and relax Node engines - #63

Merged
eric8810 merged 3 commits into
mainfrom
issue-62-musl-and-engines
Sep 24, 2026
Merged

eric8810 merged 3 commits into
mainfrom
issue-62-musl-and-engines

Conversation

@eric8810

Copy link
Copy Markdown
Contributor

Resolves #62.

What

musl (Alpine) Linux support — two new CPU-only prebuilt platform packages, @arcships/light-ocr-linux-x64-musl and @arcships/light-ocr-linux-arm64-musl (eight platform packages total):

  • The pinned ONNX Runtime 1.22.0 shared libraries are built from source in alpine:3.22 with a one-line musl execinfo.h guard (the backtrace() body is NDEBUG-compiled in Release anyway), packaged in the NuGet layout (build/native/include + runtimes/linux-<arch>-musl/native), and pinned by SHA-256 in models/deps.lock.json under the musl-runtime-1.22.0 release. .github/workflows/onnxruntime-musl.yml rebuilds both archives on demand.
  • tools/bootstrap_dependencies.py: without --platform-id, fetch every CPU runtime entry (shared-cache mode); with it, keep the exact-one selection.
  • cmake/Dependencies.cmake: new LIGHT_OCR_TARGET_LIBC (gnu | musl, default gnu) selects the musl archive and the runtimes/linux-*-musl layout, guarded by a musl toolchain -dumpmachine check. The WebGPU flavor stays glibc-only.
  • npm release pipeline: new build-native-musl and smoke-musl jobs run in an alpine:3.22 container on x64 and arm64 runners; assemble/publish wait for them.
  • Runtime loader: glibc vs musl detection on Linux (process.report plus an ldd fallback), platformIdentity() exported from @arcships/light-ocr-runtime, and both musl package mappings; document.cjs resolves the pdfium addon through the same identity (pdfium-native@0.6.1 already ships musl targets).

Node engines relaxation — engines.node moves from ^22.0.0 || ^24.0.0 to >=22.0.0 in every package. The Node-API ABI keeps newer majors (including 26) loading the same prebuilt binaries without a library release, and enumerated ranges hard-fail Yarn installs the day a new Current line ships. Tier 1 support stays the 22/24 LTS lines; the support contract now lives in the documented tier matrix and CI smoke rather than in engines.

Verification

  • Full musl x64 integration build in alpine:3.22: deps.lock selection and hash checks, OpenCV/clipper/json/stb, the Node addon (241/241 targets), the musl pdfium-native addon, and require() of light_ocr_node.node on musl Node 22 all pass; the addon resolves its libonnxruntime.so.1 through $ORIGIN.
  • arm64 musl onnxruntime built and verified (dlopen + OrtGetApiBase), archive uploaded and re-hashed from the release URL.
  • Loader identity verified both ways: musl container → linux-x64-musl, glibc host → linux-x64.
  • Python suite: 85 passed (new tests for cache-complete bootstrap selection and the musl workflow contracts). JS packages: runtime, light-ocr, document, tiny all green.

Notes for review

  • The musl ONNX Runtime archives are pinned supply-chain artifacts exactly like the NuGet package; the rebuild workflow is the documented path to rotate them.
  • Yarn 1 does not understand npm libc filtering, so a musl user on Yarn 1 still gets a clear package_load_failed error naming the missing musl package — same failure mode as today, no silent wrong-binary load.
  • WebGPU on musl is intentionally out of scope (Dawn/musl would be a separate qualification); both musl packages are CPU-only like the existing arm64 glibc and Windows arm64 packages.

…ode engines

Resolve #62. Two changes shipped together:

musl (Alpine) platform support:
- Add @arcships/light-ocr-linux-x64-musl and -arm64-musl CPU-only prebuilt
  packages (eight platform packages total).
- Build the pinned ONNX Runtime 1.22.0 musl shared libraries from source in
  alpine:3.22 with a one-line execinfo guard, package them in the NuGet
  layout, and pin both archives by SHA-256 in models/deps.lock.json under
  the musl-runtime-1.22.0 release; .github/workflows/onnxruntime-musl.yml
  rebuilds them on demand.
- bootstrap_dependencies.py: without --platform-id, fetch every CPU runtime
  entry (shared cache mode); with it, keep the exact-one selection.
- cmake/Dependencies.cmake: LIGHT_OCR_TARGET_LIBC (gnu|musl, default gnu)
  selects the musl archive and runtimes/linux-*-musl layout, guarded by a
  musl toolchain dumpmachine check; WebGPU stays glibc-only.
- npm release pipeline: build-native-musl and smoke-musl jobs run in an
  alpine:3.22 container on x64 and arm64 runners.
- runtime loader: detect glibc vs musl on Linux (process.report plus ldd
  fallback), expose platformIdentity(), and map the musl platform packages;
  document.cjs selects the pdfium addon through the same identity.

Node engines relaxation:
- Relax engines.node from ^22.0.0 || ^24.0.0 to >=22.0.0 in every package:
  the Node-API ABI keeps newer majors (including 26) loading the same
  prebuilt binaries, and enumerated ranges hard-fail Yarn installs on every
  new Current release. Tier 1 stays 22/24 LTS, documented in napi-design.md.
Review fixes for #63:

- cmake: LIGHT_OCR_TARGET_LIBC now follows the existing WebGpuRuntime.cmake
  vocabulary (glibc, not gnu); the previous wording broke every Linux WebGPU
  configure path. dumpmachine validation gains RESULT_VARIABLE handling and
  a timeout, and distinguishes unsupported-compiler from non-musl toolchains.
- smoke: document-smoke.cjs resolves the native package through the shared
  platformIdentity() (the stale glibc-only mapping would fail the musl smoke
  job and block publish).
- loader: isMuslLinux() checks the musl dynamic linker path (arch-matched)
  first and handles spawnSync error results instead of an unreachable catch;
  adds a spawn timeout.
- types: platformIdentity() is declared in index.d.ts as public API.
- musl runtime archives now bundle the ONNX Runtime LICENSE; deps.lock.json
  and Dependencies.cmake re-pin the regenerated archives (hashes re-verified
  from the release URLs through the bootstrap verifier).
- onnxruntime-musl.yml: drop the unusable tag-push trigger (publish was
  always skipped and inputs fell back to hardcoded versions); record the
  ONNX Runtime source SHA in the step summary and verify .sha256 checksums
  before release upload.
- docs: npm package README (published to npmjs.com), napi-design, npm-
  packaging, build-and-release, monorepo-design, and bindings/node README
  updated for eight platforms, fifteen staged packages, the glibc/musl
  platform tables, Node 25 tier wording, and the relaxed engines policy;
  npm-packaging musl deferral note marked as superseded.
- tests: cache-complete mode keeps rejecting the webgpu flavor (regression
  lock); workflow contract assertions scoped to the musl jobs.
Second review round fixes for #63:

- document-smoke.cjs carries its own host platform detection (glibc report
  field plus arch-matched musl loader path) instead of requiring
  platformIdentity() from the installed runtime: the publish-time
  registry-document check installs the published document@0.1.3 closure,
  whose exact-pinned runtime 0.1.7 predates that export, so the previous
  fix would have failed every real publish run. Verified against the
  installed registry closure (runtime 0.1.7, no export) with a full PDF OCR
  pass.
- Dependencies.cmake no longer injects a default LIGHT_OCR_TARGET_LIBC
  before the WebGPU branch: under CMP0126 the normal variable would shadow
  WebGpuRuntime.cmake's own glibc detection, so a musl host misconfigured
  for the WebGPU flavor lost its clear early failure. The default now
  applies only inside the CPU flavor branch; the shared validation runs
  only when the variable is set. Interaction matrix re-verified.
- build-and-release.md: the pre-build registry identity check counts 15
  package identities (eight platforms plus the seven non-native entries).
@eric8810
eric8810 merged commit 3e69189 into main Sep 24, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Platform support: Node 26 and musl

1 participant