-
Notifications
You must be signed in to change notification settings - Fork 0
JNA: Support GraalVM #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
f36ddc0 to
37a2c95
Compare
| <property name="maven-sources-jar" value="${dist}/${artifactId}-${jna.version}-sources.jar" /> | ||
|
|
||
| <property name="maven-graalvm-javadoc-jar" value="${dist}/jna-graalvm-${jna.version}-javadoc.jar" /> | ||
| <property name="maven-graalvm-sources-jar" value="${dist}/jna-graalvm-${jna.version}-sources.jar" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sources jar for graalvm doesn't build yet
| <fileset dir="${build.native}" includes="jnidispatch.dll,libjnidispatch.*"/> | ||
| <fileset dir="${build.native}" includes="jnidispatch.dll,libjnidispatch.*" excludes="*.a,*.lib"/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
current JARs (non-static) do not ship the static library, to avoid duplicating lib size contribution to JARs
| <jar jarfile="${build}/${native-static.jar}" createUnicodeExtraFields="never" encoding="UTF-8"> | ||
| <fileset dir="${build.native}" includes="jnidispatch.lib,libjnidispatch.a"/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
native-static.jar ships only the static libs
| @@ -0,0 +1,34 @@ | |||
| [versions] | |||
| jna = "5.15.0-SNAPSHOT" | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note for release: should eventually be pinned to minimum support version for gvm
samples/graalvm-native-jna/src/main/resources/META-INF/native-image/proxy-config.json
Outdated
Show resolved
Hide resolved
Signed-off-by: GitHub <[email protected]>
10a3e10 to
8b323da
Compare
Signed-off-by: GitHub <[email protected]>
Adds a JAR publication at `jna-graalvm.jar`, with accompanying build infrastructure, which provides support for JNA within the context of the Substrate Virtual Machine (SVM). GraalVM Native Image targets use SVM instead of JVM at runtime. JNA's current strategy of unpacking libraries at runtime works under SVM, but is suboptimal; the binary is native, so it can simply include JNA object code for the current platform directly. To accomplish this, several GraalVM "feature" implementations are provided in this new publication. By default, regular JNA access is enabled through the `JavaNativeAccess` feature; this class enables reflection and runtime JNI configurations for downstream projects which use JNA. Another feature, `SubstrateStaticJNA`, is experimental because it relies on unstable GraalVM APIs, but instead of loading JNA at runtime from a dynamic library, it builds JNA into the final native image with a static object. These features are enabled through a resource within `META-INF`, called `native-image.properties`, which is picked up by the native image compiler at build time. The new artifact only needs to be present for GraalVM native targets at build time; otherwise, the classes and libraries in `jna-graalvm.jar` are inert. Includes tested support for: - macOS aarch64 - Linux amd64 - feat: add `jna-graalvm.jar` publication - feat: add base `JavaNativeAccess` feature for auto-config of JNA - feat: add initial implementation of `SubstrateStaticJNA` feature - test: sample/test gradle build for native image - chore: ci config to run native sample Signed-off-by: Sam Gammon <[email protected]>
8b323da to
8978b9b
Compare
Summary
Adds a JAR publication at
jna-graalvm.jar, with accompanying build infrastructure, that provides support for JNA within the context of the Substrate Virtual Machine (SVM).JNA is already possible on SVM today, but requires extensive (and app-specific) configuration, which can end up being brittle. If methods aren't caught for configuration at build-time, dispatch at runtime can throw. This PR ships automatic configuration support for GVM to JNA itself, as an optional add-on.
Features
Warning
This PR has been filed on this fork for downstream testing. It is not ready to be filed and reviewed yet. Once functionality is ready and tested, it will be rebased and squashed.
Usage
jna-graalvm.jarto theirnative-imageclasspath--features=com.sun.jna.SubstrateStaticJNAIn addition to baseline configurations required for any use at all of JNA, the base feature leverages GraalVM's analysis to detect when a developer is using JNA features, and then registers configurations appropriately for their classes, too.
For example, when the developer writes:
jna/samples/graalvm-native-jna/src/main/java/com/example/JnaNative.java
Lines 31 to 37 in 10a3e10
... then
CLibraryis registered as a dynamic proxy with GraalVM automatically.Rationale
GraalVM Native Image targets use SVM instead of JVM at runtime. JNA's current strategy of unpacking libraries at runtime works under SVM, but is suboptimal; the binary is native, so it can simply include JNA object code directly. A configuration-only approach also leaves JNA code brittle, because configuration must be specified for all JNA touchpoints used by the app, and must stay in sync over time.
To accomplish automatic configuration, several GraalVM "feature" implementations are provided in this new publication. By default, regular JNA access is enabled through the
JavaNativeAccessfeature; this class enables reflection and runtime JNI configurations for downstream projects which use JNA.Another feature,
SubstrateStaticJNA, is experimental because it relies on unstable GraalVM APIs, but instead of loading JNA at runtime from a dynamic library, it builds JNA into the final native image with a static object.These features are enabled through a resource within
META-INF, callednative-image.properties, which is picked up by the native image compiler at build time. The new artifact only needs to be present for GraalVM native targets at build time; otherwise, the classes and libraries injna-graalvm.jarare inert.Approach
--- title: "SVM + JNA" --- classDiagram note for AbstractJNAFeature "Base Feature" note for JavaNativeAccess "Baseline Configurations" note for StaticJNAFeature "Static JNI Linkage" AbstractJNAFeature --|> JavaNativeAccess AbstractJNAFeature --|> StaticJNAFeature JavaNativeAccess --> UserCode: Detects class AbstractJNAFeature { Common Logic* -- JNI/Proxy Registration Library Resolution + Unpacking } class JavaNativeAccess { Always Active* No change to current behavior* -- Runtime JNI Registration Runtime Proxy Registration Subtype Reachability Handler } class StaticJNAFeature { Active On-Demand* -- Unpacks Static Library at Build Time Enables Static JNI Linkage } class UserCode { class X extends Library ... }Abstract Base
This new class is package-private and provides protected utilities for use exclusively by GraalVM
Featureimplementations; for unfamiliar readers,Features are build-time classes that contribute to compiler configuration.Common logic provided:
jna-graalvm.jarresourceJavaNativeAccessfeaturesequenceDiagram Native Image->>+Feature: Detects `native-image.properties`, feature self-mounts Feature->>+Native Image: Registers reachability handler and common configurations Native Image->>User Code: Analysis phase begins User Code->>Native Image: class X extends Library { ... } Native Image->>-Feature: User extended Library with class X Feature->>-Native Image: Register class X as proxyThis feature is designed to be registered unconditionally in a downstream
native-imagebuild; it is found automatically via thenative-image.propertiesresource, which declares it via--features=...JavaNativeAccess. Thus, (1) having thejna-graalvm.jaron your build-time classpath and (2) using JNA is enough to activate the feature.Configurations are contributed by this feature which always apply to JNA in the context of Substrate, native image's equivalent to JVM: these include runtime JNI access and proxy access, both of which must be declared ahead of time in GraalVM's AOT mode.
What it does:
How to use it:
jna-graalvm.jarto your build-time classpath fornative-imageNote
Many projects register these same configurations within
[proxy,jni,reflect]-config.jsonfiles in their project; these configuration files can be cleaned up downstream once this feature becomes available. Users no longer have to generate this configuration themselves. Extra configurations are inert.SubstrateStaticJNAfeatureThis feature is experimental, because it relies on unstable APIs within GraalVM's native image SDK1. Through a technique known as Static JNI2, the precursor library unpacking step normally needed for JNA's operation can be eliminated entirely. Instead of steps taken at runtime, a static library is unpacked at build time, and built directly into the user's native image.
This has many advantages: the library unpack step is no longer needed and so startup time in JNA-consuming apps is reduced; artifact size is reduced, since native libraries are no longer bundles as resources, and potentially compressed without benefit. Since the binary targets native code, unused variants of
libjnidispatch.[so,dylib,dll]can be omitted, resulting in smaller image sizes.The
StaticJNAFeatureis designed to interoperate with theJavaNativeAccessfeature. The two can be used in a build together, orStaticJNAFeaturecan be omitted to preserve the current library behavior. This feature is opt-in and is not injected by thenative-image.propertiesfile.What it does:
[lib]jnidispatch.[a,lib], at build time, according to current JNA behaviorjnidispatchas a static JNI "built-in"How to use it:
jna-graalvm.jarto your build-time classpath fornative-imagenative-image ... --features=com.sun.jna.SubstrateStaticJNACaution
Obligatory warning that this is an experimental and unstable technique. Please don't rely on it for production use. Once oracle/graal#3359 is fixed, this feature can ship as default.
Footnotes
https://github.com/oracle/graal/issues/3359 ↩
https://www.blog.akhil.cc/static-jni ↩