[RNE Rewrite] feat: on-demand native lib download and backend splitting#1283
[RNE Rewrite] feat: on-demand native lib download and backend splitting#1283msluszniak wants to merge 11 commits into
Conversation
Port PR #1039's on-demand native-lib mechanism into the rewrite. Apps opt in via a `react-native-executorch` block (`backends`/`libs`/`features`) in their package.json; the postinstall `scripts/download-libs.js` expands `features` via the full forward-looking FEATURE_MAP, writes `rne-build-config.json`, and downloads only the requested per-backend artifacts from GitHub Releases into third-party/. The podspec and android/build.gradle.kts read that config to gate `RNE_ENABLE_*` and link backends as separate libs (Xnnpack/CoreML/MLX xcframeworks, lib*_executorch_backend.so) — MLX device-slice only. Adapted to the rewrite: cpp/ layout (opencv gated as an extensible source list, guarded in RnExecutorch.cpp), Kotlin-DSL gradle config read, single android/CMakeLists.txt. scripts + FEATURE_MAP + artifact contract kept identical to #1039 so future rewrite work is code-only. CI (TS-only) skips the download via RNET_SKIP_DOWNLOAD in the setup action. Verified: config expansion, download/extract/checksum (local server), and CI gates (lint, bob build, typecheck). Release artifacts (executorch fork build) + committed headers/jar/ExecutorchLib wrapper are provisioned separately.
94f8547 to
ab793e1
Compare
Rebased onto rne-rewrite incl. #1280 keypoint detection. Rename the poseEstimation FEATURE_MAP entry to keypointDetection (tracks the useKeypointDetector hook) and set backends to xnnpack+coreml+mlx (RF-DETR keypoint ships CoreML + MLX variants) + opencv. Declare it in the computer-vision demo app.
Drop the committed third-party/include header set (~200K LOC of vendored ExecuTorch/c10/torch/opencv headers). Headers are now downloaded like the binaries: a platform-independent headers.tar.gz fetched by download-libs.js and produced by package-release-artifacts.sh. Keeps the rewrite's 'no third-party in git' philosophy and avoids churn on ExecuTorch bumps.
ab793e1 to
45ec2cb
Compare
core-android/core-ios drop the separately-shipped pthreadpool+cpuinfo (statically linked into libexecutorch.so / libthreadpool_*.a for the rewrite), and the ABI-independent executorch.jar rides in the core-android-arm64 artifact (downloaded to third-party, not committed).
Two gaps surfaced building apps/computer-vision on a physical device: - libexecutorch.so references OpenMP runtime symbols (optimized kernels), so link -fopenmp -static-openmp into libRnExecutorch.so (matches main #1039). - abiFilters was hardcoded to both ABIs, ignoring the app's reactNativeArchitectures; read it (filtered to arm64-v8a/x86_64) so device builds only compile + need the ABI they target. Build now succeeds, installs, and launches on device (arm64-v8a).
Add a Fundamentals docs tree to the rewrite (docs/docs was removed in the
scaffold):
- 01-getting-started: ported canonical content + a "Selecting native
libraries" section covering the react-native-executorch package.json
block (features/backends/libs) and the feature -> backend/lib mapping.
- 02-native-libraries: how the split is produced, shipped, and linked
(download flow, artifact set, header provenance, Android/iOS wiring,
force-load rationale, build recipe), corrected for the rewrite
(@ms/separate-backends, ET 1.3.1, device-only MLX, downloaded headers).
- sidebars: current version exposes Fundamentals + API Reference; the
not-yet-ported sections stay commented until their dirs are restored.
Fix the docs build, broken on the rewrite independently of these pages:
- restore packages/.../tsconfig.doc.json so typedoc can load the project.
- convert two URL-target {@link} TSDoc tags to markdown links so the
generated API reference compiles under MDX.
Also fix a variable-shadowing lint error in download-libs.js and add the
new technical terms to the cspell wordlist.
There was a problem hiding this comment.
Why are these scripts nested inside packages/react-native-executorch and not in the monorepo root (like the error gen scripts)?
There was a problem hiding this comment.
download-libs.js must live in the package: it runs at the package's postinstall, ships in the npm tarball, and resolves third-party/ relative to itself (unlike the dev-only error-gen scripts at root). package-release-artifacts.sh is its build-side pair (produces exactly the layout download-libs.js consumes), so it's colocated. Happy to move the release script to the monorepo root if you'd prefer.
|
…native-libs # Conflicts: # .cspell-wordlist.txt
- podspec: stop wrapping `$(PODS_TARGET_SRCROOT)` paths in File.expand_path (it baked a malformed `<dir>/$(PODS_TARGET_SRCROOT)/...` into the linker flags); use the literal Xcode build variable like HEADER_SEARCH_PATHS does. - download-libs.js: only send GITHUB_TOKEN to github.com hosts (not to the githubusercontent.com presigned redirect target). - third-party/.gitignore: ignore the downloaded executorch.jar. - RnExecutorch.cpp: drop the redundant comment on the opencv include guard.
|
The headers.tar.gz set was assembled by an ad-hoc copy of the executorch
CMake install include tree, which is incomplete: it omits the source-only
headers (extension/llm/{runner,custom_ops,apple,sampler}) that the rewrite's
LLM/multimodal tasks compile against directly, and the codegen'd
kernels/*/Functions.h.
vendor-headers.sh assembles the full, reproducible set from its four real
sources — executorch C++ source headers, build-generated/installed headers,
c10/torch from the xcframework, and opencv2 — laid out to satisfy both the
nested tokenizer include paths (CMakeLists) and the root -I. The result is a
superset of both the current RNE main header set and the CV PoC.
package-release-artifacts.sh now hard-fails if third-party/include is missing
the runner headers, and the native-libraries doc documents the step.
|
@barhanc I added mentioned script, now working on memory comparison for cv demo app. |
App-size impact of the backend splitMeasured on the CV app — split vs all-backends
iOS is ~0 here because the CV app uses every iOS backend (xnnpack + coreml + mlx via What the split drops, per backend (the cross-app value)
|
A conservative, high-signal clang-tidy config plus a runner and a (dormant) CI workflow. - .clang-tidy: bugprone-* / performance-* / clang-analyzer-* (minus the noisy easily-swappable-parameters and enum-size), analyzing only our own headers. - scripts/clang-tidy.sh + `lint:cpp`: run clang-tidy over cpp/ using compile_flags.txt, failing on any finding. - .github/workflows/clang-tidy.yml: gated behind ENABLE_CLANG_TIDY; provisions headers via the on-demand download flow (download-libs.js, #1283) since clang-tidy needs the ExecuTorch headers to parse the sources. - dtype.cpp: NOLINT the intentional identical-size switch branches.
A conservative, high-signal clang-tidy config plus a runner and a (dormant) CI workflow. - .clang-tidy: bugprone-* / performance-* / clang-analyzer-* (minus the noisy easily-swappable-parameters and enum-size), analyzing only our own headers. - scripts/clang-tidy.sh + `lint:cpp`: run clang-tidy over cpp/ using compile_flags.txt, failing on any finding. - .github/workflows/clang-tidy.yml: gated behind ENABLE_CLANG_TIDY; provisions headers via the on-demand download flow (download-libs.js, #1283) since clang-tidy needs the ExecuTorch headers to parse the sources. - dtype.cpp: NOLINT the intentional identical-size switch branches.
Provisions only headers.tar.gz (no per-target native libs) when RNET_HEADERS_ONLY is set — the integration point for clang-tidy / IDE tooling that needs include paths but never links or runs the binaries. The build config is still written. Also documents the existing RNET_NO_X86_64 opt-out in the README/env-var lists.
Description
Ports PR #1039's on-demand native-lib mechanism into the rewrite flow. Apps declare what they need via a
react-native-executorchblock (backends/libs/features) inpackage.json; the postinstallscripts/download-libs.jsexpandsfeaturesvia the forward-lookingFEATURE_MAP, writesrne-build-config.json, and downloads only the requested per-backend artifacts from GitHub Releases intothird-party/. The podspec andandroid/build.gradle.ktsread that config to gateRNE_ENABLE_*and link backends as separate libs (Xnnpack/CoreML/MLXxcframeworks,lib*_executorch_backend.so); MLX is the iOS device slice only.Adapted to the rewrite:
cpp/layout (opencv kept as an extensible source list, guarded inRnExecutorch.cpp), Kotlin-DSL gradle config read, singleandroid/CMakeLists.txt. The scripts,FEATURE_MAP, and artifact contract are kept identical to #1039 so future rewrite work stays code-only. CI (TS-only) skips the download viaRNET_SKIP_DOWNLOADin the setup action.Backed by
software-mansion-labs/executorch@ms/separate-backends(already ET 1.3.1). Release artifacts (device-only MLX) are built/uploaded separately; committed headers /executorch.jar/ExecutorchLibwrapper are provisioned alongside.Introduces a breaking change?
Type of change
Tested on
Testing instructions
react-native-executorch.features(e.g.["llm"]), runyarn install, and checkrne-build-config.jsonreflects it (enableOpencv:false, enableCoreml:false, enableXnnpack:true). Setting legacyextraserrors.RNET_BASE_URL=https://github.com/software-mansion/react-native-executorch/releases/download/v0.0.0-rewrite-libs-test RNET_TARGET=android-arm64-v8a INIT_CWD=<app> node scripts/download-libs.js— tarballs extract (checksum-verified) intothird-party/android/libs/...exactly whereCMakeLists.txt/podspec expect.yarn lint,yarn workspace react-native-executorch prepare,yarn typecheck(all green; install withRNET_SKIP_DOWNLOAD=1).Test artifacts uploaded to the
v0.0.0-rewrite-libs-testpre-release: Android freshly built from@ms/separate-backends(ET 1.3.1, split backends, arm64-v8a + x86_64); iOS reused from the same separate-backends 1.3.1 lineage (#1039) with MLX stripped to the device slice only. Full download/extract/checksum flow verified across iOS + both Android ABIs. On-device app build still to be run.Related issues
#1208
Checklist
Additional notes
Draft: all of third-party/ (headers + binaries) is downloaded on demand, not committed — headers ship as a platform-independent headers.tar.gz alongside the binary artifacts (built with device-only MLX), uploaded separately.
Header provenance:
headers.tar.gzis assembled from the@ms/separate-backendsExecuTorch CMake install include tree (cmake-out*/include/:executorch,pytorch/{c10,torch,headeronly}, the tokenizer third-party headersabsl/re2/nlohmann, andcpuinfo/pthreadpool— all platform-independent, identical across ABIs/SDKs) plus theopencv2headers from the OpenCV prebuilt (same source as theopencv-rnepod / Android staticlibopencv_*.a, not built from executorch).Docs getting-started is deferred (no rewrite getting-started page exists yet).