diff --git a/klang/jextract/src/main/java/org/openjdk/jextract/clang/libclang/RuntimeHelper.java b/klang/jextract/src/main/java/org/openjdk/jextract/clang/libclang/RuntimeHelper.java index f1ace42f..5c5490d4 100644 --- a/klang/jextract/src/main/java/org/openjdk/jextract/clang/libclang/RuntimeHelper.java +++ b/klang/jextract/src/main/java/org/openjdk/jextract/clang/libclang/RuntimeHelper.java @@ -26,26 +26,17 @@ package org.openjdk.jextract.clang.libclang; // Generated by jextract -import java.lang.foreign.Arena; -import java.lang.foreign.Linker; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.GroupLayout; -import java.lang.foreign.SymbolLookup; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.lang.foreign.ValueLayout; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.lang.foreign.*; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import java.io.File; +import java.nio.file.Files; import java.nio.file.Path; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.Optional; -import java.util.stream.Stream; +import java.nio.file.StandardCopyOption; -import static java.lang.foreign.Linker.*; import static java.lang.foreign.ValueLayout.*; final class RuntimeHelper { @@ -54,22 +45,37 @@ final class RuntimeHelper { private static final ClassLoader LOADER = RuntimeHelper.class.getClassLoader(); private static final MethodHandles.Lookup MH_LOOKUP = MethodHandles.lookup(); private static final SymbolLookup SYMBOL_LOOKUP; - private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { throw new AssertionError("should not reach here"); }; + private static final SegmentAllocator THROWING_ALLOCATOR = (x, y) -> { + throw new AssertionError("should not reach here"); + }; final static SegmentAllocator CONSTANT_ALLOCATOR = (size, align) -> Arena.ofAuto().allocate(size, align); static { + var libraryFile = new File(getTemporaryDirectory() + inferLibraryFileName()); + if (!libraryFile.exists()) { + var embeddedLibraryFile = findFileInClasspath(inferEmbededLibraryFileName()); + try { + copyInputStreamToFile(embeddedLibraryFile, libraryFile.getAbsolutePath()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + libraryFile.deleteOnExit(); + + System.load(libraryFile.getAbsolutePath()); // Manual change to handle platform specific library name difference - String libName = System.getProperty("os.name").startsWith("Windows")? "libclang" : "clang"; - System.loadLibrary(libName); + //String libName = System.getProperty("os.name").startsWith("Windows") ? "libclang" : "clang"; + //System.loadLibrary(libName); SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); SYMBOL_LOOKUP = name -> loaderLookup.find(name).or(() -> LINKER.defaultLookup().find(name)); } // Suppresses default constructor, ensuring non-instantiability. - private RuntimeHelper() {} + private RuntimeHelper() { + } static T requireNonNull(T obj, String symbolName) { if (obj == null) { @@ -111,7 +117,7 @@ static MemorySegment upcallStub(Class fi, Z z, FunctionDescriptor fdesc, } static MemorySegment asArray(MemorySegment addr, MemoryLayout layout, int numElements, Arena arena) { - return addr.reinterpret(numElements * layout.byteSize(), arena, null); + return addr.reinterpret(numElements * layout.byteSize(), arena, null); } // Internals only below this point @@ -143,7 +149,7 @@ static MethodHandle make(MemorySegment symbol, FunctionDescriptor function) { } mtype = mtype.appendParameterTypes(Object[].class); boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; + function.returnLayout().get() instanceof GroupLayout; if (needsAllocator) { mtype = mtype.insertParameterTypes(0, SegmentAllocator.class); } else { @@ -165,7 +171,7 @@ static Class carrier(MemoryLayout layout, boolean ret) { private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwable { // one trailing Object[] int nNamedArgs = function.argumentLayouts().size(); - assert(args.length == nNamedArgs + 1); + assert (args.length == nNamedArgs + 1); // The last argument is the array of vararg collector Object[] unnamedArgs = (Object[]) args[args.length - 1]; @@ -179,7 +185,7 @@ private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwabl } assert pos == nNamedArgs; - for (Object o: unnamedArgs) { + for (Object o : unnamedArgs) { argLayouts[pos] = variadicLayout(normalize(o.getClass())); pos++; } @@ -190,7 +196,7 @@ private Object invoke(SegmentAllocator allocator, Object[] args) throws Throwabl FunctionDescriptor.of(function.returnLayout().get(), argLayouts); MethodHandle mh = LINKER.downcallHandle(symbol, f); boolean needsAllocator = function.returnLayout().isPresent() && - function.returnLayout().get() instanceof GroupLayout; + function.returnLayout().get() instanceof GroupLayout; if (needsAllocator) { mh = mh.bindTo(allocator); } @@ -259,4 +265,62 @@ private MemoryLayout variadicLayout(Class c) { } } } + + private static String inferEmbededLibraryFileName() { + return STR."libclang-\{inferArchitecture()}.\{inferLibraryExtension()}"; + } + + private static String inferLibraryFileName() { + return STR."libclang.\{inferLibraryExtension()}"; + } + + private static String inferLibraryExtension() { + var osName = System.getProperty("os.name").toLowerCase(); + + if (osName.startsWith("windows")) { + return "dll"; + } else if (osName.contains("nix") || osName.contains("nux")) { + return "so"; + } else if (osName.contains("mac")) { + return "dylib"; + } + + throw new UnsupportedOperationException(STR."Unsupported operating system: \{osName}"); + } + + private static String inferArchitecture() { + var architecture = System.getProperty("os.arch").toLowerCase(); + + if (architecture.contains("amd64") + || architecture.contains("x86_64") + || architecture.contains("x86") + || architecture.contains("i386")) { + return "x86_64"; + } else if (architecture.contains("arm")) { + return "arm86"; + } + + throw new UnsupportedOperationException(STR."Unsupported architecture: \{architecture}"); + } + private static InputStream findFileInClasspath(String fileName) { + // Get current classloader + ClassLoader classLoader = RuntimeHelper.class.getClassLoader(); + + // Find the resource + InputStream resourceStream = classLoader.getResourceAsStream(fileName); + + if (resourceStream == null) { + throw new IllegalArgumentException(STR."File not found in classpath: \{fileName}"); + } + + return resourceStream; + } + + private static void copyInputStreamToFile(InputStream source, String targetFilePath) throws IOException { + Files.copy(source, Path.of(targetFilePath), StandardCopyOption.REPLACE_EXISTING); + } + + private static String getTemporaryDirectory() { + return System.getProperty("java.io.tmpdir"); + } } diff --git a/klang/klang/build.gradle.kts b/klang/klang/build.gradle.kts index 0d4a838e..8ac1d7d8 100644 --- a/klang/klang/build.gradle.kts +++ b/klang/klang/build.gradle.kts @@ -45,9 +45,9 @@ tasks.withType().configureEach { "--enable-native-access=ALL-UNNAMED" //, "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005" ) - systemProperties( + /*systemProperties( "java.library.path" to inferPlatformClangPath()?.toFile()?.absolutePath - ) + )*/ } private fun inferPlatformClangPath(): Path? { diff --git a/klang/klang/src/main/kotlin/klang/parser/libclang/panama/TypeRef.kt b/klang/klang/src/main/kotlin/klang/parser/libclang/panama/TypeRef.kt index 1230e611..d486bd27 100644 --- a/klang/klang/src/main/kotlin/klang/parser/libclang/panama/TypeRef.kt +++ b/klang/klang/src/main/kotlin/klang/parser/libclang/panama/TypeRef.kt @@ -15,5 +15,6 @@ internal fun Type.toTypeRef(): TypeRef = when (this) { private fun Type.toTypeString(): String = when (this) { is TypeImpl.DeclaredImpl -> tree().name() is TypeImpl.PrimitiveImpl -> kind().typeName() + is TypeImpl.QualifiedImpl -> type().toTypeString() else -> TODO("unsupported yet") }