diff --git a/pom.xml b/pom.xml index 49bf9c81..ca1dfd96 100644 --- a/pom.xml +++ b/pom.xml @@ -109,6 +109,13 @@ + + org.graalvm.sdk + nativeimage + 23.1.0 + provided + true + org.junit.jupiter junit-jupiter @@ -260,6 +267,7 @@ 9 + org.fusesource.jansi.AnsiMain org.fusesource.jansi org.fusesource.jansi; 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 eb049f98..9e66e579 100644 --- a/src/main/java/org/fusesource/jansi/internal/AnsiConsoleSupportHolder.java +++ b/src/main/java/org/fusesource/jansi/internal/AnsiConsoleSupportHolder.java @@ -19,19 +19,20 @@ 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() { - 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) { + 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) { + } } return new org.fusesource.jansi.internal.jni.AnsiConsoleSupportImpl(); @@ -81,47 +82,26 @@ private static AnsiConsoleSupport findProvider(String providerList) { err = e; } - String providerName = null; - AnsiConsoleSupport.CLibrary clib = null; - AnsiConsoleSupport.Kernel32 kernel32 = null; + PROVIDER = ansiConsoleSupport; + ERR = err; + } - if (ansiConsoleSupport != null) { - try { - providerName = ansiConsoleSupport.getProviderName(); - clib = ansiConsoleSupport.getCLibrary(); - kernel32 = OSInfo.isWindows() ? ansiConsoleSupport.getKernel32() : null; - } catch (Throwable e) { - err = e; - } + public static AnsiConsoleSupport getProvider() { + if (PROVIDER == null) { + throw new RuntimeException("No provider available", ERR); } - - PROVIDER_NAME = providerName; - CLIBRARY = clib; - KERNEL32 = kernel32; - ERR = err; + return PROVIDER; } public static String getProviderName() { - return PROVIDER_NAME; + return getProvider().getProviderName(); } public static AnsiConsoleSupport.CLibrary getCLibrary() { - if (CLIBRARY == null) { - throw new RuntimeException("Unable to get the instance of CLibrary", ERR); - } - - return CLIBRARY; + return getProvider().getCLibrary(); } public static AnsiConsoleSupport.Kernel32 getKernel32() { - if (KERNEL32 == null) { - if (OSInfo.isWindows()) { - throw new RuntimeException("Unable to get the instance of Kernel32", ERR); - } else { - throw new UnsupportedOperationException("Not Windows"); - } - } - - return 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 new file mode 100644 index 00000000..27063a11 --- /dev/null +++ b/src/main/java/org/fusesource/jansi/internal/NativeImageFeature.java @@ -0,0 +1,84 @@ +/* + * 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 java.util.Objects; + +import org.fusesource.jansi.AnsiConsole; +import org.graalvm.nativeimage.hosted.Feature; +import org.graalvm.nativeimage.hosted.RuntimeClassInitialization; +import org.graalvm.nativeimage.hosted.RuntimeSystemProperties; + +public class NativeImageFeature implements Feature { + @Override + public String getURL() { + return "https://github.com/fusesource/jansi"; + } + + @Override + public void duringSetup(DuringSetupAccess access) { + RuntimeClassInitialization.initializeAtBuildTime(AnsiConsoleSupportHolder.class); + + String providers = System.getProperty(AnsiConsole.JANSI_PROVIDERS); + if (providers != null) { + try { + 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 + } + } + + 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"); + } + + String packagePath = JansiLoader.class.getPackage().getName().replace('.', '/'); + + 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 + // 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); + } + } + } +} diff --git a/src/main/java/org/fusesource/jansi/internal/OSInfo.java b/src/main/java/org/fusesource/jansi/internal/OSInfo.java index 14b7b0ec..2d0ce235 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 mapArchName(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"); @@ -169,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() { @@ -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 = mapArchName(osArch); + if (arch != null) { + return arch; + } } return translateArchNameToFolderName(osArch); } 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..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,23 +27,22 @@ 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"); + throw new UnsupportedOperationException( + "Native access is not enabled for the current module: " + AnsiConsoleSupportImpl.class.getModule()); } } @Override - public String getProviderName() { - return "ffm"; - } - - @Override - public CLibrary getCLibrary() { + protected CLibrary createCLibrary() { if (OSInfo.isWindows()) { return new WindowsCLibrary(); } else { @@ -52,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/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/NativeImageDowncallRegister.java b/src/main/java/org/fusesource/jansi/internal/ffm/NativeImageDowncallRegister.java new file mode 100644 index 00000000..3052b40f --- /dev/null +++ b/src/main/java/org/fusesource/jansi/internal/ffm/NativeImageDowncallRegister.java @@ -0,0 +1,103 @@ +/* + * 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.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.RuntimeForeignAccess; + +import static java.lang.foreign.ValueLayout.*; + +public final class NativeImageDowncallRegister { + + private static void registerForDowncall(MemoryLayout resLayout, MemoryLayout... argLayouts) { + RuntimeForeignAccess.registerForDowncall(FunctionDescriptor.of(resLayout, argLayouts)); + } + + public static void registerForDowncall() { + 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..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; @@ -52,14 +53,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 (OSInfo.isInImageCode()) { + 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 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) { 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 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