Skip to content

Support pure JVM JAR compilation and packaging for desktop JVM#20761

Open
RanjithRagavan wants to merge 5 commits into
pytorch:mainfrom
RanjithRagavan:support-jvm-jar
Open

Support pure JVM JAR compilation and packaging for desktop JVM#20761
RanjithRagavan wants to merge 5 commits into
pytorch:mainfrom
RanjithRagavan:support-jvm-jar

Conversation

@RanjithRagavan

@RanjithRagavan RanjithRagavan commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

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_jvm Gradle project. In addition, the JNI CMake configuration has been expanded to support building on desktop hosts.

cc @kirklandsign @cbilgin

@pytorch-bot

pytorch-bot Bot commented Jul 7, 2026

Copy link
Copy Markdown

🔗 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.

⚠️ 13 Awaiting Approval

As of commit 36cd9f2 with merge base af62dce (image):

AWAITING APPROVAL - The following workflows need approval before CI can run:

This comment was automatically generated by Dr. CI and updates every 15 minutes.

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Jul 7, 2026
@RanjithRagavan

Copy link
Copy Markdown
Contributor Author

@pytorchbot label "release notes: none"

@pytorch-bot pytorch-bot Bot added the release notes: none Do not include this in the release notes label Jul 7, 2026
@nil-is-all nil-is-all added the module: android Issues related to Android code, build, and execution label Jul 10, 2026
@nil-is-all

Copy link
Copy Markdown
Contributor

Hi @RanjithRagavan, thank you for the PR. Could you address the CI failures?

…classpath to resolve Kotlin duplicate loading and classloader issues
@psiddh

psiddh commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

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.

  1. Don't nest desktop-JVM under android: A desktop module living in extension/android/ and compiling executorch_android's source tree byrelative path (srcDirs = ['../executorch_android/...']) couples the two platforms and gives no compile boundary — which is why android.util.Log leaks into the JVM build. Extract the platform-neutral API into a shared module, and make android and jvm thin sibling modules that depend on it:

extension/
├── jni/ shared C++ JNI + CMake
├── java/ shared, platform-neutral API (no android.* — enforced by classpath)
├── android/ Android-only: AAR, AndroidLogger, jniLibs
└── jvm/ Desktop-only: jar, ConsoleLogger, per-OS native packaging

  1. Replace reflection-based logging with a Logger interface (AndroidLogger / ConsoleLogger), selected per module — compile-checked and testable, avoids the partial Log shim.

  2. Solve native-library delivery — this is the core gap. A pure JVM jar with no native binary will UnsatisfiedLinkError on first use. The standard pattern is an API jar + per-platform native jars (Maven classifiers: linux-x86_64, macos-aarch64, windows-x86_64…) with a loader that extracts and loads the right .so/.dylib/.dll at runtime.

  3. Sequence it to keep Android safe. To keep the existing executorch-android artifact safe, I'd suggest doing the shared-module extraction as a separate, behavior-preserving refactor first (Android depends on it, package names unchanged, existing Android CI green, AAR diffed before/after), then adding the JVM module on top. That way desktop support never risks the shipping Android build.

  4. CI, tests, and docs — Changes needed to go along with the PR review

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 psiddh left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please take a look at the feedback

@RanjithRagavan

Copy link
Copy Markdown
Contributor Author

valuable feedbacks.. Will work on it.

- Extract platform-neutral API into shared 'extension/java/' module
- Replace reflection-based logging with ServiceLoader Logger SPI
- Create thin sibling platform modules ('extension/android/' and 'extension/jvm/')
- Implement per-OS NativeLibraryLoader and NativeLoader JvmDelegate on desktop JVM
- Relocate unit tests to shared module for fast JVM test execution
@RanjithRagavan RanjithRagavan requested a review from psiddh July 16, 2026 06:17
@RanjithRagavan

RanjithRagavan commented Jul 16, 2026

Copy link
Copy Markdown
Contributor Author

1. Extracted Shared Platform-Neutral Java API

