From 853e9c49c6a6e27cd196c8028ac4203d8faae37c Mon Sep 17 00:00:00 2001 From: Glavo Date: Tue, 3 Oct 2023 05:54:37 +0800 Subject: [PATCH 01/16] NativeImageFeatures --- pom.xml | 6 ++ .../jansi/internal/ffm/Kernel32.java | 9 +- .../internal/ffm/NativeImageFeatures.java | 101 ++++++++++++++++++ .../jansi/internal/ffm/PosixCLibrary.java | 12 ++- 4 files changed, 121 insertions(+), 7 deletions(-) create mode 100644 src/main/java/org/fusesource/jansi/internal/ffm/NativeImageFeatures.java diff --git a/pom.xml b/pom.xml index 49bf9c81..8c2d3d19 100644 --- a/pom.xml +++ b/pom.xml @@ -109,6 +109,12 @@ + + org.graalvm.sdk + nativeimage + 23.1.0 + true + org.junit.jupiter junit-jupiter diff --git a/src/main/java/org/fusesource/jansi/internal/ffm/Kernel32.java b/src/main/java/org/fusesource/jansi/internal/ffm/Kernel32.java index a657e096..bed95e19 100644 --- a/src/main/java/org/fusesource/jansi/internal/ffm/Kernel32.java +++ b/src/main/java/org/fusesource/jansi/internal/ffm/Kernel32.java @@ -244,7 +244,7 @@ public static int ScrollConsoleScreenBuffer( SMALL_RECT lpClipRectangle, COORD dwDestinationOrigin, CHAR_INFO lpFill) { - MethodHandle mh$ = requireNonNull(ScrollConsoleScreenBuffer$MH, "ScrollConsoleScreenBuffer"); + MethodHandle mh$ = requireNonNull(ScrollConsoleScreenBufferW$MH, "ScrollConsoleScreenBuffer"); try { return (int) mh$.invokeExact(hConsoleOutput, lpScrollRectangle, lpClipRectangle, dwDestinationOrigin, lpFill); @@ -318,8 +318,9 @@ public static String getErrorMessage(int errorCode) { private static final SymbolLookup SYMBOL_LOOKUP; static { + System.loadLibrary("msvcrt"); System.loadLibrary("Kernel32"); - SYMBOL_LOOKUP = SymbolLookup.loaderLookup().or(Linker.nativeLinker().defaultLookup()); + SYMBOL_LOOKUP = SymbolLookup.loaderLookup(); } static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { @@ -396,8 +397,8 @@ static MethodHandle downcallHandle(String name, FunctionDescriptor fdesc) { static final MethodHandle GetConsoleScreenBufferInfo$MH = downcallHandle( "GetConsoleScreenBufferInfo", FunctionDescriptor.of(C_INT$LAYOUT, C_POINTER$LAYOUT, C_POINTER$LAYOUT)); - static final MethodHandle ScrollConsoleScreenBuffer$MH = downcallHandle( - "ScrollConsoleScreenBuffer", + static final MethodHandle ScrollConsoleScreenBufferW$MH = downcallHandle( + "ScrollConsoleScreenBufferW", FunctionDescriptor.of( C_INT$LAYOUT, C_POINTER$LAYOUT, diff --git a/src/main/java/org/fusesource/jansi/internal/ffm/NativeImageFeatures.java b/src/main/java/org/fusesource/jansi/internal/ffm/NativeImageFeatures.java new file mode 100644 index 00000000..85ddfa8e --- /dev/null +++ b/src/main/java/org/fusesource/jansi/internal/ffm/NativeImageFeatures.java @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2009-2023 the original author(s). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fusesource.jansi.internal.ffm; + +import java.lang.foreign.*; + +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.hosted.Feature; +import org.graalvm.nativeimage.hosted.RuntimeForeignAccess; + +import static java.lang.foreign.ValueLayout.*; + +public final class NativeImageFeatures implements Feature { + + private static void registerForDowncall(MemoryLayout resLayout, MemoryLayout... argLayouts) { + RuntimeForeignAccess.registerForDowncall(FunctionDescriptor.of(resLayout, argLayouts)); + } + + @Override + public void duringSetup(DuringSetupAccess access) { + if (Platform.includedIn(Platform.WINDOWS.class)) { + final OfShort C_SHORT$LAYOUT = JAVA_SHORT; + final OfInt C_INT$LAYOUT = JAVA_INT; + final AddressLayout C_POINTER$LAYOUT = ADDRESS; + + StructLayout COORD$LAYOUT = + MemoryLayout.structLayout(C_SHORT$LAYOUT.withName("x"), C_SHORT$LAYOUT.withName("y")); + + // WaitForSingleObject + registerForDowncall(C_INT$LAYOUT, C_POINTER$LAYOUT, C_INT$LAYOUT); + // GetStdHandle + registerForDowncall(C_POINTER$LAYOUT, C_INT$LAYOUT); + // FormatMessageW + registerForDowncall( + C_INT$LAYOUT, + C_INT$LAYOUT, + C_POINTER$LAYOUT, + C_INT$LAYOUT, + C_INT$LAYOUT, + C_POINTER$LAYOUT, + C_INT$LAYOUT, + C_POINTER$LAYOUT); + // SetConsoleTextAttribute + registerForDowncall(C_INT$LAYOUT, C_POINTER$LAYOUT, C_SHORT$LAYOUT); + // SetConsoleMode + registerForDowncall(C_INT$LAYOUT, C_POINTER$LAYOUT, C_INT$LAYOUT); + // GetConsoleMode + registerForDowncall(C_INT$LAYOUT, C_POINTER$LAYOUT, C_POINTER$LAYOUT); + // SetConsoleTitleW + registerForDowncall(C_INT$LAYOUT, C_POINTER$LAYOUT); + // SetConsoleCursorPosition + registerForDowncall(C_INT$LAYOUT, C_POINTER$LAYOUT, COORD$LAYOUT); + // FillConsoleOutputCharacterW + registerForDowncall( + C_INT$LAYOUT, C_POINTER$LAYOUT, C_SHORT$LAYOUT, C_INT$LAYOUT, COORD$LAYOUT, C_POINTER$LAYOUT); + // FillConsoleOutputAttribute + registerForDowncall( + C_INT$LAYOUT, C_POINTER$LAYOUT, C_SHORT$LAYOUT, C_INT$LAYOUT, COORD$LAYOUT, C_POINTER$LAYOUT); + // WriteConsoleW + registerForDowncall( + C_INT$LAYOUT, C_POINTER$LAYOUT, C_POINTER$LAYOUT, C_INT$LAYOUT, C_POINTER$LAYOUT, C_POINTER$LAYOUT); + // ReadConsoleInputW + registerForDowncall(C_INT$LAYOUT, C_POINTER$LAYOUT, C_POINTER$LAYOUT, C_INT$LAYOUT, C_POINTER$LAYOUT); + // PeekConsoleInputW + registerForDowncall(C_INT$LAYOUT, C_POINTER$LAYOUT, C_POINTER$LAYOUT, C_INT$LAYOUT, C_POINTER$LAYOUT); + // GetConsoleScreenBufferInfo + registerForDowncall(C_INT$LAYOUT, C_POINTER$LAYOUT, C_POINTER$LAYOUT); + // ScrollConsoleScreenBuffer + registerForDowncall( + C_INT$LAYOUT, C_POINTER$LAYOUT, C_POINTER$LAYOUT, C_POINTER$LAYOUT, COORD$LAYOUT, C_POINTER$LAYOUT); + // GetLastError + registerForDowncall(C_INT$LAYOUT); + // GetFileType + registerForDowncall(C_INT$LAYOUT, C_POINTER$LAYOUT); + // _get_osfhandle + registerForDowncall(C_POINTER$LAYOUT, C_INT$LAYOUT); + // NtQueryObject + registerForDowncall(JAVA_INT, ADDRESS, JAVA_INT, ADDRESS, JAVA_LONG, ADDRESS); + } else if (Platform.includedIn(Platform.LINUX.class) || Platform.includedIn(Platform.DARWIN.class)) { + // ioctl + registerForDowncall(ValueLayout.JAVA_INT, ValueLayout.JAVA_INT, ValueLayout.JAVA_LONG, ValueLayout.ADDRESS); + // isatty + registerForDowncall(ValueLayout.JAVA_INT, ValueLayout.JAVA_INT); + } else { + throw new UnsupportedOperationException("Unsupported platform"); + } + } +} diff --git a/src/main/java/org/fusesource/jansi/internal/ffm/PosixCLibrary.java b/src/main/java/org/fusesource/jansi/internal/ffm/PosixCLibrary.java index 30e959b9..2ed2df8f 100644 --- a/src/main/java/org/fusesource/jansi/internal/ffm/PosixCLibrary.java +++ b/src/main/java/org/fusesource/jansi/internal/ffm/PosixCLibrary.java @@ -52,14 +52,20 @@ final class PosixCLibrary implements AnsiConsoleSupport.CLibrary { ValueLayout.JAVA_SHORT); ws_col = wsLayout.varHandle(MemoryLayout.PathElement.groupElement("ws_col")); Linker linker = Linker.nativeLinker(); + SymbolLookup lookup; + if (System.getProperty("org.graalvm.nativeimage.imagecode") != null) { + lookup = SymbolLookup.loaderLookup(); + } else { + lookup = linker.defaultLookup(); + } + ioctl = linker.downcallHandle( - linker.defaultLookup().find("ioctl").get(), + lookup.find("ioctl").get(), FunctionDescriptor.of( ValueLayout.JAVA_INT, ValueLayout.JAVA_INT, ValueLayout.JAVA_LONG, ValueLayout.ADDRESS), Linker.Option.firstVariadicArg(2)); isatty = linker.downcallHandle( - linker.defaultLookup().find("isatty").get(), - FunctionDescriptor.of(ValueLayout.JAVA_INT, ValueLayout.JAVA_INT)); + lookup.find("isatty").get(), FunctionDescriptor.of(ValueLayout.JAVA_INT, ValueLayout.JAVA_INT)); } @Override From f7a948de659cb1bc80f829a4530d303446740e25 Mon Sep 17 00:00:00 2001 From: Glavo Date: Tue, 3 Oct 2023 06:28:22 +0800 Subject: [PATCH 02/16] Use provided scope --- pom.xml | 1 + .../org/fusesource/jansi/internal/AnsiConsoleSupportHolder.java | 1 + 2 files changed, 2 insertions(+) diff --git a/pom.xml b/pom.xml index 8c2d3d19..b6284015 100644 --- a/pom.xml +++ b/pom.xml @@ -113,6 +113,7 @@ org.graalvm.sdk nativeimage 23.1.0 + provided true diff --git a/src/main/java/org/fusesource/jansi/internal/AnsiConsoleSupportHolder.java b/src/main/java/org/fusesource/jansi/internal/AnsiConsoleSupportHolder.java index eb049f98..f065d7c8 100644 --- a/src/main/java/org/fusesource/jansi/internal/AnsiConsoleSupportHolder.java +++ b/src/main/java/org/fusesource/jansi/internal/AnsiConsoleSupportHolder.java @@ -32,6 +32,7 @@ private static AnsiConsoleSupport getDefaultProvider() { .getConstructor(boolean.class) .newInstance(true); } catch (Throwable ignored) { + ignored.printStackTrace(); } return new org.fusesource.jansi.internal.jni.AnsiConsoleSupportImpl(); From a1f34c60dea5acf3fbd80cbf0730925c64f71b9c Mon Sep 17 00:00:00 2001 From: Glavo Date: Tue, 3 Oct 2023 06:35:32 +0800 Subject: [PATCH 03/16] print debug message --- .../fusesource/jansi/internal/AnsiConsoleSupportHolder.java | 2 +- .../fusesource/jansi/internal/ffm/AnsiConsoleSupportImpl.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/fusesource/jansi/internal/AnsiConsoleSupportHolder.java b/src/main/java/org/fusesource/jansi/internal/AnsiConsoleSupportHolder.java index f065d7c8..ed6e9680 100644 --- a/src/main/java/org/fusesource/jansi/internal/AnsiConsoleSupportHolder.java +++ b/src/main/java/org/fusesource/jansi/internal/AnsiConsoleSupportHolder.java @@ -32,7 +32,7 @@ private static AnsiConsoleSupport getDefaultProvider() { .getConstructor(boolean.class) .newInstance(true); } catch (Throwable ignored) { - ignored.printStackTrace(); + ignored.printStackTrace(); // TODO: for debug, should be deleted before merging } return new org.fusesource.jansi.internal.jni.AnsiConsoleSupportImpl(); diff --git a/src/main/java/org/fusesource/jansi/internal/ffm/AnsiConsoleSupportImpl.java b/src/main/java/org/fusesource/jansi/internal/ffm/AnsiConsoleSupportImpl.java index bc252b41..f22f3ac7 100644 --- a/src/main/java/org/fusesource/jansi/internal/ffm/AnsiConsoleSupportImpl.java +++ b/src/main/java/org/fusesource/jansi/internal/ffm/AnsiConsoleSupportImpl.java @@ -33,7 +33,8 @@ public AnsiConsoleSupportImpl() {} public AnsiConsoleSupportImpl(boolean checkNativeAccess) { if (checkNativeAccess && !AnsiConsoleSupportImpl.class.getModule().isNativeAccessEnabled()) { - throw new UnsupportedOperationException("Native access is not enabled for the current module"); + throw new UnsupportedOperationException( + "Native access is not enabled for the current module: " + AnsiConsoleSupportImpl.class.getModule()); } } From b6d14766e9373b75d899102fc6f185dbf44b9fac Mon Sep 17 00:00:00 2001 From: Glavo Date: Tue, 3 Oct 2023 16:55:04 +0800 Subject: [PATCH 04/16] update --- pom.xml | 13 ++ .../internal/AnsiConsoleSupportHolder.java | 18 +-- .../jansi/internal/NativeImageFeature.java | 54 ++++++++ .../org/fusesource/jansi/internal/OSInfo.java | 115 ++++++++++-------- ....java => NativeImageDowncallRegister.java} | 12 +- .../jansi/internal/ffm/PosixCLibrary.java | 3 +- .../native-image/jansi/resource-config.json | 3 +- 7 files changed, 152 insertions(+), 66 deletions(-) create mode 100644 src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java rename src/main/java/org/fusesource/jansi/internal/ffm/{NativeImageFeatures.java => NativeImageDowncallRegister.java} (93%) diff --git a/pom.xml b/pom.xml index b6284015..8e4adda2 100644 --- a/pom.xml +++ b/pom.xml @@ -206,9 +206,22 @@ **/ffm/*.java + **/NativeImageFeature.java + + jdk-9 + + compile + + + 9 + + **/NativeImageFeature.java + + + jdk-21 diff --git a/src/main/java/org/fusesource/jansi/internal/AnsiConsoleSupportHolder.java b/src/main/java/org/fusesource/jansi/internal/AnsiConsoleSupportHolder.java index ed6e9680..c3ff661d 100644 --- a/src/main/java/org/fusesource/jansi/internal/AnsiConsoleSupportHolder.java +++ b/src/main/java/org/fusesource/jansi/internal/AnsiConsoleSupportHolder.java @@ -25,14 +25,16 @@ public final class AnsiConsoleSupportHolder { private static final Throwable ERR; private static AnsiConsoleSupport getDefaultProvider() { - try { - // Call the specialized constructor to check whether the module has native access enabled - // If not, fallback to JNI to avoid the JDK printing warnings in stderr - return (AnsiConsoleSupport) Class.forName("org.fusesource.jansi.internal.ffm.AnsiConsoleSupportImpl") - .getConstructor(boolean.class) - .newInstance(true); - } catch (Throwable ignored) { - ignored.printStackTrace(); // TODO: for debug, should be deleted before merging + if (!OSInfo.isInImageCode()) { + try { + // Call the specialized constructor to check whether the module has native access enabled + // If not, fallback to JNI to avoid the JDK printing warnings in stderr + return (AnsiConsoleSupport) Class.forName("org.fusesource.jansi.internal.ffm.AnsiConsoleSupportImpl") + .getConstructor(boolean.class) + .newInstance(true); + } catch (Throwable ignored) { + ignored.printStackTrace(); // TODO: for debug, should be deleted before merging + } } return new org.fusesource.jansi.internal.jni.AnsiConsoleSupportImpl(); diff --git a/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java b/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java new file mode 100644 index 00000000..c64c0ef2 --- /dev/null +++ b/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2009-2023 the original author(s). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.fusesource.jansi.internal; + +import org.fusesource.jansi.AnsiConsole; +import org.graalvm.nativeimage.hosted.Feature; +import org.graalvm.nativeimage.hosted.RuntimeResourceAccess; + +public class NativeImageFeature implements Feature { + @Override + public String getURL() { + return "https://github.com/fusesource/jansi"; + } + + @Override + public void duringSetup(DuringSetupAccess access) { + String providers = System.getProperty(AnsiConsole.JANSI_PROVIDERS); + if (providers != null && providers.contains("ffm")) { + try { + // FFM is only available in JDK 21+, so we need to compile it separately + Class.forName("org.fusesource.jansi.internal.ffm.NativeImageDowncallRegister") + .getMethod("registerForDowncall") + .invoke(null); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } else { + String jansiNativeLibraryName = System.mapLibraryName("jansi"); + if (jansiNativeLibraryName.endsWith(".dylib")) { + jansiNativeLibraryName = jansiNativeLibraryName.replace(".dylib", ".jnilib"); + } + + String packagePath = JansiLoader.class.getPackage().getName().replace('.', '/'); + RuntimeResourceAccess.addResource( + JansiLoader.class.getModule(), + String.format( + "/%s/native/%s/%s", + packagePath, OSInfo.getNativeLibFolderPathForCurrentOS(), jansiNativeLibraryName)); + } + } +} diff --git a/src/main/java/org/fusesource/jansi/internal/OSInfo.java b/src/main/java/org/fusesource/jansi/internal/OSInfo.java index 14b7b0ec..ce8fb347 100644 --- a/src/main/java/org/fusesource/jansi/internal/OSInfo.java +++ b/src/main/java/org/fusesource/jansi/internal/OSInfo.java @@ -36,12 +36,10 @@ import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Paths; -import java.util.HashMap; import java.util.Locale; /** * Provides OS name and architecture name. - * */ public class OSInfo { @@ -54,52 +52,6 @@ public class OSInfo { public static final String ARM64 = "arm64"; public static final String RISCV64 = "riscv64"; - private static final HashMap archMapping = new HashMap(); - - static { - // x86 mappings - archMapping.put(X86, X86); - archMapping.put("i386", X86); - archMapping.put("i486", X86); - archMapping.put("i586", X86); - archMapping.put("i686", X86); - archMapping.put("pentium", X86); - - // x86_64 mappings - archMapping.put(X86_64, X86_64); - archMapping.put("amd64", X86_64); - archMapping.put("em64t", X86_64); - archMapping.put("universal", X86_64); // Needed for openjdk7 in Mac - - // Itenium 64-bit mappings - archMapping.put(IA64, IA64); - archMapping.put("ia64w", IA64); - - // Itenium 32-bit mappings, usually an HP-UX construct - archMapping.put(IA64_32, IA64_32); - archMapping.put("ia64n", IA64_32); - - // PowerPC mappings - archMapping.put(PPC, PPC); - archMapping.put("power", PPC); - archMapping.put("powerpc", PPC); - archMapping.put("power_pc", PPC); - archMapping.put("power_rs", PPC); - - // TODO: PowerPC 64bit mappings - archMapping.put(PPC64, PPC64); - archMapping.put("power64", PPC64); - archMapping.put("powerpc64", PPC64); - archMapping.put("power_pc64", PPC64); - archMapping.put("power_rs64", PPC64); - - // aarch64 mappings - archMapping.put("aarch64", ARM64); - - // riscv64 mappings - archMapping.put(RISCV64, RISCV64); - } - public static void main(String[] args) { if (args.length >= 1) { if ("--os".equals(args[0])) { @@ -114,6 +66,63 @@ public static void main(String[] args) { System.out.print(getNativeLibFolderPathForCurrentOS()); } + private static String mapArch(String arch) { + switch (arch.toLowerCase(Locale.ROOT)) { + // x86 mappings + case X86: + case "i386": + case "i486": + case "i586": + case "i686": + case "pentium": + return X86; + + // x86_64 mappings + case X86_64: + case "amd64": + case "em64t": + case "universal": // Needed for openjdk7 in Mac + return X86_64; + + // Itenium 64-bit mappings + case IA64: + case "ia64w": + return IA64; + + // Itenium 32-bit mappings, usually an HP-UX construct + case IA64_32: + case "ia64n": + return IA64_32; + + // PowerPC mappings + case PPC: + case "power": + case "powerpc": + case "power_pc": + case "power_rs": + return PPC; + + // TODO: PowerPC 64bit mappings + case PPC64: + case "power64": + case "powerpc64": + case "power_pc64": + case "power_rs64": + return PPC64; + + // aarch64 mappings + case "aarch64": + return ARM64; + + // riscv64 mappings + case RISCV64: + return RISCV64; + + default: + return null; + } + } + public static String getNativeLibFolderPathForCurrentOS() { return getOSName() + "/" + getArchName(); } @@ -145,6 +154,10 @@ public static boolean isAlpine() { return false; } + public static boolean isInImageCode() { + return System.getProperty("org.graalvm.nativeimage.imagecode") != null; + } + static String getHardwareName() { try { Process p = Runtime.getRuntime().exec("uname -m"); @@ -211,8 +224,10 @@ public static String getArchName() { if (osArch.startsWith("arm")) { osArch = resolveArmArchType(); } else { - String lc = osArch.toLowerCase(Locale.ROOT); - if (archMapping.containsKey(lc)) return archMapping.get(lc); + String arch = mapArch(osArch); + if (arch != null) { + return arch; + } } return translateArchNameToFolderName(osArch); } diff --git a/src/main/java/org/fusesource/jansi/internal/ffm/NativeImageFeatures.java b/src/main/java/org/fusesource/jansi/internal/ffm/NativeImageDowncallRegister.java similarity index 93% rename from src/main/java/org/fusesource/jansi/internal/ffm/NativeImageFeatures.java rename to src/main/java/org/fusesource/jansi/internal/ffm/NativeImageDowncallRegister.java index 85ddfa8e..3052b40f 100644 --- a/src/main/java/org/fusesource/jansi/internal/ffm/NativeImageFeatures.java +++ b/src/main/java/org/fusesource/jansi/internal/ffm/NativeImageDowncallRegister.java @@ -15,22 +15,24 @@ */ package org.fusesource.jansi.internal.ffm; -import java.lang.foreign.*; +import java.lang.foreign.AddressLayout; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.StructLayout; +import java.lang.foreign.ValueLayout; import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.hosted.Feature; import org.graalvm.nativeimage.hosted.RuntimeForeignAccess; import static java.lang.foreign.ValueLayout.*; -public final class NativeImageFeatures implements Feature { +public final class NativeImageDowncallRegister { private static void registerForDowncall(MemoryLayout resLayout, MemoryLayout... argLayouts) { RuntimeForeignAccess.registerForDowncall(FunctionDescriptor.of(resLayout, argLayouts)); } - @Override - public void duringSetup(DuringSetupAccess access) { + public static void registerForDowncall() { if (Platform.includedIn(Platform.WINDOWS.class)) { final OfShort C_SHORT$LAYOUT = JAVA_SHORT; final OfInt C_INT$LAYOUT = JAVA_INT; diff --git a/src/main/java/org/fusesource/jansi/internal/ffm/PosixCLibrary.java b/src/main/java/org/fusesource/jansi/internal/ffm/PosixCLibrary.java index 2ed2df8f..817e03e4 100644 --- a/src/main/java/org/fusesource/jansi/internal/ffm/PosixCLibrary.java +++ b/src/main/java/org/fusesource/jansi/internal/ffm/PosixCLibrary.java @@ -20,6 +20,7 @@ import java.lang.invoke.VarHandle; import org.fusesource.jansi.internal.AnsiConsoleSupport; +import org.fusesource.jansi.internal.OSInfo; final class PosixCLibrary implements AnsiConsoleSupport.CLibrary { private static final int TIOCGWINSZ; @@ -53,7 +54,7 @@ final class PosixCLibrary implements AnsiConsoleSupport.CLibrary { ws_col = wsLayout.varHandle(MemoryLayout.PathElement.groupElement("ws_col")); Linker linker = Linker.nativeLinker(); SymbolLookup lookup; - if (System.getProperty("org.graalvm.nativeimage.imagecode") != null) { + if (OSInfo.isInImageCode()) { lookup = SymbolLookup.loaderLookup(); } else { lookup = linker.defaultLookup(); diff --git a/src/main/resources/META-INF/native-image/jansi/resource-config.json b/src/main/resources/META-INF/native-image/jansi/resource-config.json index e062c81e..794d8996 100644 --- a/src/main/resources/META-INF/native-image/jansi/resource-config.json +++ b/src/main/resources/META-INF/native-image/jansi/resource-config.json @@ -1,7 +1,6 @@ { "resources": [ {"pattern": "org/fusesource/jansi/jansi.properties"}, - {"pattern": "org/fusesource/jansi/jansi.txt"}, - {"pattern": "org/fusesource/jansi/internal/native/.*"} + {"pattern": "org/fusesource/jansi/jansi.txt"} ] } \ No newline at end of file From 1026748a6f795ec71342ca56b527e9aadf273823 Mon Sep 17 00:00:00 2001 From: Glavo Date: Tue, 3 Oct 2023 17:00:32 +0800 Subject: [PATCH 05/16] fix add resource --- .../java/org/fusesource/jansi/internal/NativeImageFeature.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java b/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java index c64c0ef2..c6f0f1da 100644 --- a/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java +++ b/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java @@ -47,7 +47,7 @@ public void duringSetup(DuringSetupAccess access) { RuntimeResourceAccess.addResource( JansiLoader.class.getModule(), String.format( - "/%s/native/%s/%s", + "%s/native/%s/%s", packagePath, OSInfo.getNativeLibFolderPathForCurrentOS(), jansiNativeLibraryName)); } } From 9b6a1b17e51896140e1f30e6667b0df8dbfe341c Mon Sep 17 00:00:00 2001 From: Glavo Date: Tue, 3 Oct 2023 17:03:33 +0800 Subject: [PATCH 06/16] update --- .../org/fusesource/jansi/internal/NativeImageFeature.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java b/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java index c6f0f1da..138079e1 100644 --- a/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java +++ b/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java @@ -28,7 +28,7 @@ public String getURL() { @Override public void duringSetup(DuringSetupAccess access) { String providers = System.getProperty(AnsiConsole.JANSI_PROVIDERS); - if (providers != null && providers.contains("ffm")) { + if (providers != null && providers.contains(AnsiConsole.JANSI_PROVIDER_FFM)) { try { // FFM is only available in JDK 21+, so we need to compile it separately Class.forName("org.fusesource.jansi.internal.ffm.NativeImageDowncallRegister") @@ -37,7 +37,9 @@ public void duringSetup(DuringSetupAccess access) { } catch (Throwable e) { throw new RuntimeException(e); } - } else { + } + + if (providers == null || providers.contains(AnsiConsole.JANSI_PROVIDER_JNI)){ String jansiNativeLibraryName = System.mapLibraryName("jansi"); if (jansiNativeLibraryName.endsWith(".dylib")) { jansiNativeLibraryName = jansiNativeLibraryName.replace(".dylib", ".jnilib"); From f2ac7a2354d2798f0c421d241a5128ce760cd58a Mon Sep 17 00:00:00 2001 From: Glavo Date: Tue, 3 Oct 2023 18:18:17 +0800 Subject: [PATCH 07/16] Create native-image.properties --- .../java/org/fusesource/jansi/internal/NativeImageFeature.java | 2 +- .../META-INF/native-image/jansi/native-image.properties | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/META-INF/native-image/jansi/native-image.properties diff --git a/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java b/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java index 138079e1..1be68b75 100644 --- a/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java +++ b/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java @@ -39,7 +39,7 @@ public void duringSetup(DuringSetupAccess access) { } } - if (providers == null || providers.contains(AnsiConsole.JANSI_PROVIDER_JNI)){ + if (providers == null || providers.contains(AnsiConsole.JANSI_PROVIDER_JNI)) { String jansiNativeLibraryName = System.mapLibraryName("jansi"); if (jansiNativeLibraryName.endsWith(".dylib")) { jansiNativeLibraryName = jansiNativeLibraryName.replace(".dylib", ".jnilib"); diff --git a/src/main/resources/META-INF/native-image/jansi/native-image.properties b/src/main/resources/META-INF/native-image/jansi/native-image.properties new file mode 100644 index 00000000..6cc8f4e4 --- /dev/null +++ b/src/main/resources/META-INF/native-image/jansi/native-image.properties @@ -0,0 +1 @@ +Args=--features=org.fusesource.jansi.internal.NativeImageFeature \ No newline at end of file From a15cc8f69f80c8f4d639e72e4615b3153db27864 Mon Sep 17 00:00:00 2001 From: Glavo Date: Tue, 3 Oct 2023 18:29:37 +0800 Subject: [PATCH 08/16] Initialize AnsiConsoleSupportHolder at build time --- .../internal/AnsiConsoleSupportHolder.java | 64 +++++++++++-------- .../jansi/internal/NativeImageFeature.java | 8 +++ 2 files changed, 45 insertions(+), 27 deletions(-) diff --git a/src/main/java/org/fusesource/jansi/internal/AnsiConsoleSupportHolder.java b/src/main/java/org/fusesource/jansi/internal/AnsiConsoleSupportHolder.java index c3ff661d..65fb6c93 100644 --- a/src/main/java/org/fusesource/jansi/internal/AnsiConsoleSupportHolder.java +++ b/src/main/java/org/fusesource/jansi/internal/AnsiConsoleSupportHolder.java @@ -19,10 +19,9 @@ public final class AnsiConsoleSupportHolder { - private static final String PROVIDER_NAME; - private static final AnsiConsoleSupport.CLibrary CLIBRARY; - private static final AnsiConsoleSupport.Kernel32 KERNEL32; - private static final Throwable ERR; + static final AnsiConsoleSupport PROVIDER; + + static final Throwable ERR; private static AnsiConsoleSupport getDefaultProvider() { if (!OSInfo.isInImageCode()) { @@ -84,40 +83,51 @@ private static AnsiConsoleSupport findProvider(String providerList) { err = e; } - String providerName = null; - AnsiConsoleSupport.CLibrary clib = null; - AnsiConsoleSupport.Kernel32 kernel32 = null; - - if (ansiConsoleSupport != null) { - try { - providerName = ansiConsoleSupport.getProviderName(); - clib = ansiConsoleSupport.getCLibrary(); - kernel32 = OSInfo.isWindows() ? ansiConsoleSupport.getKernel32() : null; - } catch (Throwable e) { - err = e; - } - } - - PROVIDER_NAME = providerName; - CLIBRARY = clib; - KERNEL32 = kernel32; + PROVIDER = ansiConsoleSupport; ERR = err; } public static String getProviderName() { - return PROVIDER_NAME; + return PROVIDER.getProviderName(); + } + + private static final class LibraryHolder { + static final AnsiConsoleSupport.CLibrary CLIBRARY; + static final AnsiConsoleSupport.Kernel32 KERNEL32; + static final Throwable ERR; + + static { + AnsiConsoleSupport.CLibrary clib = null; + AnsiConsoleSupport.Kernel32 kernel32 = null; + Throwable err = null; + + if (PROVIDER != null) { + try { + clib = PROVIDER.getCLibrary(); + kernel32 = OSInfo.isWindows() ? PROVIDER.getKernel32() : null; + } catch (Throwable e) { + err = e; + } + } else { + err = AnsiConsoleSupportHolder.ERR; + } + + CLIBRARY = clib; + KERNEL32 = kernel32; + ERR = err; + } } public static AnsiConsoleSupport.CLibrary getCLibrary() { - if (CLIBRARY == null) { - throw new RuntimeException("Unable to get the instance of CLibrary", ERR); + if (LibraryHolder.CLIBRARY == null) { + throw new RuntimeException("Unable to get the instance of CLibrary", LibraryHolder.ERR); } - return CLIBRARY; + return LibraryHolder.CLIBRARY; } public static AnsiConsoleSupport.Kernel32 getKernel32() { - if (KERNEL32 == null) { + if (LibraryHolder.KERNEL32 == null) { if (OSInfo.isWindows()) { throw new RuntimeException("Unable to get the instance of Kernel32", ERR); } else { @@ -125,6 +135,6 @@ public static AnsiConsoleSupport.Kernel32 getKernel32() { } } - return KERNEL32; + return LibraryHolder.KERNEL32; } } diff --git a/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java b/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java index 1be68b75..8baf4874 100644 --- a/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java +++ b/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java @@ -17,7 +17,9 @@ import org.fusesource.jansi.AnsiConsole; import org.graalvm.nativeimage.hosted.Feature; +import org.graalvm.nativeimage.hosted.RuntimeClassInitialization; import org.graalvm.nativeimage.hosted.RuntimeResourceAccess; +import org.graalvm.nativeimage.hosted.RuntimeSystemProperties; public class NativeImageFeature implements Feature { @Override @@ -28,6 +30,10 @@ public String getURL() { @Override public void duringSetup(DuringSetupAccess access) { String providers = System.getProperty(AnsiConsole.JANSI_PROVIDERS); + if (providers != null) { + RuntimeSystemProperties.register(AnsiConsole.JANSI_PROVIDERS, providers); + } + if (providers != null && providers.contains(AnsiConsole.JANSI_PROVIDER_FFM)) { try { // FFM is only available in JDK 21+, so we need to compile it separately @@ -52,5 +58,7 @@ public void duringSetup(DuringSetupAccess access) { "%s/native/%s/%s", packagePath, OSInfo.getNativeLibFolderPathForCurrentOS(), jansiNativeLibraryName)); } + + RuntimeClassInitialization.initializeAtBuildTime(AnsiConsoleSupportHolder.class); } } From cdc443438844d98e308cc74ea05da6637de7ce60 Mon Sep 17 00:00:00 2001 From: Glavo Date: Tue, 3 Oct 2023 18:33:05 +0800 Subject: [PATCH 09/16] update --- src/main/java/org/fusesource/jansi/internal/OSInfo.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/fusesource/jansi/internal/OSInfo.java b/src/main/java/org/fusesource/jansi/internal/OSInfo.java index ce8fb347..cbe831ed 100644 --- a/src/main/java/org/fusesource/jansi/internal/OSInfo.java +++ b/src/main/java/org/fusesource/jansi/internal/OSInfo.java @@ -66,7 +66,7 @@ public static void main(String[] args) { System.out.print(getNativeLibFolderPathForCurrentOS()); } - private static String mapArch(String arch) { + private static String mapArchName(String arch) { switch (arch.toLowerCase(Locale.ROOT)) { // x86 mappings case X86: @@ -224,7 +224,7 @@ public static String getArchName() { if (osArch.startsWith("arm")) { osArch = resolveArmArchType(); } else { - String arch = mapArch(osArch); + String arch = mapArchName(osArch); if (arch != null) { return arch; } From 7d8e90d699c5e76bf594b5a37059fe8744f2172a Mon Sep 17 00:00:00 2001 From: Glavo Date: Tue, 3 Oct 2023 21:54:45 +0800 Subject: [PATCH 10/16] Compatible with GraalVM 19.0 --- pom.xml | 13 -------- .../jansi/internal/NativeImageFeature.java | 31 ++++++++++++++----- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/pom.xml b/pom.xml index 8e4adda2..b6284015 100644 --- a/pom.xml +++ b/pom.xml @@ -206,22 +206,9 @@ **/ffm/*.java - **/NativeImageFeature.java - - jdk-9 - - compile - - - 9 - - **/NativeImageFeature.java - - - jdk-21 diff --git a/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java b/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java index 8baf4874..c68f688f 100644 --- a/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java +++ b/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java @@ -18,7 +18,6 @@ import org.fusesource.jansi.AnsiConsole; import org.graalvm.nativeimage.hosted.Feature; import org.graalvm.nativeimage.hosted.RuntimeClassInitialization; -import org.graalvm.nativeimage.hosted.RuntimeResourceAccess; import org.graalvm.nativeimage.hosted.RuntimeSystemProperties; public class NativeImageFeature implements Feature { @@ -31,7 +30,11 @@ public String getURL() { public void duringSetup(DuringSetupAccess access) { String providers = System.getProperty(AnsiConsole.JANSI_PROVIDERS); if (providers != null) { - RuntimeSystemProperties.register(AnsiConsole.JANSI_PROVIDERS, providers); + try { + RuntimeSystemProperties.register(AnsiConsole.JANSI_PROVIDERS, providers); + } catch (Throwable ignored) { + // GraalVM version < 23.0 + } } if (providers != null && providers.contains(AnsiConsole.JANSI_PROVIDER_FFM)) { @@ -52,11 +55,25 @@ public void duringSetup(DuringSetupAccess access) { } String packagePath = JansiLoader.class.getPackage().getName().replace('.', '/'); - RuntimeResourceAccess.addResource( - JansiLoader.class.getModule(), - String.format( - "%s/native/%s/%s", - packagePath, OSInfo.getNativeLibFolderPathForCurrentOS(), jansiNativeLibraryName)); + + try { + Class moduleClass = Class.forName("java.lang.Module"); + Class rraClass = Class.forName("org.graalvm.nativeimage.hosted.RuntimeResourceAccess"); + + Object module = Class.class.getMethod("getModule").invoke(JansiLoader.class); + rraClass.getMethod("addResource", moduleClass, String.class) + .invoke( + null, + module, + String.format( + "%s/native/%s/%s", + packagePath, + OSInfo.getNativeLibFolderPathForCurrentOS(), + jansiNativeLibraryName)); + + } catch (Throwable ignored) { + // GraalVM version < 22.3 + } } RuntimeClassInitialization.initializeAtBuildTime(AnsiConsoleSupportHolder.class); From 72701b06b226c24b5d9ff089044be7108f1d123c Mon Sep 17 00:00:00 2001 From: Glavo Date: Tue, 3 Oct 2023 22:28:16 +0800 Subject: [PATCH 11/16] Add module main class --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index b6284015..ca1dfd96 100644 --- a/pom.xml +++ b/pom.xml @@ -267,6 +267,7 @@ 9 + org.fusesource.jansi.AnsiMain org.fusesource.jansi org.fusesource.jansi; From fb7c82d3ca1e4215d4c2e5dcc3076d7e3e777699 Mon Sep 17 00:00:00 2001 From: Glavo Date: Tue, 3 Oct 2023 22:34:37 +0800 Subject: [PATCH 12/16] update --- .../org/fusesource/jansi/internal/AnsiConsoleSupportHolder.java | 1 - src/main/java/org/fusesource/jansi/internal/OSInfo.java | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/org/fusesource/jansi/internal/AnsiConsoleSupportHolder.java b/src/main/java/org/fusesource/jansi/internal/AnsiConsoleSupportHolder.java index 65fb6c93..a8a1c83c 100644 --- a/src/main/java/org/fusesource/jansi/internal/AnsiConsoleSupportHolder.java +++ b/src/main/java/org/fusesource/jansi/internal/AnsiConsoleSupportHolder.java @@ -32,7 +32,6 @@ private static AnsiConsoleSupport getDefaultProvider() { .getConstructor(boolean.class) .newInstance(true); } catch (Throwable ignored) { - ignored.printStackTrace(); // TODO: for debug, should be deleted before merging } } diff --git a/src/main/java/org/fusesource/jansi/internal/OSInfo.java b/src/main/java/org/fusesource/jansi/internal/OSInfo.java index cbe831ed..2d0ce235 100644 --- a/src/main/java/org/fusesource/jansi/internal/OSInfo.java +++ b/src/main/java/org/fusesource/jansi/internal/OSInfo.java @@ -182,7 +182,7 @@ private static String readFully(InputStream in) throws IOException { while ((readLen = in.read(buf, 0, buf.length)) >= 0) { b.write(buf, 0, readLen); } - return b.toString(); + return b.toString("UTF-8"); } static String resolveArmArchType() { From 62c72f811ba94b0e7866c6329fc9e480e8eb91c6 Mon Sep 17 00:00:00 2001 From: Glavo Date: Tue, 3 Oct 2023 22:55:02 +0800 Subject: [PATCH 13/16] update --- .../java/org/fusesource/jansi/internal/NativeImageFeature.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java b/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java index c68f688f..0229530a 100644 --- a/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java +++ b/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java @@ -34,6 +34,7 @@ public void duringSetup(DuringSetupAccess access) { RuntimeSystemProperties.register(AnsiConsole.JANSI_PROVIDERS, providers); } catch (Throwable ignored) { // GraalVM version < 23.0 + // No need to worry as we select the provider at build time } } @@ -73,6 +74,7 @@ public void duringSetup(DuringSetupAccess access) { } catch (Throwable ignored) { // GraalVM version < 22.3 + // Users need to manually add the JNI library as resources } } From 64a81234aa8b84b27b511ea219dda0a1cbff86ec Mon Sep 17 00:00:00 2001 From: Glavo Date: Wed, 4 Oct 2023 13:14:20 +0800 Subject: [PATCH 14/16] update AnsiConsoleSupport --- .../jansi/internal/AnsiConsoleSupport.java | 42 +++++++++++++--- .../internal/AnsiConsoleSupportHolder.java | 50 ++++--------------- .../jansi/internal/NativeImageFeature.java | 27 +++++----- .../internal/ffm/AnsiConsoleSupportImpl.java | 16 +++--- .../internal/jni/AnsiConsoleSupportImpl.java | 11 ++-- 5 files changed, 71 insertions(+), 75 deletions(-) diff --git a/src/main/java/org/fusesource/jansi/internal/AnsiConsoleSupport.java b/src/main/java/org/fusesource/jansi/internal/AnsiConsoleSupport.java index 4868207d..64087fa1 100644 --- a/src/main/java/org/fusesource/jansi/internal/AnsiConsoleSupport.java +++ b/src/main/java/org/fusesource/jansi/internal/AnsiConsoleSupport.java @@ -20,9 +20,9 @@ import org.fusesource.jansi.io.AnsiProcessor; -public interface AnsiConsoleSupport { +public abstract class AnsiConsoleSupport { - interface CLibrary { + public interface CLibrary { int STDOUT_FILENO = 1; int STDERR_FILENO = 2; @@ -32,7 +32,7 @@ interface CLibrary { int isTty(int fd); } - interface Kernel32 { + public interface Kernel32 { int isTty(long console); @@ -51,9 +51,39 @@ interface Kernel32 { AnsiProcessor newProcessor(OutputStream os, long console) throws IOException; } - String getProviderName(); + private final String providerName; + private CLibrary cLibrary; + private Kernel32 kernel32; - CLibrary getCLibrary(); + protected AnsiConsoleSupport(String providerName) { + this.providerName = providerName; + } + + public final String getProviderName() { + return providerName; + } + + protected abstract CLibrary createCLibrary(); + + protected abstract Kernel32 createKernel32(); + + public final CLibrary getCLibrary() { + if (cLibrary == null) { + cLibrary = createCLibrary(); + } - Kernel32 getKernel32(); + return cLibrary; + } + + public final Kernel32 getKernel32() { + if (kernel32 == null) { + if (!OSInfo.isWindows()) { + throw new RuntimeException("Kernel32 is not available on this platform"); + } + + kernel32 = createKernel32(); + } + + return kernel32; + } } diff --git a/src/main/java/org/fusesource/jansi/internal/AnsiConsoleSupportHolder.java b/src/main/java/org/fusesource/jansi/internal/AnsiConsoleSupportHolder.java index a8a1c83c..9e66e579 100644 --- a/src/main/java/org/fusesource/jansi/internal/AnsiConsoleSupportHolder.java +++ b/src/main/java/org/fusesource/jansi/internal/AnsiConsoleSupportHolder.java @@ -86,54 +86,22 @@ private static AnsiConsoleSupport findProvider(String providerList) { ERR = err; } - public static String getProviderName() { - return PROVIDER.getProviderName(); + public static AnsiConsoleSupport getProvider() { + if (PROVIDER == null) { + throw new RuntimeException("No provider available", ERR); + } + return PROVIDER; } - private static final class LibraryHolder { - static final AnsiConsoleSupport.CLibrary CLIBRARY; - static final AnsiConsoleSupport.Kernel32 KERNEL32; - static final Throwable ERR; - - static { - AnsiConsoleSupport.CLibrary clib = null; - AnsiConsoleSupport.Kernel32 kernel32 = null; - Throwable err = null; - - if (PROVIDER != null) { - try { - clib = PROVIDER.getCLibrary(); - kernel32 = OSInfo.isWindows() ? PROVIDER.getKernel32() : null; - } catch (Throwable e) { - err = e; - } - } else { - err = AnsiConsoleSupportHolder.ERR; - } - - CLIBRARY = clib; - KERNEL32 = kernel32; - ERR = err; - } + public static String getProviderName() { + return getProvider().getProviderName(); } public static AnsiConsoleSupport.CLibrary getCLibrary() { - if (LibraryHolder.CLIBRARY == null) { - throw new RuntimeException("Unable to get the instance of CLibrary", LibraryHolder.ERR); - } - - return LibraryHolder.CLIBRARY; + return getProvider().getCLibrary(); } public static AnsiConsoleSupport.Kernel32 getKernel32() { - if (LibraryHolder.KERNEL32 == null) { - if (OSInfo.isWindows()) { - throw new RuntimeException("Unable to get the instance of Kernel32", ERR); - } else { - throw new UnsupportedOperationException("Not Windows"); - } - } - - return LibraryHolder.KERNEL32; + return getProvider().getKernel32(); } } diff --git a/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java b/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java index 0229530a..25e467b3 100644 --- a/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java +++ b/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java @@ -28,6 +28,9 @@ public String getURL() { @Override public void duringSetup(DuringSetupAccess access) { + RuntimeClassInitialization.initializeAtBuildTime(AnsiConsoleSupportHolder.class); + RuntimeClassInitialization.initializeAtBuildTime(OSInfo.class); + String providers = System.getProperty(AnsiConsole.JANSI_PROVIDERS); if (providers != null) { try { @@ -38,18 +41,9 @@ public void duringSetup(DuringSetupAccess access) { } } - if (providers != null && providers.contains(AnsiConsole.JANSI_PROVIDER_FFM)) { - try { - // FFM is only available in JDK 21+, so we need to compile it separately - Class.forName("org.fusesource.jansi.internal.ffm.NativeImageDowncallRegister") - .getMethod("registerForDowncall") - .invoke(null); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } + String provider = AnsiConsoleSupportHolder.getProviderName(); - if (providers == null || providers.contains(AnsiConsole.JANSI_PROVIDER_JNI)) { + if (provider == null || provider.equals(AnsiConsole.JANSI_PROVIDER_JNI)) { String jansiNativeLibraryName = System.mapLibraryName("jansi"); if (jansiNativeLibraryName.endsWith(".dylib")) { jansiNativeLibraryName = jansiNativeLibraryName.replace(".dylib", ".jnilib"); @@ -76,8 +70,15 @@ public void duringSetup(DuringSetupAccess access) { // GraalVM version < 22.3 // Users need to manually add the JNI library as resources } + } else if (provider.equals(AnsiConsole.JANSI_PROVIDER_FFM)) { + try { + // FFM is only available in JDK 21+, so we need to compile it separately + Class.forName("org.fusesource.jansi.internal.ffm.NativeImageDowncallRegister") + .getMethod("registerForDowncall") + .invoke(null); + } catch (Throwable e) { + throw new RuntimeException(e); + } } - - RuntimeClassInitialization.initializeAtBuildTime(AnsiConsoleSupportHolder.class); } } diff --git a/src/main/java/org/fusesource/jansi/internal/ffm/AnsiConsoleSupportImpl.java b/src/main/java/org/fusesource/jansi/internal/ffm/AnsiConsoleSupportImpl.java index f22f3ac7..b36bc692 100644 --- a/src/main/java/org/fusesource/jansi/internal/ffm/AnsiConsoleSupportImpl.java +++ b/src/main/java/org/fusesource/jansi/internal/ffm/AnsiConsoleSupportImpl.java @@ -27,11 +27,14 @@ import static org.fusesource.jansi.internal.ffm.Kernel32.*; -public final class AnsiConsoleSupportImpl implements AnsiConsoleSupport { +public final class AnsiConsoleSupportImpl extends AnsiConsoleSupport { - public AnsiConsoleSupportImpl() {} + public AnsiConsoleSupportImpl() { + super("ffm"); + } public AnsiConsoleSupportImpl(boolean checkNativeAccess) { + this(); if (checkNativeAccess && !AnsiConsoleSupportImpl.class.getModule().isNativeAccessEnabled()) { throw new UnsupportedOperationException( "Native access is not enabled for the current module: " + AnsiConsoleSupportImpl.class.getModule()); @@ -39,12 +42,7 @@ public AnsiConsoleSupportImpl(boolean checkNativeAccess) { } @Override - public String getProviderName() { - return "ffm"; - } - - @Override - public CLibrary getCLibrary() { + protected CLibrary createCLibrary() { if (OSInfo.isWindows()) { return new WindowsCLibrary(); } else { @@ -53,7 +51,7 @@ public CLibrary getCLibrary() { } @Override - public Kernel32 getKernel32() { + protected Kernel32 createKernel32() { return new Kernel32() { @Override public int isTty(long console) { diff --git a/src/main/java/org/fusesource/jansi/internal/jni/AnsiConsoleSupportImpl.java b/src/main/java/org/fusesource/jansi/internal/jni/AnsiConsoleSupportImpl.java index ea3bc2fc..e3ae4d67 100644 --- a/src/main/java/org/fusesource/jansi/internal/jni/AnsiConsoleSupportImpl.java +++ b/src/main/java/org/fusesource/jansi/internal/jni/AnsiConsoleSupportImpl.java @@ -33,15 +33,14 @@ import static org.fusesource.jansi.internal.Kernel32.STD_OUTPUT_HANDLE; import static org.fusesource.jansi.internal.Kernel32.SetConsoleMode; -public final class AnsiConsoleSupportImpl implements AnsiConsoleSupport { +public final class AnsiConsoleSupportImpl extends AnsiConsoleSupport { - @Override - public String getProviderName() { - return "jni"; + public AnsiConsoleSupportImpl() { + super("jni"); } @Override - public CLibrary getCLibrary() { + protected CLibrary createCLibrary() { return new CLibrary() { @Override public short getTerminalWidth(int fd) { @@ -56,7 +55,7 @@ public int isTty(int fd) { } @Override - public Kernel32 getKernel32() { + protected Kernel32 createKernel32() { return new Kernel32() { @Override public int isTty(long console) { From fa17cf68b0f025acf69d09bcddf11654f6890801 Mon Sep 17 00:00:00 2001 From: Glavo Date: Wed, 4 Oct 2023 13:17:04 +0800 Subject: [PATCH 15/16] clean --- .../java/org/fusesource/jansi/internal/NativeImageFeature.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java b/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java index 25e467b3..2c401104 100644 --- a/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java +++ b/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java @@ -29,7 +29,6 @@ public String getURL() { @Override public void duringSetup(DuringSetupAccess access) { RuntimeClassInitialization.initializeAtBuildTime(AnsiConsoleSupportHolder.class); - RuntimeClassInitialization.initializeAtBuildTime(OSInfo.class); String providers = System.getProperty(AnsiConsole.JANSI_PROVIDERS); if (providers != null) { From 6e3d465c4ce79fccd453881c28fc443d171d9048 Mon Sep 17 00:00:00 2001 From: Glavo Date: Wed, 4 Oct 2023 14:40:33 +0800 Subject: [PATCH 16/16] update --- .../org/fusesource/jansi/internal/NativeImageFeature.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java b/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java index 2c401104..27063a11 100644 --- a/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java +++ b/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java @@ -15,6 +15,8 @@ */ package org.fusesource.jansi.internal; +import java.util.Objects; + import org.fusesource.jansi.AnsiConsole; import org.graalvm.nativeimage.hosted.Feature; import org.graalvm.nativeimage.hosted.RuntimeClassInitialization; @@ -40,9 +42,8 @@ public void duringSetup(DuringSetupAccess access) { } } - String provider = AnsiConsoleSupportHolder.getProviderName(); - - if (provider == null || provider.equals(AnsiConsole.JANSI_PROVIDER_JNI)) { + String provider = Objects.requireNonNull(AnsiConsoleSupportHolder.getProviderName(), "No provider available"); + if (provider.equals(AnsiConsole.JANSI_PROVIDER_JNI)) { String jansiNativeLibraryName = System.mapLibraryName("jansi"); if (jansiNativeLibraryName.endsWith(".dylib")) { jansiNativeLibraryName = jansiNativeLibraryName.replace(".dylib", ".jnilib");