Skip to content

Commit

Permalink
Add support for GraalVM
Browse files Browse the repository at this point in the history
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

Signed-off-by: Sam Gammon <[email protected]>
  • Loading branch information
sgammon authored Jun 8, 2024
1 parent f6670c6 commit a94b939
Show file tree
Hide file tree
Showing 12 changed files with 620 additions and 4 deletions.
115 changes: 112 additions & 3 deletions build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
<property name="testjar2" value="${name}-test2.jar"/>
<property name="testjar3" value="${name}-test3.jar"/>
<property name="jar-jpms" value="${name}-jpms.jar"/>
<property name="jar-graalvm" value="${name}-graalvm.jar"/>
<property name="debug" value="true"/>
<property name="debug.native" value="false"/>
<property name="cflags_extra.native" value=""/>
Expand All @@ -60,6 +61,7 @@
<property name="dist-jar" value="${dist}/${jar}"/>
<property name="dist-aar" value="${dist}/${aar}"/>
<property name="dist-jar-jpms" value="${dist}/${jar-jpms}"/>
<property name="dist-jar-graalvm" value="${dist}/${jar-graalvm}" />

<!-- Maven -->
<!-- define Maven coordinates -->
Expand Down Expand Up @@ -88,10 +90,12 @@
<property name="pom-platform-base" value="pom-jna-platform.xml" />
<property name="pom-jpms-base" value="pom-jna-jpms.xml" />
<property name="pom-platform-jpms-base" value="pom-jna-platform-jpms.xml" />
<property name="pom-graalvm-base" value="pom-jna-graalvm.xml" />

<property name="pom" value="${build}/pom-jna.xml" />
<property name="pom-platform" value="${build}/pom-jna-platform.xml" />
<property name="pom-jpms" value="${build}/pom-jna-jpms.xml" />
<property name="pom-graalvm" value="${build}/pom-jna-graalvm.xml" />
<property name="pom-platform-jpms" value="${build}/pom-jna-platform-jpms.xml" />

<target name="default" depends="test" description="Build and Test."/>
Expand Down Expand Up @@ -131,6 +135,7 @@
<copy file="${pom-base}" tofile="${pom}" />
<copy file="${pom-platform-base}" tofile="${pom-platform}" />
<copy file="${pom-jpms-base}" tofile="${pom-jpms}" />
<copy file="${pom-graalvm-base}" tofile="${pom-graalvm}" />
<copy file="${pom-platform-jpms-base}" tofile="${pom-platform-jpms}" />

<replaceregexp match="(&lt;version&gt;).*(&lt;/version&gt;)"
Expand All @@ -148,6 +153,16 @@
flags="g"
file="${pom-jpms}"/>

<replaceregexp match="(&lt;version&gt;)TEMPLATE(&lt;/version&gt;)"
replace="\1${jna.version}\2"
flags="g"
file="${pom-graalvm}"/>

<replaceregexp match="(&lt;version&gt;)GRAALVM_VERSION(&lt;/version&gt;)"
replace="\1${graalvm.version}\2"
flags="g"
file="${pom-graalvm}"/>

<replaceregexp match="(&lt;version&gt;).*(&lt;/version&gt;)"
replace="\1${jna.version}\2"
flags="g"
Expand All @@ -158,6 +173,7 @@
</condition>

<property name="classes" location="${build}/classes"/>
<property name="classes-graalvm" location="${build}/classes-graalvm"/>
<property name="eclipse.classes" location="build.eclipse/classes"/>
<property name="test.classes" location="${build}/test-classes"/>
<property name="reports" value="${build}/reports"/>
Expand Down Expand Up @@ -192,6 +208,7 @@
<not><equals arg1="${libjsig}" arg2=""/></not>
</condition>
<property name="native.jar" value="${os.prefix}.jar"/>
<property name="native-static.jar" value="${os.prefix}-static.jar"/>
<property name="build.native" location="${build}/${native.subdir}"/>
<property name="build.headers" location="${build}/headers"/>
<property name="build.aar" location="${build}/aar"/>
Expand Down Expand Up @@ -248,11 +265,28 @@

<target name="compile" depends="-setup"
description="Compile all Java source">
<!-- Need GraalVM SVM artifact to build features for `jna-graalvm.jar` -->
<path id="graalvm.classpath" />
<artifact:remoteRepository id="central" url="https://repo1.maven.org/maven2/" />
<artifact:dependencies pathId="graalvm.classpath">
<remoteRepository refid="central" />
<dependency groupId="org.graalvm.nativeimage" artifactId="svm" version="${graalvm.version}"/>
<dependency groupId="org.graalvm.sdk" artifactId="nativeimage" version="${graalvm.version}"/>
<dependency groupId="org.graalvm.sdk" artifactId="jniutils" version="${graalvm.version}"/>
</artifact:dependencies>

<delete dir="${build}/jna-src" />
<mkdir dir="${build}/jna-src/com/sun/jna" />