Extracted the platform-neutral Java API into a shared module and converted the Android and JVM modules into thin sibling shells:

           +-------------------------------------------------------+
           |                    extension/java/                    |
           |             (Shared platform-neutral API)             |
           |             -----------------------------             |
           |             - DType, EValue, Module, Tensor           |
           |             - Log singleton & Logger SPI              |
           +-------------------------------------------------------+
                                ^             ^
                                |             |
      depends on (api project)  |             |  depends on (api project)
                                |             |
  +-----------------------------------+     +-----------------------------------+
  |        extension/android/         |     |          extension/jvm/           |
  |     (Android-specific shell)      |     |      (JVM Desktop-specific)       |
  |     ------------------------      |     |      ----------------------       |
  |     - AndroidLogger               |     |      - ConsoleLogger              |
  |     - fbjni AAR packing           |     |      - JvmNativeLoaderDelegate    |
  |     - jniLibs (.so package)       |     |      - NativeLibraryLoader        |
  +-----------------------------------+     +-----------------------------------+
  • Platform-neutral Kotlin API source files are now under extension/java/. No relative srcDirs are used anymore.
  • We verified that zero android.* imports exist in the shared module (extension/java).

2. Replace Reflection-Based Logging with a Logger Interface

We introduced the Logger interface and a Log facade in the shared module. Log calls dynamically resolve the provider using java.util.ServiceLoader (with a built-in fallback to console if none is found on the classpath):

ExecuTorch Classes (Shared Java Module)
             │
             ▼  (calls Log.d/i/w/e)
     Log facade (SPI)
             │
             ▼  (discovers Logger provider on classpath)
  ┌───────────────────────────┴───────────────────────────┐
  ▼                                                       ▼
AndroidLogger (extension/android)               ConsoleLogger (extension/jvm)
  │                                                       │
  ▼                                                       ▼
android.util.Log                                System.err / System.out
  • Registered AndroidLogger via ServiceLoader inside the executorch_android module.
  • Registered ConsoleLogger via ServiceLoader inside the executorch_jvm module.

3. Solve Native Library Delivery on JVM Desktop

  • We created NativeLibraryLoader in the JVM module to handle unpacking native libraries from classpath resources (/native/<os>/<arch>/...) and loading them dynamically.
  • We implemented JvmNativeLoaderDelegate to intercept library-load requests. When ExecuTorchRuntime or other classes call NativeLoader.loadLibrary("executorch"), it intercepts and maps them to "executorch_jni", which loads the self-contained JNI library (libexecutorch_jni.so/.dylib/.dll) using NativeLibraryLoader.
  • Registered JvmNativeLoaderDelegate via ServiceLoader, which allows the JVM module to dynamically hook into and handle all library loads on desktop platforms cleanly without Android needing to know:
Module / ExecuTorchRuntime (extension/java)
                 │
                 ▼  (calls NativeLoader.loadLibrary("executorch"))
        NativeLoader facade
                 │
                 ▼  (discovers JvmNativeLoaderDelegate via ServiceLoader)
    JvmNativeLoaderDelegate (extension/jvm)
                 │
                 ▼  (maps request for "executorch" to "executorch_jni")
      NativeLibraryLoader (extension/jvm)
                 │
                 ▼  (detects OS/arch and extracts binary from classpath)
Classpath: /native/macos/aarch64/libexecutorch_jni.dylib  ──►  Temp Directory
                                                                      │
                                                                      ▼ (System.load())
                                                              Loaded Native C++ Layer

4. Tests and Verification

  • Relocated EValueTest.kt and TensorTest.kt to the shared extension/java module where they run directly on the host JVM. This makes running tests incredibly fast and allows them to be executed in desktop JVM CI flows without requiring an emulator.
  • Verified all compiles and runs green on JDK 17 (Android debug/release AARs, Shared API jar, and Desktop JVM jar).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. module: android Issues related to Android code, build, and execution release notes: none Do not include this in the release notes

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

java linux cannot work , we need executorch java jar format package ,please support

3 participants