-
Notifications
You must be signed in to change notification settings - Fork 0
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
JNA: Support GraalVM #1
Conversation
f36ddc0
to
37a2c95
Compare
@@ -69,6 +72,9 @@ | |||
<property name="maven-javadoc-jar" value="${dist}/${artifactId}-${jna.version}-javadoc.jar" /> | |||
<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.jar
to theirnative-image
classpath--features=com.sun.jna.SubstrateStaticJNA
In 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
CLibrary
is 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
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
, 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.jar
are inert.Approach
Abstract Base
This new class is package-private and provides protected utilities for use exclusively by GraalVM
Feature
implementations; for unfamiliar readers,Feature
s are build-time classes that contribute to compiler configuration.Common logic provided:
jna-graalvm.jar
resourceJavaNativeAccess
featureThis feature is designed to be registered unconditionally in a downstream
native-image
build; it is found automatically via thenative-image.properties
resource, which declares it via--features=...JavaNativeAccess
. Thus, (1) having thejna-graalvm.jar
on 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.jar
to your build-time classpath fornative-image
Note
Many projects register these same configurations within
[proxy,jni,reflect]-config.json
files 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.SubstrateStaticJNA
featureThis 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
StaticJNAFeature
is designed to interoperate with theJavaNativeAccess
feature. The two can be used in a build together, orStaticJNAFeature
can be omitted to preserve the current library behavior. This feature is opt-in and is not injected by thenative-image.properties
file.What it does:
[lib]jnidispatch.[a,lib]
, at build time, according to current JNA behaviorjnidispatch
as a static JNI "built-in"How to use it:
jna-graalvm.jar
to your build-time classpath fornative-image
native-image ... --features=com.sun.jna.SubstrateStaticJNA
Caution
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 ↩