diff --git a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift index ceb8c426..b711f9b7 100644 --- a/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift +++ b/Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift @@ -256,20 +256,37 @@ extension FFMSwift2JavaGenerator { printNominal(&printer, decl) { printer in // We use a static field to abuse the initialization order such that by the time we get type metadata, // we already have loaded the library where it will be obtained from. - printer.printParts( - """ - @SuppressWarnings("unused") - private static final boolean INITIALIZED_LIBS = initializeLibs(); - static boolean initializeLibs() { - 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; + if let overrideLoading = self.config.overrideStaticBlockLibraryLoading { + if !overrideLoading.isEmpty { + let body = overrideLoading.map { " \($0)" }.joined(separator: "\n") + printer.printParts( + """ + @SuppressWarnings("unused") + private static final boolean INITIALIZED_LIBS = initializeLibs(); + static boolean initializeLibs() { + \(body) + return true; + } + """ + ) + printer.print("") } - """ - ) - printer.print("") + } else { + printer.printParts( + """ + @SuppressWarnings("unused") + private static final boolean INITIALIZED_LIBS = initializeLibs(); + static boolean initializeLibs() { + 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; + } + """ + ) + printer.print("") + } // Type metadata (common to all nominal types) printer.printParts( @@ -479,12 +496,35 @@ extension FFMSwift2JavaGenerator { """ static final SymbolLookup SYMBOL_LOOKUP = getSymbolLookup(); private static SymbolLookup getSymbolLookup() { - if (SwiftLibraries.AUTO_LOAD_LIBS) { - 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 let overrideLoading = config.overrideStaticBlockLibraryLoading { + if !overrideLoading.isEmpty { + let body = overrideLoading.map { " \($0)" }.joined(separator: "\n") + printer.print( + """ + if (SwiftLibraries.AUTO_LOAD_LIBS) { + \(body) + } + """ + ) + } + } else { + printer.print( + """ + if (SwiftLibraries.AUTO_LOAD_LIBS) { + 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); + } + """ + ) + } + + printer.print( + """ if (PlatformUtils.isMacOS()) { return SymbolLookup.libraryLookup(System.mapLibraryName(LIB_NAME), LIBRARY_ARENA) diff --git a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift index 42c4ce38..ffe9971c 100644 --- a/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift +++ b/Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift @@ -112,14 +112,33 @@ extension JNISwift2JavaGenerator { printer.print( """ static final String LIB_NAME = "\(config.nativeLibraryName ?? swiftModuleName)"; - - static { - System.loadLibrary(SwiftLibraries.LIB_NAME_SWIFT_JAVA); - System.loadLibrary(LIB_NAME); - } """ ) + if let overrideLoading = config.overrideStaticBlockLibraryLoading { + if !overrideLoading.isEmpty { + let body = overrideLoading.map { " \($0)" }.joined(separator: "\n") + printer.print( + """ + + static { + \(body) + } + """ + ) + } + } else { + printer.print( + """ + + static { + System.loadLibrary(SwiftLibraries.LIB_NAME_SWIFT_JAVA); + System.loadLibrary(LIB_NAME); + } + """ + ) + } + for decl in analysis.importedGlobalFuncs { self.logger.trace("Print global function: \(decl)") printFunctionDowncallMethods(&printer, decl) @@ -201,17 +220,39 @@ extension JNISwift2JavaGenerator { printer.print( """ static final String LIB_NAME = "\(config.nativeLibraryName ?? swiftModuleName)"; - - @SuppressWarnings("unused") - private static final boolean INITIALIZED_LIBS = initializeLibs(); - static boolean initializeLibs() { - System.loadLibrary(SwiftLibraries.LIB_NAME_SWIFT_JAVA); - System.loadLibrary(LIB_NAME); - return true; - } """ ) + if let overrideLoading = config.overrideStaticBlockLibraryLoading { + if !overrideLoading.isEmpty { + let body = overrideLoading.map { " \($0)" }.joined(separator: "\n") + printer.print( + """ + + @SuppressWarnings("unused") + private static final boolean INITIALIZED_LIBS = initializeLibs(); + static boolean initializeLibs() { + \(body) + return true; + } + """ + ) + } + } else { + printer.print( + """ + + @SuppressWarnings("unused") + private static final boolean INITIALIZED_LIBS = initializeLibs(); + static boolean initializeLibs() { + System.loadLibrary(SwiftLibraries.LIB_NAME_SWIFT_JAVA); + System.loadLibrary(LIB_NAME); + return true; + } + """ + ) + } + let nestedTypes = self.analysis.importedTypes.filter { _, type in type.parent == decl.swiftNominal } diff --git a/Sources/SwiftJavaConfigurationShared/Configuration.swift b/Sources/SwiftJavaConfigurationShared/Configuration.swift index ea5981f2..43ab445e 100644 --- a/Sources/SwiftJavaConfigurationShared/Configuration.swift +++ b/Sources/SwiftJavaConfigurationShared/Configuration.swift @@ -38,6 +38,14 @@ public struct Configuration: Codable { /// (e.g. the module is `MyLibrary` but the dylib is `MyLibrarySwiftJava` or something else). public var nativeLibraryName: String? + /// When non-nil, overrides the library loading statements emitted in the + /// `static {}` / `initializeLibs()` block of generated Java classes. + /// Each string is emitted as a verbatim Java statement. + /// + /// When `nil` (the default), the standard loading calls are emitted. + /// When set to an empty array `[]`, no library loading code is emitted at all. + public var overrideStaticBlockLibraryLoading: [String]? + public var inputSwiftDirectory: String? public var outputSwiftDirectory: String? diff --git a/Tests/JExtractSwiftTests/JNI/JNIModuleTests.swift b/Tests/JExtractSwiftTests/JNI/JNIModuleTests.swift index 0b6b4870..40e47b47 100644 --- a/Tests/JExtractSwiftTests/JNI/JNIModuleTests.swift +++ b/Tests/JExtractSwiftTests/JNI/JNIModuleTests.swift @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// import JExtractSwiftLib +import SwiftJavaConfigurationShared import Testing @Suite @@ -277,4 +278,53 @@ struct JNIModuleTests { ] ) } + + @Test + func generatesModuleJavaClass_overrideStaticBlockLibraryLoading_empty() throws { + let input = "public func helloWorld()" + var config = Configuration() + config.overrideStaticBlockLibraryLoading = [] + + try assertOutput( + input: input, + config: config, + .jni, + .java, + expectedChunks: [ + """ + static final String LIB_NAME = "SwiftModule"; + """ + ], + notExpectedChunks: [ + "System.loadLibrary", + "initializeLibs", + ] + ) + } + + @Test + func generatesModuleJavaClass_overrideStaticBlockLibraryLoading_custom() throws { + let input = "public func helloWorld()" + var config = Configuration() + config.overrideStaticBlockLibraryLoading = [ + "System.loadLibrary(\"SomeSpecialName\");" + ] + + try assertOutput( + input: input, + config: config, + .jni, + .java, + expectedChunks: [ + """ + static { + System.loadLibrary("SomeSpecialName"); + } + """ + ], + notExpectedChunks: [ + "SwiftLibraries.LIB_NAME_SWIFT_JAVA" + ] + ) + } } diff --git a/Tests/JExtractSwiftTests/JNI/JNIStructTests.swift b/Tests/JExtractSwiftTests/JNI/JNIStructTests.swift index e7a5cb80..411bd377 100644 --- a/Tests/JExtractSwiftTests/JNI/JNIStructTests.swift +++ b/Tests/JExtractSwiftTests/JNI/JNIStructTests.swift @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// import JExtractSwiftLib +import SwiftJavaConfigurationShared import Testing @Suite @@ -206,4 +207,27 @@ struct JNIStructTests { ] ) } + + @Test + func generatesStructJavaClass_overrideStaticBlockLibraryLoading_empty() throws { + var config = Configuration() + config.overrideStaticBlockLibraryLoading = [] + + try assertOutput( + input: source, + config: config, + .jni, + .java, + expectedChunks: [ + """ + public final class MyStruct implements JNISwiftInstance { + static final String LIB_NAME = "SwiftModule"; + """ + ], + notExpectedChunks: [ + "System.loadLibrary", + "initializeLibs", + ] + ) + } }