Skip to content
Merged
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
20 changes: 13 additions & 7 deletions Plugins/JExtractSwiftPlugin/JExtractSwiftPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ private let SwiftJavaConfigFileName = "swift-java.config"
@main
struct JExtractSwiftBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin {

struct DependentConfigFile {
let swiftModuleName: String
let configURL: URL
}

var pluginName: String = "swift-java"
var verbose: Bool = getEnvironmentBool("SWIFT_JAVA_VERBOSE")

Expand Down Expand Up @@ -78,11 +83,10 @@ struct JExtractSwiftBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin {
arguments += ["--static-build-config", resolvedURL.absoluteURL.path(percentEncoded: false)]
}

let dependentConfigFilesArguments = dependentConfigFiles.flatMap { moduleAndConfigFile in
let (moduleName, configFile) = moduleAndConfigFile
return [
let dependentConfigFilesArguments = dependentConfigFiles.flatMap { dependentConfigFile in
[
"--depends-on",
"\(moduleName)=\(configFile.path(percentEncoded: false))",
"\(dependentConfigFile.swiftModuleName)=\(dependentConfigFile.configURL.path(percentEncoded: false))",
]
}
arguments += dependentConfigFilesArguments
Expand Down Expand Up @@ -270,8 +274,8 @@ struct JExtractSwiftBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin {

/// Find the manifest files from other swift-java executions in any targets
/// this target depends on.
func searchForDependentConfigFiles(in target: any Target) -> [(String, URL)] {
var dependentConfigFiles = [(String, URL)]()
func searchForDependentConfigFiles(in target: any Target) -> [DependentConfigFile] {
var dependentConfigFiles: [DependentConfigFile] = []

func _searchForConfigFiles(in target: any Target) {
// log("Search for config files in target: \(target.name)")
Expand All @@ -286,7 +290,9 @@ struct JExtractSwiftBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin {
.path(percentEncoded: false)

if FileManager.default.fileExists(atPath: dependencyConfigString) {
dependentConfigFiles.append((target.name, dependencyConfigURL))
dependentConfigFiles.append(
DependentConfigFile(swiftModuleName: target.name, configURL: dependencyConfigURL)
)
}
}

Expand Down
19 changes: 12 additions & 7 deletions Plugins/SwiftJavaPlugin/SwiftJavaPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ private let SwiftJavaConfigFileName = "swift-java.config"

@main
struct SwiftJavaBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin {
struct DependentConfigFile {
let swiftModuleName: String
let configURL: URL
}

var pluginName: String = "swift-java"
var verbose: Bool = getEnvironmentBool("SWIFT_JAVA_VERBOSE")
Expand Down Expand Up @@ -46,7 +50,7 @@ struct SwiftJavaBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin {

/// Find the manifest files from other swift-java executions in any targets
/// this target depends on.
var dependentConfigFiles: [(String, URL)] = []
var dependentConfigFiles: [DependentConfigFile] = []
func searchForConfigFiles(in target: any Target) {
// log("Search for config files in target: \(target.name)")
let dependencyURL = target.directoryURL
Expand All @@ -60,7 +64,9 @@ struct SwiftJavaBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin {
.path(percentEncoded: false)

if FileManager.default.fileExists(atPath: dependencyConfigString) {
dependentConfigFiles.append((target.name, dependencyConfigURL))
dependentConfigFiles.append(
DependentConfigFile(swiftModuleName: target.name, configURL: dependencyConfigURL)
)
}
}

Expand Down Expand Up @@ -223,12 +229,11 @@ extension SwiftJavaBuildToolPlugin {
]
}

func argumentsDependedOnConfigs(_ dependentConfigFiles: [(String, URL)]) -> [String] {
dependentConfigFiles.flatMap { moduleAndConfigFile in
let (moduleName, configFile) = moduleAndConfigFile
return [
func argumentsDependedOnConfigs(_ dependentConfigFiles: [DependentConfigFile]) -> [String] {
dependentConfigFiles.flatMap { dependentConfigFile in
[
"--depends-on",
"\(moduleName)=\(configFile.path(percentEncoded: false))",
"\(dependentConfigFile.swiftModuleName)=\(dependentConfigFile.configURL.path(percentEncoded: false))",
]
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import SwiftJavaJNICore

extension JavaType {

var jniTypeSignature: String {
switch self {
case .boolean: return "Z"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ extension JNISwift2JavaGenerator {
swiftModuleName: swiftModuleName,
javaPackage: self.javaPackage,
javaClassLookupTable: self.javaClassLookupTable,
moduleJavaPackages: self.moduleJavaPackages,
knownTypes: SwiftKnownTypes(symbolTable: lookupContext.symbolTable),
protocolWrappers: self.interfaceProtocolWrappers,
logger: self.logger,
Expand Down Expand Up @@ -64,6 +65,7 @@ extension JNISwift2JavaGenerator {
swiftModuleName: swiftModuleName,
javaPackage: self.javaPackage,
javaClassLookupTable: self.javaClassLookupTable,
moduleJavaPackages: self.moduleJavaPackages,
knownTypes: SwiftKnownTypes(symbolTable: lookupContext.symbolTable),
protocolWrappers: self.interfaceProtocolWrappers,
logger: self.logger,
Expand All @@ -85,6 +87,7 @@ extension JNISwift2JavaGenerator {
let swiftModuleName: String
let javaPackage: String
let javaClassLookupTable: JavaClassLookupTable
let moduleJavaPackages: ModuleJavaPackages
var knownTypes: SwiftKnownTypes
let protocolWrappers: [ImportedNominalType: JavaInterfaceSwiftWrapper]
let logger: Logger
Expand Down Expand Up @@ -546,7 +549,7 @@ extension JNISwift2JavaGenerator {
}

let javaType = JavaType.class(
package: nil,
package: moduleJavaPackages[nominalType.nominalTypeDecl.moduleName],
name: nominalTypeName,
typeParameters: try nominalType.genericArguments?.map { swiftType in
try translateGenericTypeParameter(
Expand Down Expand Up @@ -982,7 +985,7 @@ extension JNISwift2JavaGenerator {
}

let javaType = JavaType.class(
package: nil,
package: moduleJavaPackages[nominalType.nominalTypeDecl.moduleName],
name: nominalType.nominalTypeDecl.qualifiedName,
typeParameters: try nominalType.genericArguments?.map { swiftType in
try translateGenericTypeParameter(
Expand Down Expand Up @@ -1131,7 +1134,7 @@ extension JNISwift2JavaGenerator {
} ?? []

return .class(
package: nil,
package: moduleJavaPackages[nominalType.nominalTypeDecl.moduleName],
name: nominalTypeName,
typeParameters: typeParameters,
)
Expand Down Expand Up @@ -1512,7 +1515,7 @@ extension JNISwift2JavaGenerator {
],
),
function: "toArray",
arguments: [.constant("\(javaType.className!)[]::new")]
arguments: [.constant("\(javaType.fullyQualifiedClassName!)[]::new")]
)
)

Expand Down Expand Up @@ -1914,7 +1917,7 @@ extension JNISwift2JavaGenerator {

case .wrapMemoryAddressUnsafe(let inner, let javaType):
let inner = inner.render(&printer, placeholder)
guard case .class(_, let className, let typeParameters) = javaType else {
guard case .class(_, _, let typeParameters) = javaType else {
fatalError("\(javaType) is not class.")
}
let genericClause =
Expand All @@ -1923,7 +1926,7 @@ extension JNISwift2JavaGenerator {
} else {
""
}
return "\(className).\(genericClause)wrapMemoryAddressUnsafe(\(inner), swiftArena)"
return "\(javaType.fullyQualifiedClassName!).\(genericClause)wrapMemoryAddressUnsafe(\(inner), swiftArena)"

case .constructJavaClass(let inner, let javaType):
let inner = inner.render(&printer, placeholder)
Expand Down
6 changes: 6 additions & 0 deletions Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ import SwiftJavaJNICore
/// the fully qualified canoical names.
package typealias JavaClassLookupTable = [String: String]

/// A table where keys are Swift module names and the values are Java package names.
package typealias ModuleJavaPackages = [String: String]

package class JNISwift2JavaGenerator: Swift2JavaGenerator {

let logger: Logger
Expand All @@ -32,6 +35,7 @@ package class JNISwift2JavaGenerator: Swift2JavaGenerator {
let lookupContext: SwiftTypeLookupContext

let javaClassLookupTable: JavaClassLookupTable
let moduleJavaPackages: ModuleJavaPackages

var javaPackagePath: String {
javaPackage.replacingOccurrences(of: ".", with: "/")
Expand Down Expand Up @@ -75,6 +79,7 @@ package class JNISwift2JavaGenerator: Swift2JavaGenerator {
swiftOutputDirectory: String,
javaOutputDirectory: String,
javaClassLookupTable: JavaClassLookupTable,
moduleJavaPackages: ModuleJavaPackages,
) {
self.config = config
self.logger = Logger(label: "jni-generator", logLevel: translator.log.logLevel)
Expand All @@ -84,6 +89,7 @@ package class JNISwift2JavaGenerator: Swift2JavaGenerator {
self.swiftOutputDirectory = swiftOutputDirectory
self.javaOutputDirectory = javaOutputDirectory
self.javaClassLookupTable = javaClassLookupTable
self.moduleJavaPackages = moduleJavaPackages
self.lookupContext = translator.lookupContext

// If we are forced to write empty files, construct the expected outputs.
Expand Down
20 changes: 16 additions & 4 deletions Sources/JExtractSwiftLib/Swift2Java.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ import SwiftSyntaxBuilder

public struct SwiftToJava {
let config: Configuration
let dependentConfigs: [Configuration]
let dependentConfigs: [DependentConfig]

public init(config: Configuration, dependentConfigs: [Configuration]) {
public init(config: Configuration, dependentConfigs: [DependentConfig]) {
self.config = config
self.dependentConfigs = dependentConfigs
}
Expand Down Expand Up @@ -95,12 +95,23 @@ public struct SwiftToJava {
fatalError("Missing --output-java directory!")
}

let wrappedJavaClassesLookupTable: JavaClassLookupTable = dependentConfigs.compactMap(\.classes).reduce(into: [:]) {
let wrappedJavaClassesLookupTable: JavaClassLookupTable = dependentConfigs.compactMap(\.configuration.classes).reduce(into: [:]) {
for (canonicalName, javaClass) in $1 {
$0[javaClass] = canonicalName
}
}

let moduleJavaPackages = dependentConfigs.reduce(into: [String: String]()) { partialResult, dependency in
guard
let moduleName = dependency.swiftModuleName,
let javaPackage = dependency.configuration.javaPackage,
!javaPackage.isEmpty
else {
return
}
partialResult[moduleName] = javaPackage
}

translator.dependenciesClasses = Array(wrappedJavaClassesLookupTable.keys)

try translator.analyze()
Expand All @@ -124,7 +135,8 @@ public struct SwiftToJava {
javaPackage: config.javaPackage ?? "",
swiftOutputDirectory: outputSwiftDirectory,
javaOutputDirectory: outputJavaDirectory,
javaClassLookupTable: wrappedJavaClassesLookupTable
javaClassLookupTable: wrappedJavaClassesLookupTable,
moduleJavaPackages: moduleJavaPackages
)

try generator.generate()
Expand Down
18 changes: 14 additions & 4 deletions Sources/SwiftJavaConfigurationShared/Configuration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -426,9 +426,19 @@ public func readConfiguration(
}
}

/// Load all dependent configs configured with `--depends-on` and return a list of
/// `(SwiftModuleName, Configuration)` tuples.
public func loadDependentConfigs(dependsOn: [String]) throws -> [(String?, Configuration)] {
/// Parsed dependent configuration provided via `--depends-on`.
public struct DependentConfig {
public let swiftModuleName: String?
public let configuration: Configuration

public init(swiftModuleName: String?, configuration: Configuration) {
self.swiftModuleName = swiftModuleName
self.configuration = configuration
}
}

/// Load all dependent configs configured with `--depends-on`.
public func loadDependentConfigs(dependsOn: [String]) throws -> [DependentConfig] {
try dependsOn.map { dependentConfig in
let equalLoc = dependentConfig.firstIndex(of: "=")

Expand All @@ -442,7 +452,7 @@ public func loadDependentConfigs(dependsOn: [String]) throws -> [(String?, Confi

let config = try readConfiguration(configPath: URL(fileURLWithPath: configFileName)) ?? Configuration()

return (swiftModuleName, config)
return DependentConfig(swiftModuleName: swiftModuleName, configuration: config)
}
}

Expand Down
4 changes: 2 additions & 2 deletions Sources/SwiftJavaTool/Commands/JExtractCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ extension SwiftJava.JExtractCommand {
let dependentConfigs = try loadDependentConfigs(dependsOn: self.dependsOn)
print("[debug][swift-java] Dependent configs: \(dependentConfigs.count)")

try jextractSwift(config: config, dependentConfigs: dependentConfigs.map(\.1))
try jextractSwift(config: config, dependentConfigs: dependentConfigs)
}

/// Check if the configured modes are compatible, and fail if not
Expand Down Expand Up @@ -207,7 +207,7 @@ struct IncompatibleModeError: Error {
extension SwiftJava.JExtractCommand {
func jextractSwift(
config: Configuration,
dependentConfigs: [Configuration],
dependentConfigs: [DependentConfig],
) throws {
try SwiftToJava(config: config, dependentConfigs: dependentConfigs).run()
}
Expand Down
26 changes: 15 additions & 11 deletions Sources/SwiftJavaTool/Commands/WrapJavaCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ extension SwiftJava {
}

extension SwiftJava.WrapJavaCommand {
struct NamedDependentConfig {
let swiftModuleName: String
let configuration: Configuration
}

mutating func runSwiftJavaCommand(config: inout Configuration) async throws {
print("self.filterInclude = \(self.filterInclude)")
Expand All @@ -101,23 +105,23 @@ extension SwiftJava.WrapJavaCommand {
)

// Load all of the dependent configurations and associate them with Swift modules.
let dependentConfigs = try loadDependentConfigs(dependsOn: self.dependsOn).map { moduleName, config in
guard let moduleName else {
let dependentConfigs = try loadDependentConfigs(dependsOn: self.dependsOn).map { dependentConfig in
guard let moduleName = dependentConfig.swiftModuleName else {
throw JavaToSwiftError.badConfigOption(self.dependsOn.joined(separator: " "))
}
return (moduleName, config)
return NamedDependentConfig(swiftModuleName: moduleName, configuration: dependentConfig.configuration)
}
print("[debug][swift-java] Dependent configs: \(dependentConfigs.count)")

// Include classpath entries which libs we depend on require...
for (fromModule, config) in dependentConfigs {
for dependentConfig in dependentConfigs {
print(
"[trace][swift-java] Add dependent config (\(fromModule)) classpath elements: \(config.classpathEntries.count)"
"[trace][swift-java] Add dependent config (\(dependentConfig.swiftModuleName)) classpath elements: \(dependentConfig.configuration.classpathEntries.count)"
)
// TODO: may need to resolve the dependent configs rather than just get their configs
// TODO: We should cache the resolved classpaths as well so we don't do it many times
for entry in config.classpathEntries {
print("[trace][swift-java] Add dependent config (\(fromModule)) classpath element: \(entry)")
for entry in dependentConfig.configuration.classpathEntries {
print("[trace][swift-java] Add dependent config (\(dependentConfig.swiftModuleName)) classpath element: \(entry)")
classpathEntries.append(entry)
}
}
Expand All @@ -137,7 +141,7 @@ extension SwiftJava.WrapJavaCommand {

mutating func generateWrappers(
config: Configuration,
dependentConfigs: [(String, Configuration)],
dependentConfigs: [NamedDependentConfig],
environment: JNIEnvironment
) throws {
let translator = JavaTranslator(
Expand All @@ -163,10 +167,10 @@ extension SwiftJava.WrapJavaCommand {
}

// Note all of the dependent configurations.
for (swiftModuleName, dependentConfig) in dependentConfigs {
for dependentConfig in dependentConfigs {
translator.addConfiguration(
dependentConfig,
forSwiftModule: swiftModuleName
dependentConfig.configuration,
forSwiftModule: dependentConfig.swiftModuleName
)
}

Expand Down
3 changes: 2 additions & 1 deletion Tests/JExtractSwiftTests/Asserts/TextAssertions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ func assertOutput(
javaPackage: "com.example.swift",
swiftOutputDirectory: "/fake",
javaOutputDirectory: "/fake",
javaClassLookupTable: javaClassLookupTable
javaClassLookupTable: javaClassLookupTable,
moduleJavaPackages: [:]
)

switch renderKind {
Expand Down
Loading
Loading