<delete dir="${classes-graalvm}" />
<mkdir dir="${classes-graalvm}" />
<delete dir="${build}/gvm-src" />
<mkdir dir="${build}/gvm-src/com/sun/jna" />

<copy file="src/com/sun/jna/Version.java" todir="${build}/jna-src/com/sun/jna" />
<copy file="lib/gvm/AbstractJNAFeature.java" todir="${build}/gvm-src/com/sun/jna" />
<copy file="lib/gvm/JavaNativeAccess.java" todir="${build}/gvm-src/com/sun/jna" />
<copy file="lib/gvm/SubstrateStaticJNA.java" todir="${build}/gvm-src/com/sun/jna" />

<replaceregexp match='VERSION = ".*";'
replace='VERSION = "${jna.version}";'
Expand Down Expand Up @@ -280,6 +314,19 @@
<src refid="src.path"/>
<exclude name="com/sun/jna/Version.java" />
</javac>
<javac release="11"
destdir="${classes-graalvm}"
includeantruntime="false"
deprecation="on"
debug="${debug}"
encoding="UTF-8"
nativeheaderdir="${build.headers}">
<src location="${build}/gvm-src/com/sun/jna" />
<classpath>
<path refid="graalvm.classpath"/>
<pathelement location="${classes}" />
</classpath>
</javac>
</target>

<target name=":jar">
Expand Down Expand Up @@ -562,13 +609,27 @@ osname=macosx;processor=aarch64
includes="LICENSE,LGPL2.1,AL2.0"
prefix="META-INF"/>
</jar>
<jar jarfile="${build}/${jar-graalvm}" duplicate="preserve" createUnicodeExtraFields="never" encoding="UTF-8">
<fileset dir="${classes-graalvm}">
<patternset refid="jar-compiled"/>
</fileset>
<zipfileset dir="lib/gvm"
includes="native-image.properties"
prefix="META-INF/native-image/com.sun.jna"/>
<zipfileset dir="."
includes="LICENSE,LGPL2.1,AL2.0"
prefix="META-INF"/>
</jar>
<zip zipfile="${build}/${minjar}">
<zipfileset src="${build}/${jar}" excludes="**/*jnidispatch*"/>
</zip>
<jar jarfile="${build}/jna-jpms.jar" duplicate="preserve" createUnicodeExtraFields="never" encoding="UTF-8" manifest="${build}/manifest/module.mf">
<zipfileset src="${build}/${jar}" excludes="META-INF/MANIFEST.mf"/>
<zipfileset dir="${build}/manifest/" includes="module-info.class" prefix="META-INF/versions/9"/>
</jar>
<jar jarfile="${build}/jna-graalvm.jar" duplicate="preserve" createUnicodeExtraFields="never" encoding="UTF-8">
<zipfileset src="${build}/${jar-graalvm}" excludes="META-INF/MANIFEST.mf"/>
</jar>
</target>

<target name="aar" depends="jar" description="Build Android Archive">
Expand Down Expand Up @@ -1014,28 +1075,45 @@ cd ..
<arg value="JNA_JNI_VERSION=${jni.version}"/>
<arg value="CHECKSUM=${jni.md5}"/>
</exec>
<!-- Include only dynamic library variants for JVM JAR targets. -->
<mkdir dir="${classes}/${native.path}"/>
<copy todir="${classes}/${native.path}">
<fileset dir="${build.native}"
includes="jnidispatch.dll,libjnidispatch.*"/>
includes="jnidispatch.dll,libjnidispatch.*"
excludes="*.lib,*.a"/>
</copy>
<mkdir dir="${eclipse.classes}/${native.path}"/>
<copy todir="${eclipse.classes}/${native.path}"
failonerror="false">
<fileset dir="${build.native}"
includes="jnidispatch.dll,libjnidispatch.*"
excludes="*.lib,*.a"/>
</copy>
<!-- Include both dynamic and static library variants for all operating systems in the GraalVM JAR. -->
<mkdir dir="${classes-graalvm}/${native.path}"/>
<copy todir="${classes-graalvm}/${native.path}">
<fileset dir="${build.native}"
includes="jnidispatch.dll,libjnidispatch.*"/>
</copy>
<!-- For web start, native libraries may be provided in the root of -->
<!-- an included jar file -->
<jar jarfile="${build}/${native.jar}" createUnicodeExtraFields="never" encoding="UTF-8">
<fileset dir="${build.native}" includes="jnidispatch.dll,libjnidispatch.*"/>
<fileset dir="${build.native}" includes="jnidispatch.dll,libjnidispatch.*" excludes="*.a,*.lib"/>
<manifest>
<attribute name="Implementation-Version" value="${jni.version} b${jni.build}"/>
<attribute name="Specification-Version" value="${jni.version}"/>
</manifest>
</jar>
<jar jarfile="${build}/${native-static.jar}" createUnicodeExtraFields="never" encoding="UTF-8">
<fileset dir="${build.native}" includes="jnidispatch.lib,libjnidispatch.a"/>
<manifest>
<attribute name="Implementation-Version" value="${jni.version} b${jni.build}"/>
<attribute name="Specification-Version" value="${jni.version}"/>
</manifest>
</jar>
<copy todir="${lib.native}">
<fileset dir="${build}" includes="${native.jar}"/>
<fileset dir="${build}" includes="${native-static.jar}"/>
</copy>
</target>

