RFR: Add `--library-path-resolver` option for custom library path resolving

devjeonghwan duke at openjdk.org
Fri Nov 14 15:51:32 UTC 2025


On Thu, 13 Nov 2025 08:37:25 GMT, devjeonghwan <duke at openjdk.org> wrote:

> #### 1. Status Quo
> 
> Currently, `jextract` generates code using two standard loading mechanisms:
> 
> 1.  **Default:** `SymbolLookup.libraryLookup(System.mapLibraryName("name"), ...)`
> 2.  **With `--use-system-load-library`:** `System.loadLibrary("name")`
> 
> Both methods depend on static paths (e.g., `java.library.path`) and do not support runtime path resolution (hooking) without manual code modification.
> 
> #### 2. Problem
> 
> Standard loading fails in dynamic deployment scenarios:
> 
>   * **Bundled Libraries:** Native libraries inside JARs (extracted to temp directories) require loading from an absolute path.
>   * **Dynamic Paths:** Paths determined at runtime based on OS/Arch cannot be handled by static system properties.
> 
> Users currently must manually edit the generated source to inject custom loading logic.
> 
> #### 3. Fix
> 
> Introduced a new CLI option: `--library-path-resolver`.
> This option injects a user-defined static method to resolve the library path (or name) at runtime.
> 
> **Usage:**
> 
> 
> jextract ... --library-path-resolver com.example.Resolver#resolvePath
> 
> 
> **Code Generation:**
> 
> **Case 1: Default (SymbolLookup)**
> 
> 
> // Before
> SymbolLookup.libraryLookup(System.mapLibraryName("foo"), ARENA);
> 
> // After
> SymbolLookup.libraryLookup(com.example.Resolver.resolvePath("foo"), ARENA);
> 
> 
> **Case 2: With `--use-system-load-library`**
> 
> 
> // Before
> System.loadLibrary("foo");
> 
> // After
> System.load(com.example.Resolver.resolvePath("foo"));
> 
> 
> #### 4. Additional Notes
> 
>   * **Method Signature:** The resolver method must match `String <method_name>(String <parameter_name>)`.
>   * **Return Value:**
>       * For `--use-system-load-library`: Must return an **absolute path** (required by `System.load()`).
>       * For Default: Returns a path or name accepted by `SymbolLookup`.
> 
> #### 5. Testing
> 
> Added `TestLibraryPathResolver`.
> 
>   * Dynamic compilation and loading of a custom resolver class.
>   * Correct code generation when the option is present.
>   * Verifying that the custom resolver is actually invoked and that the native library is successfully loaded and linked via the resolved path
> 
> All tests pass locally.

Thanks for the link. The instance-based design looks like the right direction for the future.

However, I believe this PR is still necessary as a practical solution for today, for the following reasons:

1. Framework interference (Spring, Jakarta EE, etc..)
The "Main Wrapper" approach assumes we control exactly when classes are loaded. In reality, frameworks often scan the classpath and touch classes via `reflection` early at startup.
If a framework accesses the jextract-generated class before my Main Wrapper runs its static initializer, the native library is not loaded yet. This causes an `UnsatisfiedLinkError`.

2. Bad API Design
Forcing users to `Always initialize Class A or call initialize method before using Class B(binding class)` is a bad API design. The generated code should be self-contained and able to resolve its library path when needed.

Since this CLI option is purely optional, it doesn't affect the default behavior. It solves a real pain point for library distributors until the new architecture arrives.

-------------

PR Comment: https://git.openjdk.org/jextract/pull/295#issuecomment-3533380496


More information about the jextract-dev mailing list