Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -194,10 +194,10 @@ extension FFMSwift2JavaGenerator {
@SuppressWarnings("unused")
private static final boolean INITIALIZED_LIBS = initializeLibs();
static boolean initializeLibs() {
System.loadLibrary(SwiftLibraries.LIB_NAME_SWIFT_CORE);
System.loadLibrary(SwiftLibraries.LIB_NAME_SWIFT_JAVA);
System.loadLibrary(SwiftLibraries.LIB_NAME_SWIFT_RUNTIME_FUNCTIONS);
System.loadLibrary(LIB_NAME);
SwiftLibraries.loadLibraryWithFallbacks(SwiftLibraries.LIB_NAME_SWIFT_CORE);
SwiftLibraries.loadLibraryWithFallbacks(SwiftLibraries.LIB_NAME_SWIFT_JAVA);
SwiftLibraries.loadLibraryWithFallbacks(SwiftLibraries.LIB_NAME_SWIFT_RUNTIME_FUNCTIONS);
SwiftLibraries.loadLibraryWithFallbacks(LIB_NAME);
return true;
}

Expand Down Expand Up @@ -345,10 +345,10 @@ extension FFMSwift2JavaGenerator {
static final SymbolLookup SYMBOL_LOOKUP = getSymbolLookup();
private static SymbolLookup getSymbolLookup() {
if (SwiftLibraries.AUTO_LOAD_LIBS) {
System.loadLibrary(SwiftLibraries.LIB_NAME_SWIFT_CORE);
System.loadLibrary(SwiftLibraries.LIB_NAME_SWIFT_JAVA);
System.loadLibrary(SwiftLibraries.LIB_NAME_SWIFT_RUNTIME_FUNCTIONS);
System.loadLibrary(LIB_NAME);
SwiftLibraries.loadLibraryWithFallbacks(SwiftLibraries.LIB_NAME_SWIFT_CORE);
SwiftLibraries.loadLibraryWithFallbacks(SwiftLibraries.LIB_NAME_SWIFT_JAVA);
SwiftLibraries.loadLibraryWithFallbacks(SwiftLibraries.LIB_NAME_SWIFT_RUNTIME_FUNCTIONS);
SwiftLibraries.loadLibraryWithFallbacks(LIB_NAME);
}

if (PlatformUtils.isMacOS()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,39 +41,138 @@ public final class SwiftLibraries {
: Boolean.getBoolean("swiftkit.auto-load-libraries");

@SuppressWarnings("unused")
private static final boolean INITIALIZED_LIBS = loadLibraries(false);
private static final boolean INITIALIZED_LIBS = AUTO_LOAD_LIBS ? loadLibraries(false) : true;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that seems right, thanks


public static boolean loadLibraries(boolean loadSwiftRuntimeFunctions) {
System.loadLibrary(LIB_NAME_SWIFT_CORE);
System.loadLibrary(LIB_NAME_SWIFT_JAVA);
if (loadSwiftRuntimeFunctions) {
System.loadLibrary(LIB_NAME_SWIFT_RUNTIME_FUNCTIONS);
try {
loadLibraryWithFallbacks(LIB_NAME_SWIFT_CORE);
loadLibraryWithFallbacks(LIB_NAME_SWIFT_JAVA);
if (loadSwiftRuntimeFunctions) {
loadLibraryWithFallbacks(LIB_NAME_SWIFT_RUNTIME_FUNCTIONS);
}
return true;
} catch (RuntimeException e) {
// Libraries could not be loaded
if (CallTraces.TRACE_DOWNCALLS) {
System.err.println("[swift-java] Could not load libraries: " + e.getMessage());
System.err.println("[swift-java] Libraries will need to be loaded explicitly or from JAR resources");
}
return false;
}
return true;
}

// ==== ------------------------------------------------------------------------------------------------------------
// Loading libraries

public static void loadResourceLibrary(String libname) {
String resourceName = PlatformUtils.dynamicLibraryName(libname);
if (CallTraces.TRACE_DOWNCALLS) {
System.out.println("[swift-java] Loading resource library: " + resourceName);
/**
* Returns the platform-specific system path to the swiftCore library.
*
* @return Full path to swiftCore on the system, or null if platform is not macOS or Linux
*/
public static String libSwiftCorePath() {
if (PlatformUtils.isMacOS()) {
return "/usr/lib/swift/libswiftCore.dylib";
} else if (PlatformUtils.isLinux()) {
return "/usr/lib/swift/linux/libswiftCore.so";
}
return null;
}

/**
* Attempts to load a library using multiple fallback strategies with nice error reporting.
* Tries in order: java.library.path, JAR resources, system path (for swiftCore only).
*
* @param libname The library name to load
* @throws RuntimeException if all loading strategies fail
*/
public static void loadLibraryWithFallbacks(String libname) {
// Try 1: Load from java.library.path
try {
System.loadLibrary(libname);
if (CallTraces.TRACE_DOWNCALLS) {
System.out.println("[swift-java] Loaded " + libname + " from java.library.path");
}
return;
} catch (Throwable e) {
if (CallTraces.TRACE_DOWNCALLS) {
System.err.println("[swift-java] Failed to load " + libname + " from java.library.path: " + e.getMessage());
}
}

try (InputStream libInputStream = SwiftLibraries.class.getResourceAsStream("/" + resourceName)) {
if (libInputStream == null) {
throw new RuntimeException("Expected library '" + libname + "' ('" + resourceName + "') was not found as resource!");
// Try 2: Load from JAR resources
try {
loadResourceLibrary(libname);
if (CallTraces.TRACE_DOWNCALLS) {
System.out.println("[swift-java] Loaded " + libname + " from JAR resources");
}
return;
} catch (Throwable e2) {
if (CallTraces.TRACE_DOWNCALLS) {
System.err.println("[swift-java] Failed to load " + libname + " from JAR: " + e2.getMessage());
}

// TODO: we could do an in memory file system here
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The TODO is still valid, don't remove it

File tempFile = File.createTempFile(libname, "");
tempFile.deleteOnExit();
Files.copy(libInputStream, tempFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
// Try 3: For swiftCore only, try system path
if (libname.equals(LIB_NAME_SWIFT_CORE)) {
String systemPath = libSwiftCorePath();
if (systemPath != null) {
try {
System.load(systemPath);
if (CallTraces.TRACE_DOWNCALLS) {
System.out.println("[swift-java] Loaded " + libname + " from system path: " + systemPath);
}
return;
} catch (Throwable e3) {
throw new RuntimeException(
"Failed to load " + libname + " from java.library.path, JAR resources, and system path (" + systemPath + ")",
e3
);
}
} else {
if (CallTraces.TRACE_DOWNCALLS) {
System.err.println("[swift-java] System path not available on this platform");
}
}
}

System.load(tempFile.getAbsolutePath());
} catch (IOException e) {
throw new RuntimeException("Failed to load dynamic library '" + libname + "' ('" + resourceName + "') as resource!", e);
throw new RuntimeException("Failed to load " + libname + " from java.library.path and JAR resources", e2);
}
}

// Cache of already-loaded libraries to prevent duplicate extraction
private static final java.util.concurrent.ConcurrentHashMap<String, File> loadedLibraries = new java.util.concurrent.ConcurrentHashMap<>();

public static void loadResourceLibrary(String libname) {
loadedLibraries.computeIfAbsent(libname, key -> {
String resourceName = PlatformUtils.dynamicLibraryName(key);
if (CallTraces.TRACE_DOWNCALLS) {
System.out.println("[swift-java] Loading resource library: " + resourceName);
}

try (InputStream libInputStream = SwiftLibraries.class.getResourceAsStream("/" + resourceName)) {
if (libInputStream == null) {
throw new RuntimeException("Expected library '" + key + "' ('" + resourceName + "') was not found as resource!");
}

// TODO: we could do an in memory file system here
// Extract to temp file
File tempFile = File.createTempFile(key, "");
tempFile.deleteOnExit();
Files.copy(libInputStream, tempFile.toPath(), StandardCopyOption.REPLACE_EXISTING);

System.load(tempFile.getAbsolutePath());

if (CallTraces.TRACE_DOWNCALLS) {
System.out.println("[swift-java] Loaded and cached library: " + key + " from " + tempFile.getAbsolutePath());
}

return tempFile;
} catch (IOException e) {
throw new RuntimeException("Failed to load dynamic library '" + key + "' ('" + resourceName + "') as resource!", e);
}
});

if (CallTraces.TRACE_DOWNCALLS) {
System.out.println("[swift-java] Library already loaded from cache: " + libname);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import org.swift.swiftkit.core.SwiftInstance;
import org.swift.swiftkit.core.CallTraces;
import org.swift.swiftkit.core.SwiftLibraries;
import org.swift.swiftkit.core.util.PlatformUtils;
import org.swift.swiftkit.ffm.SwiftRuntime.swiftjava;

Expand All @@ -32,30 +33,34 @@

public class SwiftRuntime {

public static final String STDLIB_DYLIB_NAME = "swiftCore";
public static final String SWIFT_RUNTIME_FUNCTIONS_DYLIB_NAME = "SwiftRuntimeFunctions";

private static final String STDLIB_MACOS_DYLIB_PATH = "/usr/lib/swift/libswiftCore.dylib";

private static final Arena LIBRARY_ARENA = Arena.ofAuto();

@SuppressWarnings("unused")
private static final boolean INITIALIZED_LIBS = loadLibraries(false);

public static boolean loadLibraries(boolean loadSwiftRuntimeFunctions) {
System.loadLibrary(STDLIB_DYLIB_NAME);
if (loadSwiftRuntimeFunctions) {
System.loadLibrary(SWIFT_RUNTIME_FUNCTIONS_DYLIB_NAME);
try {
SwiftLibraries.loadLibraryWithFallbacks(SwiftLibraries.LIB_NAME_SWIFT_CORE);
if (loadSwiftRuntimeFunctions) {
SwiftLibraries.loadLibraryWithFallbacks(SwiftLibraries.LIB_NAME_SWIFT_RUNTIME_FUNCTIONS);
}
return true;
} catch (RuntimeException e) {
// Libraries could not be loaded
if (CallTraces.TRACE_DOWNCALLS) {
System.err.println("[swift-java] SwiftRuntime: Could not load libraries: " + e.getMessage());
System.err.println("[swift-java] Libraries will need to be loaded explicitly or from JAR resources");
}
return false;
}
return true;
}

static final SymbolLookup SYMBOL_LOOKUP = getSymbolLookup();

private static SymbolLookup getSymbolLookup() {
if (PlatformUtils.isMacOS()) {
// On Apple platforms we need to lookup using the complete path
return SymbolLookup.libraryLookup(STDLIB_MACOS_DYLIB_PATH, LIBRARY_ARENA)
return SymbolLookup.libraryLookup(SwiftLibraries.libSwiftCorePath(), LIBRARY_ARENA)
.or(SymbolLookup.loaderLookup())
.or(Linker.nativeLinker().defaultLookup());
} else {
Expand Down
Loading