Expand Down Expand Up @@ -1351,7 +1429,7 @@ cd ..
<target name="dist" depends="jar,aar,javadoc,contrib-jars,compile-tests,native"
description="Build distribution files">
<copy todir="${dist}" force="true" overwrite="true">
<fileset dir="${build}" includes="${jar},${minjar},${aar},${jar-jpms}"/>
<fileset dir="${build}" includes="${jar},${minjar},${aar},${jar-jpms},${jar-graalvm}"/>
<fileset dir="${contrib}/platform/dist" includes="jna-platform.jar,jna-platform-jpms.jar"/>
<fileset dir="${lib.native}">
<include name="*.jar"/>
Expand Down Expand Up @@ -1431,6 +1509,12 @@ cd ..
<arg value="-Djavadoc=${maven-javadoc-jar}"/>
</artifact:mvn>

<artifact:mvn failonerror="true">
<arg value="org.apache.maven.plugins:maven-install-plugin:2.5:install-file"/>
<arg value="-DpomFile=${pom-graalvm}"/>
<arg value="-Dfile=${dist-jar-graalvm}"/>
</artifact:mvn>

<artifact:mvn failonerror="true">
<arg value="org.apache.maven.plugins:maven-install-plugin:2.5:install-file"/>
<arg value="-DpomFile=${pom-platform}"/>
Expand Down Expand Up @@ -1483,6 +1567,17 @@ cd ..
<arg value="-Dclassifiers=sources,javadoc"/>
</artifact:mvn>

<artifact:mvn failonerror="true">
<arg value="org.apache.maven.plugins:maven-deploy-plugin:2.7:deploy-file"/>
<arg value="-Durl=${maven-snapshots-repository-url}"/>
<arg value="-DrepositoryId=${maven-snapshots-repository-id}"/>
<arg value="-DpomFile=${pom-graalvm}"/>
<arg value="-Dfile=${dist-jar-graalvm}"/>
<arg value="-Dfiles=${maven-sources-jar},${maven-javadoc-jar}"/>
<arg value="-Dtypes=jar,jar"/>
<arg value="-Dclassifiers=sources,javadoc"/>
</artifact:mvn>

<artifact:mvn failonerror="true">
<arg value="org.apache.maven.plugins:maven-deploy-plugin:2.7:deploy-file"/>
<arg value="-Durl=${maven-snapshots-repository-url}"/>
Expand Down Expand Up @@ -1538,6 +1633,19 @@ cd ..
<arg value="-Dgpg.useagent=true"/>
</artifact:mvn>

<!-- sign and deploy the graalvm artifact -->
<artifact:mvn failonerror="true">
<arg value="org.apache.maven.plugins:maven-gpg-plugin:${version-maven-gpg-plugin}:sign-and-deploy-file"/>
<arg value="-Durl=${maven-staging-repository-url}"/>
<arg value="-DrepositoryId=${maven-staging-repository-id}"/>
<arg value="-DpomFile=${pom-graalvm}"/>
<arg value="-Dfile=${dist-jar-graalvm}"/>
<arg value="-Dfiles=${maven-sources-jar},${maven-javadoc-jar}"/>
<arg value="-Dtypes=jar,jar"/>
<arg value="-Dclassifiers=sources,javadoc"/>
<arg value="-Dgpg.useagent=true"/>
</artifact:mvn>

<!-- sign and deploy the platform artifact -->
<artifact:mvn failonerror="true">
<arg value="org.apache.maven.plugins:maven-gpg-plugin:${version-maven-gpg-plugin}:sign-and-deploy-file"/>
Expand All @@ -1553,6 +1661,7 @@ cd ..
</target>

<target name="-bootstrap-maven">
<artifact:remoteRepository id="central" url="https://repo1.maven.org/maven2/" />
<artifact:remoteRepository id="remote.mavenCentral" url="https://repo1.maven.org/maven2/" />
<artifact:dependencies pathId="dependency.dummy">
<remoteRepository refid="remote.mavenCentral" />
Expand Down
1 change: 1 addition & 0 deletions common.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
</or>
</condition>
<property name="jna.version" value="${jna.major}.${jna.minor}.${jna.revision}${version.suffix}"/>
<property name="graalvm.version" value="24.0.1" />
<property name="osgi.version" value="${jna.major}.${jna.minor}.${jna.revision}"/>
<!-- jnidispatch library release version -->
<property name="jni.major" value="7"/>
Expand Down
Loading

0 comments on commit a94b939

Please sign in to comment.