Skip to content

Commit cdaa7de

Browse files
committed
Add JNI activation and lib path managment
fix quarkusio#2999
1 parent aaef669 commit cdaa7de

File tree

5 files changed

+100
-29
lines changed

5 files changed

+100
-29
lines changed

core/creator/src/main/java/io/quarkus/creator/phase/nativeimage/NativeImagePhase.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -381,15 +381,23 @@ public void provideOutcome(AppCreator ctx) throws AppCreatorException {
381381
}
382382
}
383383

384-
enableSslNative = properties.getProperty("quarkus.ssl.native") != null
385-
? Boolean.parseBoolean(properties.getProperty("quarkus.ssl.native"))
384+
final String enableSslNativeFromProperties = properties.getProperty("quarkus.ssl.native");
385+
enableSslNative = enableSslNativeFromProperties != null
386+
? Boolean.parseBoolean(enableSslNativeFromProperties)
386387
: false;
388+
if (!enableJni) {
389+
final String enableJniFromProperties = properties.getProperty("quarkus.jni.enable");
390+
enableJni = enableJniFromProperties != null
391+
? Boolean.parseBoolean(enableJniFromProperties)
392+
: false;
393+
}
387394
}
388395
if (enableSslNative) {
389396
enableHttpsUrlHandler = true;
390397
enableJni = true;
391398
enableAllSecurityServices = true;
392399
}
400+
393401
if (additionalBuildArgs != null) {
394402
command.addAll(additionalBuildArgs);
395403
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package io.quarkus.deployment;
2+
3+
import java.util.List;
4+
5+
import io.quarkus.deployment.annotations.BuildProducer;
6+
import io.quarkus.deployment.annotations.BuildStep;
7+
import io.quarkus.deployment.builditem.JniBuildItem;
8+
import io.quarkus.runtime.annotations.ConfigItem;
9+
import io.quarkus.runtime.annotations.ConfigPhase;
10+
import io.quarkus.runtime.annotations.ConfigRoot;
11+
12+
public class JniProcessor {
13+
14+
JniConfig jni;
15+
16+
@ConfigRoot(phase = ConfigPhase.BUILD_TIME)
17+
static class JniConfig {
18+
/**
19+
* Paths of library to load.
20+
*/
21+
@ConfigItem(name = "libraryPath")
22+
List<String> libraryPaths;
23+
24+
/**
25+
* Enable JNI support.
26+
*/
27+
@ConfigItem(defaultValue = "false")
28+
boolean enable = false;
29+
}
30+
31+
@BuildStep
32+
void setupJni(BuildProducer<JniBuildItem> jniProducer) {
33+
if ((jni.enable) || !jni.libraryPaths.isEmpty()) {
34+
jniProducer.produce(new JniBuildItem(jni.libraryPaths));
35+
}
36+
}
37+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package io.quarkus.deployment.builditem;
2+
3+
import java.util.List;
4+
5+
import io.quarkus.builder.item.MultiBuildItem;
6+
7+
public final class JniBuildItem extends MultiBuildItem {
8+
9+
private final List<String> libraryPaths;
10+
11+
public JniBuildItem(List<String> libraryPaths) {
12+
this.libraryPaths = libraryPaths;
13+
}
14+
15+
public List<String> getLibraryPaths() {
16+
return libraryPaths;
17+
}
18+
19+
}

core/deployment/src/main/java/io/quarkus/deployment/steps/MainClassBuildStep.java

Lines changed: 15 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import static io.quarkus.gizmo.MethodDescriptor.ofConstructor;
44
import static io.quarkus.gizmo.MethodDescriptor.ofMethod;
55

6+
import java.io.File;
67
import java.lang.reflect.Modifier;
78
import java.util.List;
89
import java.util.Optional;
@@ -125,32 +126,22 @@ MainClassBuildItem build(List<StaticBytecodeRecorderBuildItem> staticInitTasks,
125126

126127
// Set the SSL system properties
127128
if (!javaLibraryPathAdditionalPaths.isEmpty()) {
128-
// FIXME: this is the code we should use but I couldn't get GraalVM to work with a java.library.path containing multiple paths.
129-
// We need to dig further but for now, we need this to work.
130-
// ResultHandle javaLibraryPath = mv.newInstance(ofConstructor(StringBuilder.class, String.class),
131-
// mv.invokeStaticMethod(ofMethod(System.class, "getProperty", String.class, String.class), mv.load(JAVA_LIBRARY_PATH)));
132-
// for (JavaLibraryPathAdditionalPathBuildItem javaLibraryPathAdditionalPath : javaLibraryPathAdditionalPaths) {
133-
// ResultHandle javaLibraryPathLength = mv.invokeVirtualMethod(ofMethod(StringBuilder.class, "length", int.class), javaLibraryPath);
134-
// mv.ifNonZero(javaLibraryPathLength).trueBranch()
135-
// .invokeVirtualMethod(ofMethod(StringBuilder.class, "append", StringBuilder.class, String.class), javaLibraryPath, mv.load(File.pathSeparator));
136-
// mv.invokeVirtualMethod(ofMethod(StringBuilder.class, "append", StringBuilder.class, String.class), javaLibraryPath,
137-
// mv.load(javaLibraryPathAdditionalPath.getPath()));
138-
// }
139-
// mv.invokeStaticMethod(ofMethod(System.class, "setProperty", String.class, String.class, String.class),
140-
// mv.load(JAVA_LIBRARY_PATH), mv.invokeVirtualMethod(ofMethod(StringBuilder.class, "toString", String.class), javaLibraryPath));
141-
142-
ResultHandle isJavaLibraryPathEmpty = mv.invokeVirtualMethod(ofMethod(String.class, "isEmpty", boolean.class),
129+
ResultHandle javaLibraryPath = mv.newInstance(ofConstructor(StringBuilder.class, String.class),
143130
mv.invokeStaticMethod(ofMethod(System.class, "getProperty", String.class, String.class),
144131
mv.load(JAVA_LIBRARY_PATH)));
145-
146-
BytecodeCreator inGraalVMCode = mv
147-
.ifNonZero(mv.invokeStaticMethod(ofMethod(ImageInfo.class, "inImageRuntimeCode", boolean.class)))
148-
.trueBranch();
149-
150-
inGraalVMCode.ifNonZero(isJavaLibraryPathEmpty).trueBranch().invokeStaticMethod(
151-
ofMethod(System.class, "setProperty", String.class, String.class, String.class),
152-
inGraalVMCode.load(JAVA_LIBRARY_PATH),
153-
inGraalVMCode.load(javaLibraryPathAdditionalPaths.iterator().next().getPath()));
132+
for (JavaLibraryPathAdditionalPathBuildItem javaLibraryPathAdditionalPath : javaLibraryPathAdditionalPaths) {
133+
ResultHandle javaLibraryPathLength = mv.invokeVirtualMethod(ofMethod(StringBuilder.class, "length", int.class),
134+
javaLibraryPath);
135+
mv.ifNonZero(javaLibraryPathLength).trueBranch()
136+
.invokeVirtualMethod(ofMethod(StringBuilder.class, "append", StringBuilder.class, String.class),
137+
javaLibraryPath, mv.load(File.pathSeparator));
138+
mv.invokeVirtualMethod(ofMethod(StringBuilder.class, "append", StringBuilder.class, String.class),
139+
javaLibraryPath,
140+
mv.load(javaLibraryPathAdditionalPath.getPath()));
141+
}
142+
mv.invokeStaticMethod(ofMethod(System.class, "setProperty", String.class, String.class, String.class),
143+
mv.load(JAVA_LIBRARY_PATH),
144+
mv.invokeVirtualMethod(ofMethod(StringBuilder.class, "toString", String.class), javaLibraryPath));
154145
}
155146

156147
if (sslTrustStoreSystemProperty.isPresent()) {

core/deployment/src/main/java/io/quarkus/deployment/steps/SubstrateConfigBuildStep.java

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import io.quarkus.deployment.annotations.Record;
1717
import io.quarkus.deployment.builditem.ExtensionSslNativeSupportBuildItem;
1818
import io.quarkus.deployment.builditem.JavaLibraryPathAdditionalPathBuildItem;
19+
import io.quarkus.deployment.builditem.JniBuildItem;
1920
import io.quarkus.deployment.builditem.SslNativeConfigBuildItem;
2021
import io.quarkus.deployment.builditem.SslTrustStoreSystemPropertyBuildItem;
2122
import io.quarkus.deployment.builditem.SystemPropertyBuildItem;
@@ -39,6 +40,7 @@ class SubstrateConfigBuildStep {
3940
void build(SslContextConfigurationTemplate sslContextConfigurationTemplate,
4041
List<SubstrateConfigBuildItem> substrateConfigBuildItems,
4142
SslNativeConfigBuildItem sslNativeConfig,
43+
List<JniBuildItem> jniBuildItems,
4244
List<ExtensionSslNativeSupportBuildItem> extensionSslNativeSupport,
4345
BuildProducer<SubstrateProxyDefinitionBuildItem> proxy,
4446
BuildProducer<SubstrateResourceBundleBuildItem> resourceBundle,
@@ -87,8 +89,7 @@ void build(SslContextConfigurationTemplate sslContextConfigurationTemplate,
8789
Path linuxPath = linuxLibDirectory.resolve(LIB_SUN_EC);
8890

8991
// We add . as it might be useful in a containerized world
90-
// FIXME: it seems GraalVM does not support having multiple paths in java.library.path
91-
//javaLibraryPathAdditionalPath.produce(new JavaLibraryPathAdditionalPathBuildItem("."));
92+
javaLibraryPathAdditionalPath.produce(new JavaLibraryPathAdditionalPathBuildItem("."));
9293
if (Files.exists(linuxPath)) {
9394
// On Linux, the SunEC library is in jre/lib/amd64/
9495
// This is useful for testing or if you have a similar environment in production
@@ -112,8 +113,23 @@ void build(SslContextConfigurationTemplate sslContextConfigurationTemplate,
112113
}
113114
}
114115
}
115-
116116
nativeImage.produce(new SubstrateSystemPropertyBuildItem("quarkus.ssl.native", sslNativeEnabled.toString()));
117+
118+
if(!jniBuildItems.isEmpty()) {
119+
boolean enableJni = false;
120+
for (JniBuildItem jniBuildItem : jniBuildItems) {
121+
enableJni = true;
122+
if (jniBuildItem.getLibraryPaths() != null && !jniBuildItem.getLibraryPaths().isEmpty()) {
123+
for (String path : jniBuildItem.getLibraryPaths()) {
124+
javaLibraryPathAdditionalPath
125+
.produce(new JavaLibraryPathAdditionalPathBuildItem(path));
126+
}
127+
}
128+
}
129+
if (enableJni) {
130+
nativeImage.produce(new SubstrateSystemPropertyBuildItem("quarkus.jni.enable", "true"));
131+
}
132+
}
117133
}
118134

119135
private Boolean isSslNativeEnabled(SslNativeConfigBuildItem sslNativeConfig,

0 commit comments

Comments
 (0)