Support pure JVM JAR compilation and packaging for desktop JVM - #20761
Support pure JVM JAR compilation and packaging for desktop JVM#20761RanjithRagavan wants to merge 11 commits into
Conversation
🔗 Helpful Links🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/20761
Note: Links to docs will display an error until the docs builds have been completed.
|
|
@pytorchbot label "release notes: none" |
|
Hi @RanjithRagavan, thank you for the PR. Could you address the CI failures? |
|
Thanks @RanjithRagavan for the PR. The idea is strong and imo worth pursuing — a pure-JVM ExecuTorch artifact for desktop (Linux/macOS/Windows) is good in terms of direction This requires a bit of a redesign before it's mergeable, so let me lay out my thoughts rather than line-by-line comments.
extension/
Happy to help scope the shared-module split and the native-packaging approach. IMO this is a valuable addition and worth getting the foundation right. 🙏 |
psiddh
left a comment
There was a problem hiding this comment.
Please take a look at the feedback
|
valuable feedbacks.. Will work on it. |
b9b0432 to
50fcff9
Compare
1. Extracted Shared Platform-Neutral Java APIExtracted the platform-neutral Java API into a shared module and converted the Android and JVM modules into thin sibling shells:
2. Replace Reflection-Based Logging with a Logger InterfaceWe introduced the
3. Solve Native Library Delivery on JVM Desktop
4. Tests and Verification
|
|
This is a good redesign. I want to be clear about the bar this change has to clear, though. ExecuTorch Android is a foundational, widely-deployed dependency in production, so the Android path must not regress. Before we can consider next steps this will need thorough vetting and careful consideration, internal integration validation, a release-shrunk consumer build, and an AAR before/after diff proving the shipping artifact is unchanged. Please bear with a slower, more careful review than usual; it's a reflection of the surface area and potential blast radius, not the quality of the work. Thanks for the collaboration! I'll summarize the next steps. |
36cd9f2 to
6190fc1
Compare
…(Linux/macOS/Windows) Add desktop JVM support (executorch_jvm) that compiles a standalone desktop JAR without altering ExecuTorch Android layout or adding runtime indirection. Shared Java/Kotlin sources are compiled directly via Gradle sourceSets. This PR was authored with Claude.
6190fc1 to
b84b044
Compare
Rearchitected ExecuTorch JVM Support — Zero Android Path RegressionThanks for the feedback @psiddh! Based on your guidance regarding ExecuTorch Android's foundational status in production, this change has been re-architected to guarantee that the Android build path, shipping AAR artifact, and runtime performance do not regress in any way. Key Architectural Decisions
Architecture Diagramgraph TD
subgraph "Source Files"
A["extension/android/executorch_android/src/main/java/<br/>(Tensor.kt, Module.kt, EValue.kt, LlmModule.kt, etc.)"]
B["Android Log.kt<br/>(android.util.Log static call)"]
C["JVM Log.kt & NativeLibraryLoader.kt<br/>(Console logging & OS native library unpacker)"]
end
subgraph "Gradle Build Targets"
A --> |Direct Sources| D[":executorch_android (.aar)"]
B --> |Direct Android Log| D
A --> |Shared sourceSets.main| E[":executorch_jvm (.jar)"]
C --> |Desktop Overrides| E
end
subgraph "Shipping Artifacts"
D --> F["Android Production Artifact<br/>(executorch-android.aar)"]
E --> G["Desktop JVM Artifact<br/>(executorch-jvm.jar)"]
end
|
…d/JVM siblings Address reviewer feedback on pytorch#20761: 1. Extract platform-neutral API into extension/java (executorch-java). No android.* references in the shared module - enforced by classpath (JDK + fbjni-java-only + soloader only). Android and JVM modules are thin siblings that depend on it via api project(':executorch_java'). No relative srcDirs cross-compilation anymore. 2. Replace reflection/ServiceLoader-based wiring with compile-checked interfaces: Logger interface with AndroidLogger (installed via ExecuTorchInitProvider at process start) and ConsoleLogger (JVM default). Native loading is configured explicitly through ExecuTorchRuntime.configureNativeLoading(); the desktop entry point is ExecuTorchJvm.init(). The Android runtime path no longer contains any ServiceLoader lookup and keeps SystemDelegate + 'executorch' defaults. 3. Native library delivery for desktop: API jar + per-platform native jars with Maven classifiers (linux-x86_64, macos-aarch64, ...). jarNative* Gradle tasks package binaries staged under extension/cmake-out-jvm/<classifier>/ into native/<os>/<arch>/ paths that NativeLibraryLoader extracts at runtime. 4. Android artifact parity: package names unchanged, Android runtime defaults unchanged, manifest gains only the init provider. Unit tests (EValue/Tensor/Logger) now run on the desktop JVM in the shared module - 63 tests green. Buck targets keep their historical names in extension/android/BUCK and re-export the new //xplat/executorch/extension/java targets.
|
@psiddh Redesign implemented per your feedback — pushed as 438dce3. Point-by-point: 1. Shared platform-neutral module extracted ✅New
2. Logger interface, no reflection ✅
The ServiceLoader lookup that was in 3. Native-library delivery ✅ (mechanism)Standard API-jar + per-platform-native-jars pattern:
4. Android safety ✅ (with two honest caveats)
Caveats I want to be upfront about:
Would appreciate another look when you have time. Thanks for the detailed direction — the codebase is much cleaner this way. |
I will look into it this week and get back, Thanks again for all the great work and contribution |
|
@claude Please review the design of this PR and read all existing comments What do you think of this alternative design? Share platform-neutral sources without making Android depend on a new untime JAR: java-common sources Android may reference the shared source location, but its existing artifact
Desktop JNI should have its own build boundary, preferably self-contained Suggested sequencing / Ownership:
|
|
Claude finished @psiddh's task in 3m 24s —— View job Design review: shared-source vs. shared-runtime-JAR
Verdict: I agree with your alternative. Share sources, not a runtime artifact. The current PR is well-executed and much cleaner as OSS module topology, but it converts four separate properties of the shipping Android contract into changes, and each one is an independent regression vector. Source-sharing gives you the desktop artifact while keeping the AAR byte-close to what ships today. Below I map each of your constraints to the concrete thing in the current diff it would revert, then flag one actual bug I found while reading. Where the current design touches the Android shipping contract
On Buck (constraint: unchanged ownership/attributes): sources moved to Bug in the current desktop path (independent of which design you pick)
// ExecuTorchRuntime.kt
init { ensureNativeLibraryLoaded() } // runs on FIRST touch of the companion
...
fun configureNativeLoading(...) {
check(!NativeLoader.isInitialized()) { "...must be called before...loaded" } // will throw
}Calling Notes for implementing the source-sharing design cleanly
On sequencingYour 4-step plan is the right shape, and it matches the safe path you asked for on Aug 16: land the shared-source extraction as a standalone, behavior-preserving refactor first (AAR-diff empty, all Android variants' standalone-AAR tests green, internal Buck/FoA validated), then add the JVM jar and native classifiers on top. That way desktop support never gates on, or risks, the shipping Android build. The per-OS native binaries (step 3) genuinely need a CI matrix regardless of design; the loader/packaging mechanism here is reusable once the extraction hardening above is in. Net: the alternative is the lower-risk design and I'd recommend adopting it. Happy to look again once the shared-source version is up. |
|
@RanjithRagavan Thank you for the thoughtful redesigns, responsiveness to feedback, and the substantial time you’ve invested here. Desktop JVM support is valuable, and I appreciate your continued collaboration in getting the foundation and Android safety bar right. I’m happy to own the internal Buck/FoA validation and final parity checks while you drive the OSS implementation and testing. Please let me know your thoughts |
|
@psiddh Thank you — I agree with the shared-source design, and with the sequencing. It's strictly lower-risk for Android and still delivers the full desktop artifact, so let's go with it.
|
|
@psiddh Thank you — I agree with the shared-source design and the sequencing. Step 1 (the behavior-preserving shared-source extraction) is up for review as #22338. A few notes on how it maps to your constraints and the @claude review:
I opened this as a fresh PR to keep the review archaeology clean, since this branch's design differs from what's on this one. Happy to close #22338 and fold the exact same branch back into this PR if you'd rather keep everything here. Once step 1 lands, I'll follow with the desktop JVM jar (step 2) and native classifier publication (step 3) on top. |
|
@claude review |
|
Claude finished @kirklandsign's task in 2m 29s —— View job Code Review — Desktop JVM support (PR #20761)
First, the meta-point: the branch on this PR still contains the earlier shared-runtime-JAR design — the one where If the plan holds, this branch should either be closed in favor of #22338 (+ follow-ups), or reset to the shared-source approach. The review below is against the code actually on this branch. Android regression vectors still present on this branch
Bug:
|
|
@kirklandsign Thanks for the review — agreed on all points. #22338 is the current direction; this PR stays as the umbrella for steps 2–3 and won't merge as-is. Once #22338 lands I'll rebuild the JVM module on top of it with: lazy per-artifact native loading (the |
This PR adds support for compiling and packaging the ExecuTorch Java/Kotlin APIs as a standard JVM JAR package targeting desktop platforms (Linux, macOS, Windows). It resolves #16422 by decoupling the codebase from Android-specific APIs (using reflection to delegate android logging) and adding a new
:executorch_jvmGradle project. In addition, the JNI CMake configuration has been expanded to support building on desktop hosts.cc @kirklandsign @cbilgin