fix reachability metadata drift

This commit is contained in:
Gregor Lohaus
2026-05-29 10:31:44 +02:00
parent eeac1d20d6
commit 482305a1af
5 changed files with 156 additions and 2 deletions

View File

@@ -14,6 +14,16 @@ java {
withSourcesJar()
}
val graalvmHome = providers.environmentVariable("GRAALVM_HOME")
.orElse(providers.systemProperty("java.home"))
val graalNativeImageJmod = graalvmHome.map {
file("$it/jmods/org.graalvm.nativeimage.jmod")
}
dependencies {
compileOnly(files(graalNativeImageJmod))
}
tasks.withType<JavaCompile>().configureEach {
options.release.set(22)
}

View File

@@ -30,6 +30,7 @@
else if pkgs ? jdk24_headless then pkgs.jdk24_headless
else if pkgs ? jdk24 then pkgs.jdk24
else pkgs.jdk;
graalvm = pkgs.graalvmPackages.graalvm-ce;
version = "0.1.0-SNAPSHOT";
groupPath = "dev/jlibghostty";
@@ -79,7 +80,7 @@
cp "$ghostty_lib" "$bundled_lib"
find src/main/java -name '*.java' | sort > build/sources.txt
javac --release 22 -d build/classes @build/sources.txt
javac --release 22 --module-path ${graalvm}/jmods -d build/classes @build/sources.txt
jar --create \
--file build/${artifactId}-${version}.jar \
@@ -149,14 +150,17 @@ POM
else if pkgs ? jdk24_headless then pkgs.jdk24_headless
else if pkgs ? jdk24 then pkgs.jdk24
else pkgs.jdk;
graalvm = pkgs.graalvmPackages.graalvm-ce;
ghosttyVt = ghostty.packages.${system}.libghostty-vt;
in
{
default = pkgs.mkShell {
packages =
[ jdk pkgs.gradle ]
[ jdk pkgs.gradle graalvm ]
++ pkgs.lib.optional (pkgs ? jextract) pkgs.jextract;
GRAALVM_HOME = "${graalvm}";
JLIBGHOSTTY_LIBRARY =
if pkgs.stdenv.hostPlatform.isDarwin
then "${ghosttyVt}/lib/libghostty-vt.dylib"

View File

@@ -0,0 +1,134 @@
package dev.jlibghostty;
import org.graalvm.nativeimage.hosted.Feature;
import org.graalvm.nativeimage.hosted.RuntimeForeignAccess;
import java.lang.foreign.AddressLayout;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.GroupLayout;
import java.lang.foreign.Linker;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.ValueLayout;
/**
* Registers FFM descriptors for GraalVM releases that do not consume
* foreign.downcalls from reachability-metadata.json.
*/
public final class GhosttyForeignRegistrationFeature implements Feature {
private static final Linker LINKER = Linker.nativeLinker();
private static final AddressLayout C_POINTER = (AddressLayout) LINKER.canonicalLayouts().get("void*");
private static final ValueLayout.OfBoolean C_BOOL = (ValueLayout.OfBoolean) LINKER.canonicalLayouts().get("bool");
private static final ValueLayout.OfShort C_SHORT = (ValueLayout.OfShort) LINKER.canonicalLayouts().get("short");
private static final ValueLayout.OfInt C_INT = (ValueLayout.OfInt) LINKER.canonicalLayouts().get("int");
private static final ValueLayout.OfLong C_LONG_LONG = (ValueLayout.OfLong) LINKER.canonicalLayouts().get("long long");
private static final ValueLayout.OfLong C_SIZE_T = sizeTLayout();
private static final GroupLayout TERMINAL_OPTIONS = MemoryLayout.structLayout(
C_SHORT.withName("cols"),
C_SHORT.withName("rows"),
MemoryLayout.paddingLayout(4),
C_SIZE_T.withName("max_scrollback")
);
private static final GroupLayout SIZE_REPORT_SIZE = MemoryLayout.structLayout(
C_SHORT.withName("rows"),
C_SHORT.withName("columns"),
C_INT.withName("cell_width"),
C_INT.withName("cell_height")
);
private static final GroupLayout SCROLL_VIEWPORT = MemoryLayout.structLayout(
C_INT.withName("tag"),
MemoryLayout.paddingLayout(4),
MemoryLayout.structLayout(
C_LONG_LONG.withName("delta"),
C_LONG_LONG.withName("padding")
).withName("value")
);
private static final GroupLayout MOUSE_POSITION = MemoryLayout.structLayout(
ValueLayout.JAVA_FLOAT.withName("x"),
ValueLayout.JAVA_FLOAT.withName("y")
);
private static final GroupLayout FORMATTER_SCREEN_EXTRA = MemoryLayout.structLayout(
C_SIZE_T.withName("size"),
C_BOOL.withName("cursor"),
C_BOOL.withName("style"),
C_BOOL.withName("hyperlink"),
C_BOOL.withName("protection"),
C_BOOL.withName("kitty_keyboard"),
C_BOOL.withName("charsets"),
MemoryLayout.paddingLayout(2)
);
private static final GroupLayout FORMATTER_TERMINAL_EXTRA = MemoryLayout.structLayout(
C_SIZE_T.withName("size"),
C_BOOL.withName("palette"),
C_BOOL.withName("modes"),
C_BOOL.withName("scrolling_region"),
C_BOOL.withName("tabstops"),
C_BOOL.withName("pwd"),
C_BOOL.withName("keyboard"),
MemoryLayout.paddingLayout(2),
FORMATTER_SCREEN_EXTRA.withName("screen")
);
private static final GroupLayout FORMATTER_TERMINAL_OPTIONS = MemoryLayout.structLayout(
C_SIZE_T.withName("size"),
C_INT.withName("emit"),
C_BOOL.withName("unwrap"),
C_BOOL.withName("trim"),
MemoryLayout.paddingLayout(2),
FORMATTER_TERMINAL_EXTRA.withName("extra"),
C_POINTER.withName("selection")
);
@Override
public void duringSetup(DuringSetupAccess access) {
downcall(FunctionDescriptor.of(C_INT, C_POINTER, C_POINTER, TERMINAL_OPTIONS));
downcall(FunctionDescriptor.ofVoid(C_POINTER));
downcall(FunctionDescriptor.of(C_INT, C_POINTER, C_SHORT, C_SHORT, C_INT, C_INT));
downcall(FunctionDescriptor.ofVoid(C_POINTER, SCROLL_VIEWPORT));
downcall(FunctionDescriptor.ofVoid(C_POINTER, C_POINTER, C_SIZE_T));
downcall(FunctionDescriptor.of(C_INT, C_POINTER, C_INT, C_POINTER));
downcall(FunctionDescriptor.of(C_BOOL, C_POINTER, C_SIZE_T));
downcall(FunctionDescriptor.of(C_INT, C_POINTER, C_SIZE_T, C_BOOL, C_POINTER, C_SIZE_T, C_POINTER));
downcall(FunctionDescriptor.of(C_INT, C_INT, C_POINTER));
downcall(FunctionDescriptor.of(C_POINTER));
downcall(FunctionDescriptor.of(C_INT, C_INT, C_POINTER, C_SIZE_T, C_POINTER));
downcall(FunctionDescriptor.of(C_INT, C_INT, C_INT, C_POINTER, C_SIZE_T, C_POINTER));
downcall(FunctionDescriptor.of(C_INT, C_INT, SIZE_REPORT_SIZE, C_POINTER, C_SIZE_T, C_POINTER));
downcall(FunctionDescriptor.of(C_INT, C_POINTER, C_POINTER, C_POINTER, FORMATTER_TERMINAL_OPTIONS));
downcall(FunctionDescriptor.of(C_INT, C_POINTER, C_POINTER, C_SIZE_T, C_POINTER));
downcall(FunctionDescriptor.of(C_INT, C_POINTER, C_POINTER));
downcall(FunctionDescriptor.of(C_BOOL, C_POINTER));
downcall(FunctionDescriptor.of(C_INT, C_POINTER, C_POINTER, C_POINTER, C_POINTER));
downcall(FunctionDescriptor.ofVoid(C_POINTER, C_INT));
downcall(FunctionDescriptor.ofVoid(C_POINTER, C_SHORT));
downcall(FunctionDescriptor.ofVoid(C_POINTER, MOUSE_POSITION));
downcall(FunctionDescriptor.ofVoid(C_POINTER, C_INT, C_POINTER));
downcall(FunctionDescriptor.ofVoid(C_POINTER, C_POINTER));
downcall(FunctionDescriptor.of(C_INT, C_POINTER, C_POINTER, C_POINTER, C_SIZE_T, C_POINTER));
downcall(FunctionDescriptor.of(C_POINTER, C_POINTER, C_INT));
upcall(FunctionDescriptor.ofVoid(C_POINTER, C_POINTER, C_POINTER, C_SIZE_T));
upcall(FunctionDescriptor.of(C_BOOL, C_POINTER, C_POINTER, C_POINTER));
}
private static void downcall(FunctionDescriptor descriptor) {
RuntimeForeignAccess.registerForDowncall(descriptor);
}
private static void upcall(FunctionDescriptor descriptor) {
RuntimeForeignAccess.registerForUpcall(descriptor);
}
private static ValueLayout.OfLong sizeTLayout() {
ValueLayout layout = (ValueLayout) LINKER.canonicalLayouts().get("size_t");
if (layout.byteSize() != Long.BYTES) {
throw new UnsupportedOperationException("jlibghostty currently supports 64-bit platforms only");
}
return (ValueLayout.OfLong) layout;
}
}

View File

@@ -1,3 +1,5 @@
module dev.jlibghostty {
requires static org.graalvm.nativeimage;
exports dev.jlibghostty;
}

View File

@@ -0,0 +1,4 @@
Args = --features=dev.jlibghostty.GhosttyForeignRegistrationFeature \
-H:+UnlockExperimentalVMOptions \
-H:+ForeignAPISupport \
--enable-native-access=ALL-UNNAMED,dev.jlibghostty