diff --git a/Package.swift b/Package.swift
index 42b74041..16c8a1a3 100644
--- a/Package.swift
+++ b/Package.swift
@@ -4,8 +4,7 @@
import CompilerPluginSupport
import PackageDescription
-import class Foundation.FileManager
-import class Foundation.ProcessInfo
+import Foundation
// Note: the JAVA_HOME environment variable must be set to point to where
// Java is installed, e.g.,
@@ -25,9 +24,53 @@ func findJavaHome() -> String {
return home
}
+
+ if let home = getJavaHomeFromLibexecJavaHome(),
+ !home.isEmpty {
+ return home
+ }
fatalError("Please set the JAVA_HOME environment variable to point to where Java is installed.")
}
+
+/// On MacOS we can use the java_home tool as a fallback if we can't find JAVA_HOME environment variable.
+func getJavaHomeFromLibexecJavaHome() -> String? {
+ let task = Process()
+ task.executableURL = URL(fileURLWithPath: "/usr/libexec/java_home")
+
+ // Check if the executable exists before trying to run it
+ guard FileManager.default.fileExists(atPath: task.executableURL!.path) else {
+ print("/usr/libexec/java_home does not exist")
+ return nil
+ }
+
+ let pipe = Pipe()
+ task.standardOutput = pipe
+ task.standardError = pipe // Redirect standard error to the same pipe for simplicity
+
+ do {
+ try task.run()
+ task.waitUntilExit()
+
+ let data = pipe.fileHandleForReading.readDataToEndOfFile()
+ let output = String(data: data, encoding: .utf8)?.trimmingCharacters(in: .whitespacesAndNewlines)
+
+ if task.terminationStatus == 0 {
+ return output
+ } else {
+ print("java_home terminated with status: \(task.terminationStatus)")
+ // Optionally, log the error output for debugging
+ if let errorOutput = String(data: pipe.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8) {
+ print("Error output: \(errorOutput)")
+ }
+ return nil
+ }
+ } catch {
+ print("Error running java_home: \(error)")
+ return nil
+ }
+}
+
let javaHome = findJavaHome()
let javaIncludePath = "\(javaHome)/include"
@@ -92,8 +135,8 @@ let package = Package(
),
.executable(
- name: "Java2Swift",
- targets: ["Java2Swift"]
+ name: "swift-java",
+ targets: ["SwiftJavaTool"]
),
// ==== Plugin for building Java code
@@ -106,19 +149,12 @@ let package = Package(
// ==== Plugin for wrapping Java classes in Swift
.plugin(
- name: "Java2SwiftPlugin",
+ name: "SwiftJavaPlugin",
targets: [
- "Java2SwiftPlugin"
+ "SwiftJavaPlugin"
]
),
- // ==== jextract-swift (extract Java accessors from Swift interface files)
-
- .executable(
- name: "jextract-swift",
- targets: ["JExtractSwiftTool"]
- ),
-
// Support library written in Swift for SwiftKit "Java"
.library(
name: "SwiftKitSwift",
@@ -127,8 +163,8 @@ let package = Package(
),
.library(
- name: "JExtractSwift",
- targets: ["JExtractSwift"]
+ name: "JExtractSwiftLib",
+ targets: ["JExtractSwiftLib"]
),
// ==== Plugin for wrapping Java classes in Swift
@@ -271,10 +307,10 @@ let package = Package(
),
.plugin(
- name: "Java2SwiftPlugin",
+ name: "SwiftJavaPlugin",
capability: .buildTool(),
dependencies: [
- "Java2Swift"
+ "SwiftJavaTool"
]
),
@@ -312,7 +348,7 @@ let package = Package(
),
.target(
- name: "Java2SwiftLib",
+ name: "SwiftJavaLib",
dependencies: [
.product(name: "SwiftBasicFormat", package: "swift-syntax"),
.product(name: "SwiftSyntax", package: "swift-syntax"),
@@ -334,7 +370,7 @@ let package = Package(
),
.executableTarget(
- name: "Java2Swift",
+ name: "SwiftJavaTool",
dependencies: [
.product(name: "SwiftBasicFormat", package: "swift-syntax"),
.product(name: "SwiftSyntax", package: "swift-syntax"),
@@ -343,7 +379,8 @@ let package = Package(
"JavaKit",
"JavaKitJar",
"JavaKitNetwork",
- "Java2SwiftLib",
+ "SwiftJavaLib",
+ "JExtractSwiftLib",
"JavaKitShared",
],
@@ -355,7 +392,7 @@ let package = Package(
),
.target(
- name: "JExtractSwift",
+ name: "JExtractSwiftLib",
dependencies: [
.product(name: "SwiftBasicFormat", package: "swift-syntax"),
.product(name: "SwiftSyntax", package: "swift-syntax"),
@@ -370,21 +407,11 @@ let package = Package(
]
),
- .executableTarget(
- name: "JExtractSwiftTool",
- dependencies: [
- "JExtractSwift",
- ],
- swiftSettings: [
- .swiftLanguageMode(.v5)
- ]
- ),
-
.plugin(
name: "JExtractSwiftPlugin",
capability: .buildTool(),
dependencies: [
- "JExtractSwiftTool"
+ "SwiftJavaTool"
]
),
.plugin(
@@ -394,7 +421,7 @@ let package = Package(
permissions: [
]),
dependencies: [
- "JExtractSwiftTool"
+ "SwiftJavaTool"
]
),
@@ -427,8 +454,8 @@ let package = Package(
),
.testTarget(
- name: "Java2SwiftTests",
- dependencies: ["Java2SwiftLib"],
+ name: "SwiftJavaTests",
+ dependencies: ["SwiftJavaLib"],
swiftSettings: [
.swiftLanguageMode(.v5),
.unsafeFlags(["-I\(javaIncludePath)", "-I\(javaPlatformIncludePath)"])
@@ -438,7 +465,7 @@ let package = Package(
.testTarget(
name: "JExtractSwiftTests",
dependencies: [
- "JExtractSwift"
+ "JExtractSwiftLib"
],
swiftSettings: [
.swiftLanguageMode(.v5),
diff --git a/Plugins/JExtractSwiftCommandPlugin/JExtractSwiftCommandPlugin.swift b/Plugins/JExtractSwiftCommandPlugin/JExtractSwiftCommandPlugin.swift
index d6cfb7cb..3ea89886 100644
--- a/Plugins/JExtractSwiftCommandPlugin/JExtractSwiftCommandPlugin.swift
+++ b/Plugins/JExtractSwiftCommandPlugin/JExtractSwiftCommandPlugin.swift
@@ -69,21 +69,21 @@ final class JExtractSwiftCommandPlugin: SwiftJavaPluginProtocol, BuildToolPlugin
let sourceDir = target.directory.string
let configuration = try readConfiguration(sourceDir: "\(sourceDir)")
- guard let javaPackage = configuration.javaPackage else {
- throw SwiftJavaPluginError.missingConfiguration(sourceDir: "\(sourceDir)", key: "javaPackage")
- }
var arguments: [String] = [
- "--swift-module", sourceModule.name,
- "--package-name", javaPackage,
- "--output-directory-java", context.outputDirectoryJava.path(percentEncoded: false),
- "--output-directory-swift", context.outputDirectorySwift.path(percentEncoded: false),
+ "--input-swift", sourceDir,
+ "--module-name", sourceModule.name,
+ "--output-java", context.outputJavaDirectory.path(percentEncoded: false),
+ "--output-swift", context.outputSwiftDirectory.path(percentEncoded: false),
// TODO: "--build-cache-directory", ...
// Since plugins cannot depend on libraries we cannot detect what the output files will be,
// as it depends on the contents of the input files. Therefore we have to implement this as a prebuild plugin.
// We'll have to make up some caching inside the tool so we don't re-parse files which have not changed etc.
]
- arguments.append(sourceDir)
+ // arguments.append(sourceDir) // TODO: we could do this shape maybe? to have the dirs last?
+ if let package = configuration?.javaPackage, !package.isEmpty {
+ ["--java-package", package]
+ }
return arguments
}
@@ -130,7 +130,7 @@ final class JExtractSwiftCommandPlugin: SwiftJavaPluginProtocol, BuildToolPlugin
func runExtract(context: PluginContext, target: Target, arguments: [String]) throws {
let process = Process()
- process.executableURL = try context.tool(named: "JExtractSwiftTool").url
+ process.executableURL = try context.tool(named: "SwiftJavaTool").url
process.arguments = arguments
do {
diff --git a/Plugins/JExtractSwiftPlugin/JExtractSwiftPlugin.swift b/Plugins/JExtractSwiftPlugin/JExtractSwiftPlugin.swift
index f4255ff5..a2cda352 100644
--- a/Plugins/JExtractSwiftPlugin/JExtractSwiftPlugin.swift
+++ b/Plugins/JExtractSwiftPlugin/JExtractSwiftPlugin.swift
@@ -22,7 +22,7 @@ struct JExtractSwiftBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin {
var verbose: Bool = getEnvironmentBool("SWIFT_JAVA_VERBOSE")
func createBuildCommands(context: PluginContext, target: Target) throws -> [Command] {
- let toolURL = try context.tool(named: "JExtractSwiftTool").url
+ let toolURL = try context.tool(named: "SwiftJavaTool").url
guard let sourceModule = target.sourceModule else { return [] }
@@ -42,7 +42,7 @@ struct JExtractSwiftBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin {
let sourceDir = target.directory.string
let configuration = try readConfiguration(sourceDir: "\(sourceDir)")
- guard let javaPackage = configuration.javaPackage else {
+ guard let javaPackage = configuration?.javaPackage else {
// throw SwiftJavaPluginError.missingConfiguration(sourceDir: "\(sourceDir)", key: "javaPackage")
log("Skipping jextract step, no 'javaPackage' configuration in \(getSwiftJavaConfigPath(target: target) ?? "")")
return []
@@ -50,20 +50,23 @@ struct JExtractSwiftBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin {
// We use the the usual maven-style structure of "src/[generated|main|test]/java/..."
// that is common in JVM ecosystem
- let outputDirectoryJava = context.outputDirectoryJava
- let outputDirectorySwift = context.outputDirectorySwift
+ let outputJavaDirectory = context.outputJavaDirectory
+ let outputSwiftDirectory = context.outputSwiftDirectory
var arguments: [String] = [
- "--swift-module", sourceModule.name,
- "--package-name", javaPackage,
- "--output-directory-java", outputDirectoryJava.path(percentEncoded: false),
- "--output-directory-swift", outputDirectorySwift.path(percentEncoded: false),
+ "--input-swift", sourceDir,
+ "--module-name", sourceModule.name,
+ "--output-java", outputJavaDirectory.path(percentEncoded: false),
+ "--output-swift", outputSwiftDirectory.path(percentEncoded: false),
// TODO: "--build-cache-directory", ...
// Since plugins cannot depend on libraries we cannot detect what the output files will be,
// as it depends on the contents of the input files. Therefore we have to implement this as a prebuild plugin.
// We'll have to make up some caching inside the tool so we don't re-parse files which have not changed etc.
]
- arguments.append(sourceDir)
+ // arguments.append(sourceDir)
+ if !javaPackage.isEmpty {
+ arguments.append(contentsOf: ["--java-package", javaPackage])
+ }
return [
.prebuildCommand(
@@ -72,7 +75,7 @@ struct JExtractSwiftBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin {
arguments: arguments,
// inputFiles: [ configFile ] + swiftFiles,
// outputFiles: outputJavaFiles
- outputFilesDirectory: outputDirectorySwift
+ outputFilesDirectory: outputSwiftDirectory
)
]
}
diff --git a/Plugins/PluginsShared/PluginUtils.swift b/Plugins/PluginsShared/PluginUtils.swift
index 6932253a..691d3375 100644
--- a/Plugins/PluginsShared/PluginUtils.swift
+++ b/Plugins/PluginsShared/PluginUtils.swift
@@ -60,14 +60,14 @@ func getEnvironmentBool(_ name: String) -> Bool {
}
extension PluginContext {
- var outputDirectoryJava: URL {
+ var outputJavaDirectory: URL {
self.pluginWorkDirectoryURL
.appending(path: "src")
.appending(path: "generated")
.appending(path: "java")
}
- var outputDirectorySwift: URL {
+ var outputSwiftDirectory: URL {
self.pluginWorkDirectoryURL
.appending(path: "Sources")
}
diff --git a/Plugins/Java2SwiftPlugin/Java2SwiftPlugin.swift b/Plugins/SwiftJavaPlugin/SwiftJavaPlugin.swift
similarity index 96%
rename from Plugins/Java2SwiftPlugin/Java2SwiftPlugin.swift
rename to Plugins/SwiftJavaPlugin/SwiftJavaPlugin.swift
index 88507f2e..77d7058d 100644
--- a/Plugins/Java2SwiftPlugin/Java2SwiftPlugin.swift
+++ b/Plugins/SwiftJavaPlugin/SwiftJavaPlugin.swift
@@ -18,7 +18,7 @@ import PackagePlugin
fileprivate let SwiftJavaConfigFileName = "swift-java.config"
@main
-struct Java2SwiftBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin {
+struct SwiftJavaBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin {
var pluginName: String = "swift-java"
var verbose: Bool = getEnvironmentBool("SWIFT_JAVA_VERBOSE")
@@ -27,7 +27,7 @@ struct Java2SwiftBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin {
log("Create build commands for target '\(target.name)'")
guard let sourceModule = target.sourceModule else { return [] }
- let executable = try context.tool(named: "Java2Swift").url
+ let executable = try context.tool(named: "SwiftJavaTool").url
var commands: [Command] = []
// Note: Target doesn't have a directoryURL counterpart to directory,
@@ -38,7 +38,7 @@ struct Java2SwiftBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin {
// which we are generating Swift wrappers for Java classes.
let configFile = URL(filePath: sourceDir)
.appending(path: SwiftJavaConfigFileName)
- let config = try readConfiguration(sourceDir: sourceDir)
+ let config = try readConfiguration(sourceDir: sourceDir) ?? Configuration()
log("Config on path: \(configFile.path(percentEncoded: false))")
log("Config was: \(config)")
@@ -199,7 +199,7 @@ struct Java2SwiftBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin {
}
}
-extension Java2SwiftBuildToolPlugin {
+extension SwiftJavaBuildToolPlugin {
func argumentsModuleName(sourceModule: Target) -> [String] {
return [
"--module-name", sourceModule.name
diff --git a/Plugins/Java2SwiftPlugin/_PluginsShared b/Plugins/SwiftJavaPlugin/_PluginsShared
similarity index 100%
rename from Plugins/Java2SwiftPlugin/_PluginsShared
rename to Plugins/SwiftJavaPlugin/_PluginsShared
diff --git a/Samples/JavaDependencySampleApp/Package.swift b/Samples/JavaDependencySampleApp/Package.swift
index 2b5ae361..b39e7b81 100644
--- a/Samples/JavaDependencySampleApp/Package.swift
+++ b/Samples/JavaDependencySampleApp/Package.swift
@@ -76,7 +76,7 @@ let package = Package(
.swiftLanguageMode(.v5),
],
plugins: [
- .plugin(name: "Java2SwiftPlugin", package: "swift-java"),
+ .plugin(name: "SwiftJavaPlugin", package: "swift-java"),
]
),
@@ -96,7 +96,7 @@ let package = Package(
],
plugins: [
// .plugin(name: "SwiftJavaBootstrapJavaPlugin", package: "swift-java"),
- .plugin(name: "Java2SwiftPlugin", package: "swift-java"),
+ .plugin(name: "SwiftJavaPlugin", package: "swift-java"),
]
),
diff --git a/Samples/JavaKitSampleApp/Package.swift b/Samples/JavaKitSampleApp/Package.swift
index e51867cc..0956290c 100644
--- a/Samples/JavaKitSampleApp/Package.swift
+++ b/Samples/JavaKitSampleApp/Package.swift
@@ -77,7 +77,7 @@ let package = Package(
plugins: [
.plugin(name: "JavaCompilerPlugin", package: "swift-java"),
.plugin(name: "JExtractSwiftPlugin", package: "swift-java"),
- .plugin(name: "Java2SwiftPlugin", package: "swift-java"),
+ .plugin(name: "SwiftJavaPlugin", package: "swift-java"),
]
),
]
diff --git a/Samples/JavaProbablyPrime/Package.swift b/Samples/JavaProbablyPrime/Package.swift
index e837bfdb..4cc887f8 100644
--- a/Samples/JavaProbablyPrime/Package.swift
+++ b/Samples/JavaProbablyPrime/Package.swift
@@ -34,7 +34,7 @@ let package = Package(
.swiftLanguageMode(.v5)
],
plugins: [
- .plugin(name: "Java2SwiftPlugin", package: "swift-java"),
+ .plugin(name: "SwiftJavaPlugin", package: "swift-java"),
]
),
]
diff --git a/Samples/JavaSieve/Package.swift b/Samples/JavaSieve/Package.swift
index 35dcd19c..cd65f82e 100644
--- a/Samples/JavaSieve/Package.swift
+++ b/Samples/JavaSieve/Package.swift
@@ -58,7 +58,7 @@ let package = Package(
.unsafeFlags(["-I\(javaIncludePath)", "-I\(javaPlatformIncludePath)"])
],
plugins: [
- .plugin(name: "Java2SwiftPlugin", package: "swift-java"),
+ .plugin(name: "SwiftJavaPlugin", package: "swift-java"),
]
),
@@ -75,7 +75,7 @@ let package = Package(
.unsafeFlags(["-I\(javaIncludePath)", "-I\(javaPlatformIncludePath)"])
],
plugins: [
- .plugin(name: "Java2SwiftPlugin", package: "swift-java"),
+ .plugin(name: "SwiftJavaPlugin", package: "swift-java"),
]
),
]
diff --git a/Sources/JExtractSwift/CDeclLowering/CRepresentation.swift b/Sources/JExtractSwiftLib/CDeclLowering/CRepresentation.swift
similarity index 100%
rename from Sources/JExtractSwift/CDeclLowering/CRepresentation.swift
rename to Sources/JExtractSwiftLib/CDeclLowering/CRepresentation.swift
diff --git a/Sources/JExtractSwift/CDeclLowering/Swift2JavaTranslator+FunctionLowering.swift b/Sources/JExtractSwiftLib/CDeclLowering/Swift2JavaTranslator+FunctionLowering.swift
similarity index 100%
rename from Sources/JExtractSwift/CDeclLowering/Swift2JavaTranslator+FunctionLowering.swift
rename to Sources/JExtractSwiftLib/CDeclLowering/Swift2JavaTranslator+FunctionLowering.swift
diff --git a/Sources/JExtractSwift/CTypes/CEnum.swift b/Sources/JExtractSwiftLib/CTypes/CEnum.swift
similarity index 100%
rename from Sources/JExtractSwift/CTypes/CEnum.swift
rename to Sources/JExtractSwiftLib/CTypes/CEnum.swift
diff --git a/Sources/JExtractSwift/CTypes/CFunction.swift b/Sources/JExtractSwiftLib/CTypes/CFunction.swift
similarity index 100%
rename from Sources/JExtractSwift/CTypes/CFunction.swift
rename to Sources/JExtractSwiftLib/CTypes/CFunction.swift
diff --git a/Sources/JExtractSwift/CTypes/CParameter.swift b/Sources/JExtractSwiftLib/CTypes/CParameter.swift
similarity index 100%
rename from Sources/JExtractSwift/CTypes/CParameter.swift
rename to Sources/JExtractSwiftLib/CTypes/CParameter.swift
diff --git a/Sources/JExtractSwift/CTypes/CStruct.swift b/Sources/JExtractSwiftLib/CTypes/CStruct.swift
similarity index 100%
rename from Sources/JExtractSwift/CTypes/CStruct.swift
rename to Sources/JExtractSwiftLib/CTypes/CStruct.swift
diff --git a/Sources/JExtractSwift/CTypes/CTag.swift b/Sources/JExtractSwiftLib/CTypes/CTag.swift
similarity index 100%
rename from Sources/JExtractSwift/CTypes/CTag.swift
rename to Sources/JExtractSwiftLib/CTypes/CTag.swift
diff --git a/Sources/JExtractSwift/CTypes/CType.swift b/Sources/JExtractSwiftLib/CTypes/CType.swift
similarity index 100%
rename from Sources/JExtractSwift/CTypes/CType.swift
rename to Sources/JExtractSwiftLib/CTypes/CType.swift
diff --git a/Sources/JExtractSwift/CTypes/CUnion.swift b/Sources/JExtractSwiftLib/CTypes/CUnion.swift
similarity index 100%
rename from Sources/JExtractSwift/CTypes/CUnion.swift
rename to Sources/JExtractSwiftLib/CTypes/CUnion.swift
diff --git a/Sources/JExtractSwift/CodePrinter.swift b/Sources/JExtractSwiftLib/CodePrinter.swift
similarity index 100%
rename from Sources/JExtractSwift/CodePrinter.swift
rename to Sources/JExtractSwiftLib/CodePrinter.swift
diff --git a/Sources/JExtractSwift/Convenience/Collection+Extensions.swift b/Sources/JExtractSwiftLib/Convenience/Collection+Extensions.swift
similarity index 100%
rename from Sources/JExtractSwift/Convenience/Collection+Extensions.swift
rename to Sources/JExtractSwiftLib/Convenience/Collection+Extensions.swift
diff --git a/Sources/JExtractSwift/Convenience/String+Extensions.swift b/Sources/JExtractSwiftLib/Convenience/String+Extensions.swift
similarity index 100%
rename from Sources/JExtractSwift/Convenience/String+Extensions.swift
rename to Sources/JExtractSwiftLib/Convenience/String+Extensions.swift
diff --git a/Sources/JExtractSwift/Convenience/SwiftSyntax+Extensions.swift b/Sources/JExtractSwiftLib/Convenience/SwiftSyntax+Extensions.swift
similarity index 100%
rename from Sources/JExtractSwift/Convenience/SwiftSyntax+Extensions.swift
rename to Sources/JExtractSwiftLib/Convenience/SwiftSyntax+Extensions.swift
diff --git a/Sources/JExtractSwift/ConversionStep.swift b/Sources/JExtractSwiftLib/ConversionStep.swift
similarity index 100%
rename from Sources/JExtractSwift/ConversionStep.swift
rename to Sources/JExtractSwiftLib/ConversionStep.swift
diff --git a/Sources/JExtractSwift/ImportedDecls.swift b/Sources/JExtractSwiftLib/ImportedDecls.swift
similarity index 100%
rename from Sources/JExtractSwift/ImportedDecls.swift
rename to Sources/JExtractSwiftLib/ImportedDecls.swift
diff --git a/Sources/JExtractSwift/JavaConstants/ForeignValueLayouts.swift b/Sources/JExtractSwiftLib/JavaConstants/ForeignValueLayouts.swift
similarity index 100%
rename from Sources/JExtractSwift/JavaConstants/ForeignValueLayouts.swift
rename to Sources/JExtractSwiftLib/JavaConstants/ForeignValueLayouts.swift
diff --git a/Sources/JExtractSwift/JavaConstants/JavaTypes.swift b/Sources/JExtractSwiftLib/JavaConstants/JavaTypes.swift
similarity index 100%
rename from Sources/JExtractSwift/JavaConstants/JavaTypes.swift
rename to Sources/JExtractSwiftLib/JavaConstants/JavaTypes.swift
diff --git a/Sources/JExtractSwift/Logger.swift b/Sources/JExtractSwiftLib/Logger.swift
similarity index 72%
rename from Sources/JExtractSwift/Logger.swift
rename to Sources/JExtractSwiftLib/Logger.swift
index 9aceb201..180ffb54 100644
--- a/Sources/JExtractSwift/Logger.swift
+++ b/Sources/JExtractSwiftLib/Logger.swift
@@ -14,6 +14,8 @@
import Foundation
import SwiftSyntax
+import ArgumentParser
+import JavaKitConfigurationShared
// Placeholder for some better logger, we could depend on swift-log
public struct Logger {
@@ -95,47 +97,17 @@ public struct Logger {
}
extension Logger {
- public enum Level: String, Hashable {
- case trace = "trace"
- case debug = "debug"
- case info = "info"
- case notice = "notice"
- case warning = "warning"
- case error = "error"
- case critical = "critical"
- }
+ public typealias Level = JavaKitConfigurationShared.LogLevel
}
-extension Logger.Level {
- public init(from decoder: any Decoder) throws {
- var container = try decoder.unkeyedContainer()
- let string = try container.decode(String.self)
- switch string {
- case "trace": self = .trace
- case "debug": self = .debug
- case "info": self = .info
- case "notice": self = .notice
- case "warning": self = .warning
- case "error": self = .error
- case "critical": self = .critical
- default: fatalError("Unknown value for \(Logger.Level.self): \(string)")
- }
+extension Logger.Level: ExpressibleByArgument {
+ public var defaultValueDescription: String {
+ "log level"
}
+ public private(set) static var allValueStrings: [String] =
+ ["trace", "debug", "info", "notice", "warning", "error", "critical"]
- public func encode(to encoder: any Encoder) throws {
- var container = encoder.singleValueContainer()
- let text =
- switch self {
- case .trace: "trace"
- case .debug: "debug"
- case .info: "info"
- case .notice: "notice"
- case .warning: "warning"
- case .error: "error"
- case .critical: "critical"
- }
- try container.encode(text)
- }
+ public private(set) static var defaultCompletionKind: CompletionKind = .default
}
extension Logger.Level {
diff --git a/Sources/JExtractSwift/Swift2Java.swift b/Sources/JExtractSwiftLib/Swift2Java.swift
similarity index 56%
rename from Sources/JExtractSwift/Swift2Java.swift
rename to Sources/JExtractSwiftLib/Swift2Java.swift
index 6525fc0a..79cb0fec 100644
--- a/Sources/JExtractSwift/Swift2Java.swift
+++ b/Sources/JExtractSwiftLib/Swift2Java.swift
@@ -12,57 +12,49 @@
//
//===----------------------------------------------------------------------===//
-import ArgumentParser
import Foundation
import SwiftSyntax
import SwiftSyntaxBuilder
import JavaKitShared
+import JavaKitConfigurationShared // TODO: this should become SwiftJavaConfigurationShared
-/// Command-line utility, similar to `jextract` to export Swift types to Java.
-public struct SwiftToJava: ParsableCommand {
- public init() {}
+public struct SwiftToJava {
+ let config: Configuration
- public static var _commandName: String {
- "jextract-swift"
+ public init(config: Configuration) {
+ self.config = config
}
- @Option(help: "The package the generated Java code should be emitted into.")
- var packageName: String
-
- @Option(
- name: .shortAndLong,
- help: "The directory in which to output the generated Swift files and manifest.")
- var outputDirectoryJava: String = ".build/jextract-swift/generated"
-
- @Option(help: "Swift output directory")
- var outputDirectorySwift: String
-
- @Option(
- name: .long,
- help: "Name of the Swift module to import (and the swift interface files belong to)")
- var swiftModule: String
-
- @Option(name: .shortAndLong, help: "Configure the level of lots that should be printed")
- var logLevel: Logger.Level = .info
-
- @Argument(help: "The Swift files or directories to recursively export to Java.")
- var input: [String]
-
public func run() throws {
- let inputPaths = self.input.dropFirst().map { URL(string: $0)! }
+ guard let swiftModule = config.swiftModule else {
+ fatalError("Missing '--swift-module' name.")
+ }
let translator = Swift2JavaTranslator(
- javaPackage: packageName,
+ javaPackage: config.javaPackage ?? "", // no package is ok, we'd generate all into top level
swiftModuleName: swiftModule
)
- translator.log.logLevel = logLevel
+ translator.log.logLevel = config.logLevel ?? .info
+
+ if config.javaPackage == nil || config.javaPackage!.isEmpty {
+ translator.log.warning("Configured java package is '', consider specifying concrete package for generated sources.")
+ }
+
+ print("===== CONFIG ==== \(config)")
+
+ guard let inputSwift = config.inputSwiftDirectory else {
+ fatalError("Missing '--swift-input' directory!")
+ }
+
+ let inputPaths = inputSwift.split(separator: ",").map { URL(string: String($0))! }
+ translator.log.info("Input paths = \(inputPaths)")
var allFiles: [URL] = []
let fileManager = FileManager.default
let log = translator.log
-
+
for path in inputPaths {
- log.debug("Input path: \(path)")
+ log.info("Input path: \(path)")
if isDirectory(url: path) {
if let enumerator = fileManager.enumerator(at: path, includingPropertiesForKeys: nil) {
for case let fileURL as URL in enumerator {
@@ -88,10 +80,21 @@ public struct SwiftToJava: ParsableCommand {
translator.add(filePath: file.path, text: text)
}
+ guard let outputSwiftDirectory = config.outputSwiftDirectory else {
+ fatalError("Missing --output-swift directory!")
+ }
+ guard let outputJavaDirectory = config.outputJavaDirectory else {
+ fatalError("Missing --output-java directory!")
+ }
+
try translator.analyze()
- try translator.writeSwiftThunkSources(outputDirectory: outputDirectorySwift)
- try translator.writeExportedJavaSources(outputDirectory: outputDirectoryJava)
- print("[swift-java] Generated Java sources (\(packageName)) in: \(outputDirectoryJava)/")
+
+ try translator.writeSwiftThunkSources(outputDirectory: outputSwiftDirectory)
+ print("[swift-java] Generated Swift sources (module: '\(config.swiftModule ?? "")') in: \(outputSwiftDirectory)/")
+
+ try translator.writeExportedJavaSources(outputDirectory: outputJavaDirectory)
+ print("[swift-java] Generated Java sources (package: '\(config.javaPackage ?? "")') in: \(outputJavaDirectory)/")
+
print("[swift-java] Imported Swift module '\(swiftModule)': " + "done.".green)
}
@@ -102,16 +105,6 @@ public struct SwiftToJava: ParsableCommand {
}
-extension Logger.Level: ExpressibleByArgument {
- public var defaultValueDescription: String {
- "log level"
- }
- public private(set) static var allValueStrings: [String] =
- ["trace", "debug", "info", "notice", "warning", "error", "critical"]
-
- public private(set) static var defaultCompletionKind: CompletionKind = .default
-}
-
func isDirectory(url: URL) -> Bool {
var isDirectory: ObjCBool = false
_ = FileManager.default.fileExists(atPath: url.path, isDirectory: &isDirectory)
diff --git a/Sources/JExtractSwift/Swift2JavaTranslator+JavaBindingsPrinting.swift b/Sources/JExtractSwiftLib/Swift2JavaTranslator+JavaBindingsPrinting.swift
similarity index 100%
rename from Sources/JExtractSwift/Swift2JavaTranslator+JavaBindingsPrinting.swift
rename to Sources/JExtractSwiftLib/Swift2JavaTranslator+JavaBindingsPrinting.swift
diff --git a/Sources/JExtractSwift/Swift2JavaTranslator+JavaTranslation.swift b/Sources/JExtractSwiftLib/Swift2JavaTranslator+JavaTranslation.swift
similarity index 100%
rename from Sources/JExtractSwift/Swift2JavaTranslator+JavaTranslation.swift
rename to Sources/JExtractSwiftLib/Swift2JavaTranslator+JavaTranslation.swift
diff --git a/Sources/JExtractSwift/Swift2JavaTranslator+Printing.swift b/Sources/JExtractSwiftLib/Swift2JavaTranslator+Printing.swift
similarity index 100%
rename from Sources/JExtractSwift/Swift2JavaTranslator+Printing.swift
rename to Sources/JExtractSwiftLib/Swift2JavaTranslator+Printing.swift
diff --git a/Sources/JExtractSwift/Swift2JavaTranslator+SwiftThunkPrinting.swift b/Sources/JExtractSwiftLib/Swift2JavaTranslator+SwiftThunkPrinting.swift
similarity index 100%
rename from Sources/JExtractSwift/Swift2JavaTranslator+SwiftThunkPrinting.swift
rename to Sources/JExtractSwiftLib/Swift2JavaTranslator+SwiftThunkPrinting.swift
diff --git a/Sources/JExtractSwift/Swift2JavaTranslator.swift b/Sources/JExtractSwiftLib/Swift2JavaTranslator.swift
similarity index 100%
rename from Sources/JExtractSwift/Swift2JavaTranslator.swift
rename to Sources/JExtractSwiftLib/Swift2JavaTranslator.swift
diff --git a/Sources/JExtractSwift/Swift2JavaVisitor.swift b/Sources/JExtractSwiftLib/Swift2JavaVisitor.swift
similarity index 100%
rename from Sources/JExtractSwift/Swift2JavaVisitor.swift
rename to Sources/JExtractSwiftLib/Swift2JavaVisitor.swift
diff --git a/Sources/JExtractSwift/SwiftKit+Printing.swift b/Sources/JExtractSwiftLib/SwiftKit+Printing.swift
similarity index 100%
rename from Sources/JExtractSwift/SwiftKit+Printing.swift
rename to Sources/JExtractSwiftLib/SwiftKit+Printing.swift
diff --git a/Sources/JExtractSwift/SwiftTypes/SwiftFunctionSignature.swift b/Sources/JExtractSwiftLib/SwiftTypes/SwiftFunctionSignature.swift
similarity index 100%
rename from Sources/JExtractSwift/SwiftTypes/SwiftFunctionSignature.swift
rename to Sources/JExtractSwiftLib/SwiftTypes/SwiftFunctionSignature.swift
diff --git a/Sources/JExtractSwift/SwiftTypes/SwiftFunctionType.swift b/Sources/JExtractSwiftLib/SwiftTypes/SwiftFunctionType.swift
similarity index 100%
rename from Sources/JExtractSwift/SwiftTypes/SwiftFunctionType.swift
rename to Sources/JExtractSwiftLib/SwiftTypes/SwiftFunctionType.swift
diff --git a/Sources/JExtractSwift/SwiftTypes/SwiftModuleSymbolTable.swift b/Sources/JExtractSwiftLib/SwiftTypes/SwiftModuleSymbolTable.swift
similarity index 100%
rename from Sources/JExtractSwift/SwiftTypes/SwiftModuleSymbolTable.swift
rename to Sources/JExtractSwiftLib/SwiftTypes/SwiftModuleSymbolTable.swift
diff --git a/Sources/JExtractSwift/SwiftTypes/SwiftNominalTypeDeclaration.swift b/Sources/JExtractSwiftLib/SwiftTypes/SwiftNominalTypeDeclaration.swift
similarity index 100%
rename from Sources/JExtractSwift/SwiftTypes/SwiftNominalTypeDeclaration.swift
rename to Sources/JExtractSwiftLib/SwiftTypes/SwiftNominalTypeDeclaration.swift
diff --git a/Sources/JExtractSwift/SwiftTypes/SwiftParameter.swift b/Sources/JExtractSwiftLib/SwiftTypes/SwiftParameter.swift
similarity index 100%
rename from Sources/JExtractSwift/SwiftTypes/SwiftParameter.swift
rename to Sources/JExtractSwiftLib/SwiftTypes/SwiftParameter.swift
diff --git a/Sources/JExtractSwift/SwiftTypes/SwiftParsedModuleSymbolTable.swift b/Sources/JExtractSwiftLib/SwiftTypes/SwiftParsedModuleSymbolTable.swift
similarity index 100%
rename from Sources/JExtractSwift/SwiftTypes/SwiftParsedModuleSymbolTable.swift
rename to Sources/JExtractSwiftLib/SwiftTypes/SwiftParsedModuleSymbolTable.swift
diff --git a/Sources/JExtractSwift/SwiftTypes/SwiftResult.swift b/Sources/JExtractSwiftLib/SwiftTypes/SwiftResult.swift
similarity index 100%
rename from Sources/JExtractSwift/SwiftTypes/SwiftResult.swift
rename to Sources/JExtractSwiftLib/SwiftTypes/SwiftResult.swift
diff --git a/Sources/JExtractSwift/SwiftTypes/SwiftStandardLibraryTypes.swift b/Sources/JExtractSwiftLib/SwiftTypes/SwiftStandardLibraryTypes.swift
similarity index 100%
rename from Sources/JExtractSwift/SwiftTypes/SwiftStandardLibraryTypes.swift
rename to Sources/JExtractSwiftLib/SwiftTypes/SwiftStandardLibraryTypes.swift
diff --git a/Sources/JExtractSwift/SwiftTypes/SwiftSymbolTable.swift b/Sources/JExtractSwiftLib/SwiftTypes/SwiftSymbolTable.swift
similarity index 100%
rename from Sources/JExtractSwift/SwiftTypes/SwiftSymbolTable.swift
rename to Sources/JExtractSwiftLib/SwiftTypes/SwiftSymbolTable.swift
diff --git a/Sources/JExtractSwift/SwiftTypes/SwiftType.swift b/Sources/JExtractSwiftLib/SwiftTypes/SwiftType.swift
similarity index 100%
rename from Sources/JExtractSwift/SwiftTypes/SwiftType.swift
rename to Sources/JExtractSwiftLib/SwiftTypes/SwiftType.swift
diff --git a/Sources/JExtractSwift/ThunkNameRegistry.swift b/Sources/JExtractSwiftLib/ThunkNameRegistry.swift
similarity index 100%
rename from Sources/JExtractSwift/ThunkNameRegistry.swift
rename to Sources/JExtractSwiftLib/ThunkNameRegistry.swift
diff --git a/Sources/JExtractSwiftTool/JExtractSwiftTool.swift b/Sources/JExtractSwiftTool/JExtractSwiftTool.swift
deleted file mode 100644
index f219cc8c..00000000
--- a/Sources/JExtractSwiftTool/JExtractSwiftTool.swift
+++ /dev/null
@@ -1,23 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// This source file is part of the Swift.org open source project
-//
-// Copyright (c) 2024 Apple Inc. and the Swift.org project authors
-// Licensed under Apache License v2.0
-//
-// See LICENSE.txt for license information
-// See CONTRIBUTORS.txt for the list of Swift.org project authors
-//
-// SPDX-License-Identifier: Apache-2.0
-//
-//===----------------------------------------------------------------------===//
-
-import JExtractSwift
-
-@main
-struct JExtractSwift {
- static func main() throws {
- let command = SwiftToJava.parseOrExit(CommandLine.arguments)
- try command.run()
- }
-}
diff --git a/Sources/JavaKitConfigurationShared/Configuration.swift b/Sources/JavaKitConfigurationShared/Configuration.swift
index 13c7fd9b..1c4fad56 100644
--- a/Sources/JavaKitConfigurationShared/Configuration.swift
+++ b/Sources/JavaKitConfigurationShared/Configuration.swift
@@ -21,12 +21,23 @@ import Foundation
public typealias JavaVersion = Int
-/// Configuration for the SwiftJava plugins, provided on a per-target basis.
+/// Configuration for the SwiftJava tools and plugins, provided on a per-target basis.
public struct Configuration: Codable {
- // ==== swift 2 java ---------------------------------------------------------
+
+ public var logLevel: LogLevel?
+
+ // ==== swift 2 java / jextract swift ---------------------------------------
public var javaPackage: String?
+ public var swiftModule: String?
+
+ public var inputSwiftDirectory: String?
+
+ public var outputSwiftDirectory: String?
+
+ public var outputJavaDirectory: String?
+
// ==== java 2 swift ---------------------------------------------------------
/// The Java class path that should be passed along to the Java2Swift tool.
@@ -102,7 +113,7 @@ public struct JavaDependencyDescriptor: Hashable, Codable {
}
}
-public func readConfiguration(sourceDir: String, file: String = #fileID, line: UInt = #line) throws -> Configuration {
+public func readConfiguration(sourceDir: String, file: String = #fileID, line: UInt = #line) throws -> Configuration? {
// Workaround since filePath is macOS 13
let sourcePath =
if sourceDir.hasPrefix("file://") { sourceDir } else { "file://" + sourceDir }
@@ -111,12 +122,15 @@ public func readConfiguration(sourceDir: String, file: String = #fileID, line: U
return try readConfiguration(configPath: configPath, file: file, line: line)
}
-public func readConfiguration(configPath: URL, file: String = #fileID, line: UInt = #line) throws -> Configuration {
+public func readConfiguration(configPath: URL, file: String = #fileID, line: UInt = #line) throws -> Configuration? {
+ guard let configData = try? Data(contentsOf: configPath) else {
+ return nil
+ }
+
do {
- let configData = try Data(contentsOf: configPath)
return try JSONDecoder().decode(Configuration.self, from: configData)
} catch {
- throw ConfigurationError(message: "Failed to parse SwiftJava configuration at '\(configPath.absoluteURL)'!", error: error,
+ throw ConfigurationError(message: "Failed to parse SwiftJava configuration at '\(configPath.absoluteURL)'! \(#fileID):\(#line)", error: error,
file: file, line: line)
}
}
@@ -200,3 +214,45 @@ public struct ConfigurationError: Error {
self.line = line
}
}
+
+public enum LogLevel: String, Codable, Hashable {
+ case trace = "trace"
+ case debug = "debug"
+ case info = "info"
+ case notice = "notice"
+ case warning = "warning"
+ case error = "error"
+ case critical = "critical"
+}
+
+extension LogLevel {
+ public init(from decoder: any Decoder) throws {
+ var container = try decoder.unkeyedContainer()
+ let string = try container.decode(String.self)
+ switch string {
+ case "trace": self = .trace
+ case "debug": self = .debug
+ case "info": self = .info
+ case "notice": self = .notice
+ case "warning": self = .warning
+ case "error": self = .error
+ case "critical": self = .critical
+ default: fatalError("Unknown value for \(LogLevel.self): \(string)")
+ }
+ }
+
+ public func encode(to encoder: any Encoder) throws {
+ var container = encoder.singleValueContainer()
+ let text =
+ switch self {
+ case .trace: "trace"
+ case .debug: "debug"
+ case .info: "info"
+ case .notice: "notice"
+ case .warning: "warning"
+ case .error: "error"
+ case .critical: "critical"
+ }
+ try container.encode(text)
+ }
+}
\ No newline at end of file
diff --git a/Sources/Java2SwiftLib/JavaClassTranslator.swift b/Sources/SwiftJavaLib/JavaClassTranslator.swift
similarity index 100%
rename from Sources/Java2SwiftLib/JavaClassTranslator.swift
rename to Sources/SwiftJavaLib/JavaClassTranslator.swift
diff --git a/Sources/Java2SwiftLib/JavaTranslator+Configuration.swift b/Sources/SwiftJavaLib/JavaTranslator+Configuration.swift
similarity index 100%
rename from Sources/Java2SwiftLib/JavaTranslator+Configuration.swift
rename to Sources/SwiftJavaLib/JavaTranslator+Configuration.swift
diff --git a/Sources/Java2SwiftLib/JavaTranslator+Validation.swift b/Sources/SwiftJavaLib/JavaTranslator+Validation.swift
similarity index 100%
rename from Sources/Java2SwiftLib/JavaTranslator+Validation.swift
rename to Sources/SwiftJavaLib/JavaTranslator+Validation.swift
diff --git a/Sources/Java2SwiftLib/JavaTranslator.swift b/Sources/SwiftJavaLib/JavaTranslator.swift
similarity index 100%
rename from Sources/Java2SwiftLib/JavaTranslator.swift
rename to Sources/SwiftJavaLib/JavaTranslator.swift
diff --git a/Sources/Java2SwiftLib/MethodVariance.swift b/Sources/SwiftJavaLib/MethodVariance.swift
similarity index 100%
rename from Sources/Java2SwiftLib/MethodVariance.swift
rename to Sources/SwiftJavaLib/MethodVariance.swift
diff --git a/Sources/Java2SwiftLib/OptionalKind.swift b/Sources/SwiftJavaLib/OptionalKind.swift
similarity index 100%
rename from Sources/Java2SwiftLib/OptionalKind.swift
rename to Sources/SwiftJavaLib/OptionalKind.swift
diff --git a/Sources/Java2SwiftLib/StringExtras.swift b/Sources/SwiftJavaLib/StringExtras.swift
similarity index 100%
rename from Sources/Java2SwiftLib/StringExtras.swift
rename to Sources/SwiftJavaLib/StringExtras.swift
diff --git a/Sources/Java2SwiftLib/TranslationError.swift b/Sources/SwiftJavaLib/TranslationError.swift
similarity index 100%
rename from Sources/Java2SwiftLib/TranslationError.swift
rename to Sources/SwiftJavaLib/TranslationError.swift
diff --git a/Sources/Java2Swift/String+Extensions.swift b/Sources/SwiftJavaTool/String+Extensions.swift
similarity index 97%
rename from Sources/Java2Swift/String+Extensions.swift
rename to Sources/SwiftJavaTool/String+Extensions.swift
index 26a20241..f2bb9e72 100644
--- a/Sources/Java2Swift/String+Extensions.swift
+++ b/Sources/SwiftJavaTool/String+Extensions.swift
@@ -14,10 +14,10 @@
import Foundation
import ArgumentParser
-import Java2SwiftLib
+import SwiftJavaLib
import JavaKit
import JavaKitJar
-import Java2SwiftLib
+import SwiftJavaLib
import JavaKitConfigurationShared
extension String {
diff --git a/Sources/Java2Swift/JavaToSwift+EmitConfiguration.swift b/Sources/SwiftJavaTool/SwiftJava+EmitConfiguration.swift
similarity index 98%
rename from Sources/Java2Swift/JavaToSwift+EmitConfiguration.swift
rename to Sources/SwiftJavaTool/SwiftJava+EmitConfiguration.swift
index 6754d381..e029d2db 100644
--- a/Sources/Java2Swift/JavaToSwift+EmitConfiguration.swift
+++ b/Sources/SwiftJavaTool/SwiftJava+EmitConfiguration.swift
@@ -14,13 +14,12 @@
import Foundation
import ArgumentParser
-import Java2SwiftLib
+import SwiftJavaLib
import JavaKit
import JavaKitJar
-import Java2SwiftLib
import JavaKitConfigurationShared
-extension JavaToSwift {
+extension SwiftJava {
// TODO: make this perhaps "emit type mappings"
mutating func emitConfiguration(
diff --git a/Sources/Java2Swift/JavaToSwift+FetchDependencies.swift b/Sources/SwiftJavaTool/SwiftJava+FetchDependencies.swift
similarity index 99%
rename from Sources/Java2Swift/JavaToSwift+FetchDependencies.swift
rename to Sources/SwiftJavaTool/SwiftJava+FetchDependencies.swift
index 2a9694c0..47570b19 100644
--- a/Sources/Java2Swift/JavaToSwift+FetchDependencies.swift
+++ b/Sources/SwiftJavaTool/SwiftJava+FetchDependencies.swift
@@ -13,16 +13,16 @@
//===----------------------------------------------------------------------===//
import Foundation
-import Java2SwiftLib
+import SwiftJavaLib
import JavaKit
import Foundation
import JavaKitJar
-import Java2SwiftLib
+import SwiftJavaLib
import JavaKitConfigurationShared
import JavaKitShared
import _Subprocess
-extension JavaToSwift {
+extension SwiftJava {
var SwiftJavaClasspathPrefix: String { "SWIFT_JAVA_CLASSPATH:" }
diff --git a/Sources/Java2Swift/JavaToSwift+GenerateWrappers.swift b/Sources/SwiftJavaTool/SwiftJava+GenerateWrappers.swift
similarity index 98%
rename from Sources/Java2Swift/JavaToSwift+GenerateWrappers.swift
rename to Sources/SwiftJavaTool/SwiftJava+GenerateWrappers.swift
index 67aa3f9c..a57644de 100644
--- a/Sources/Java2Swift/JavaToSwift+GenerateWrappers.swift
+++ b/Sources/SwiftJavaTool/SwiftJava+GenerateWrappers.swift
@@ -14,13 +14,13 @@
import Foundation
import ArgumentParser
-import Java2SwiftLib
+import SwiftJavaLib
import JavaKit
import JavaKitJar
-import Java2SwiftLib
+import SwiftJavaLib
import JavaKitConfigurationShared
-extension JavaToSwift {
+extension SwiftJava {
mutating func generateWrappers(
config: Configuration,
classpath: String,
diff --git a/Sources/SwiftJavaTool/SwiftJava+JExtract.swift b/Sources/SwiftJavaTool/SwiftJava+JExtract.swift
new file mode 100644
index 00000000..79c96d3e
--- /dev/null
+++ b/Sources/SwiftJavaTool/SwiftJava+JExtract.swift
@@ -0,0 +1,40 @@
+//===----------------------------------------------------------------------===//
+//
+// This source file is part of the Swift.org open source project
+//
+// Copyright (c) 2024 Apple Inc. and the Swift.org project authors
+// Licensed under Apache License v2.0
+//
+// See LICENSE.txt for license information
+// See CONTRIBUTORS.txt for the list of Swift.org project authors
+//
+// SPDX-License-Identifier: Apache-2.0
+//
+//===----------------------------------------------------------------------===//
+
+import Foundation
+import ArgumentParser
+import SwiftJavaLib
+import JavaKit
+import JavaKitJar
+import SwiftJavaLib
+import JExtractSwiftLib
+import JavaKitConfigurationShared
+
+/// Extract Java bindings from Swift sources or interface files.
+///
+/// Example usage:
+/// ```
+/// > swift-java --input-swift Sources/SwiftyBusiness \
+/// --output-swift .build/.../outputs/SwiftyBusiness \
+/// --output-Java .build/.../outputs/Java
+/// ```
+extension SwiftJava {
+
+ mutating func jextractSwift(
+ config: Configuration
+ ) throws {
+ try SwiftToJava(config: config).run()
+ }
+
+}
diff --git a/Sources/Java2Swift/JavaToSwift.swift b/Sources/SwiftJavaTool/SwiftJava.swift
similarity index 75%
rename from Sources/Java2Swift/JavaToSwift.swift
rename to Sources/SwiftJavaTool/SwiftJava.swift
index 536b3fd1..badd5455 100644
--- a/Sources/Java2Swift/JavaToSwift.swift
+++ b/Sources/SwiftJavaTool/SwiftJava.swift
@@ -14,7 +14,8 @@
import ArgumentParser
import Foundation
-import Java2SwiftLib
+import SwiftJavaLib
+import JExtractSwiftLib
import JavaKit
import JavaKitJar
import JavaKitNetwork
@@ -26,11 +27,11 @@ import JavaKitShared
/// Command-line utility to drive the export of Java classes into Swift types.
@main
-struct JavaToSwift: AsyncParsableCommand {
- static var _commandName: String { "Java2Swift" }
+struct SwiftJava: AsyncParsableCommand {
+ static var _commandName: String { "swift-java" }
@Option(help: "The name of the Swift module into which the resulting Swift types will be generated.")
- var moduleName: String?
+ var moduleName: String? // TODO: rename to --swift-module?
@Option(
help:
@@ -59,13 +60,28 @@ struct JavaToSwift: AsyncParsableCommand {
)
var swiftNativeImplementation: [String] = []
- @Option(name: .shortAndLong, help: "The directory in which to output the generated Swift files or the Java2Swift configuration file.")
+ @Option(help: "Directory containing Swift files which should be extracted into Java bindings. Also known as 'jextract' mode. Must be paired with --output-java and --output-swift.")
+ var inputSwift: String? = nil
+
+ @Option(help: "The directory where generated Swift files should be written. Generally used with jextract mode.")
+ var outputSwift: String? = nil
+
+ @Option(help: "The directory where generated Java files should be written. Generally used with jextract mode.")
+ var outputJava: String? = nil
+
+ @Option(help: "The Java package the generated Java code should be emitted into.")
+ var javaPackage: String? = nil
+
+ // TODO: clarify this vs outputSwift (history: outputSwift is jextract, and this was java2swift)
+ @Option(name: .shortAndLong, help: "The directory in which to output the generated Swift files or the SwiftJava configuration file.")
var outputDirectory: String? = nil
-
@Option(name: .shortAndLong, help: "Directory where to write cached values (e.g. swift-java.classpath files)")
var cacheDirectory: String? = nil
-
+
+ @Option(name: .shortAndLong, help: "Configure the level of logs that should be printed")
+ var logLevel: Logger.Level = .info
+
var effectiveCacheDirectory: String? {
if let cacheDirectory {
return cacheDirectory
@@ -87,10 +103,9 @@ struct JavaToSwift: AsyncParsableCommand {
var javaPackageFilter: String? = nil
@Argument(
- help:
- "The input file, which is either a Java2Swift configuration file or (if '-jar' was specified) a Jar file."
+ help: "The input file, which is either a Java2Swift configuration file or (if '-jar' was specified) a Jar file."
)
- var input: String
+ var input: String?
/// Whether we have ensured that the output directory exists.
var createdOutputDirectory: Bool = false
@@ -101,6 +116,7 @@ struct JavaToSwift: AsyncParsableCommand {
return nil
}
+ print("[debug][swift-java] Module base directory based on outputDirectory!")
return URL(fileURLWithPath: outputDirectory)
}
@@ -143,6 +159,7 @@ struct JavaToSwift: AsyncParsableCommand {
// The configuration file goes at the top level.
let outputDir: Foundation.URL
if jar {
+ precondition(self.input != nil, "-jar mode requires path to jar to be specified as input path")
outputDir = baseDir
} else {
outputDir = baseDir
@@ -163,23 +180,58 @@ struct JavaToSwift: AsyncParsableCommand {
/// Fetch dependencies for a module
case fetchDependencies
+
+ /// Extract Java bindings from provided Swift sources.
+ case jextract // TODO: carry jextract specific config here?
}
mutating func run() async {
print("[info][swift-java] Run: \(CommandLine.arguments.joined(separator: " "))")
+ print("[info][swift-java] Current work directory: \(URL(fileURLWithPath: "."))")
+ print("[info][swift-java] Module base directory: \(moduleBaseDir)")
do {
- let config: Configuration
-
+ var earlyConfig: Configuration?
+ if let moduleBaseDir {
+ print("[debug][swift-java] Load config from module base directory: \(moduleBaseDir.path)")
+ earlyConfig = try readConfiguration(sourceDir: moduleBaseDir.path)
+ } else if let inputSwift {
+ print("[debug][swift-java] Load config from module swift input directory: \(inputSwift)")
+ earlyConfig = try readConfiguration(sourceDir: inputSwift)
+ }
+ var config = earlyConfig ?? Configuration()
+
+ config.logLevel = self.logLevel
+ if let javaPackage {
+ config.javaPackage = javaPackage
+ }
+
// Determine the mode in which we'll execute.
let toolMode: ToolMode
- if jar {
- if let moduleBaseDir {
- config = try readConfiguration(sourceDir: moduleBaseDir.path)
- } else {
- config = Configuration()
+ // TODO: some options are exclusive to each other so we should detect that
+ if let inputSwift {
+ guard let outputSwift else {
+ print("[swift-java] --input-swift enabled 'jextract' mode, however no --output-swift directory was provided!\n\(Self.helpMessage())")
+ return
+ }
+ guard let outputJava else {
+ print("[swift-java] --input-swift enabled 'jextract' mode, however no --output-java directory was provided!\n\(Self.helpMessage())")
+ return
+ }
+ config.swiftModule = self.moduleName // FIXME: rename the moduleName
+ config.inputSwiftDirectory = self.inputSwift
+ config.outputSwiftDirectory = self.outputSwift
+ config.outputJavaDirectory = self.outputJava
+
+ toolMode = .jextract
+ } else if jar {
+ guard let input else {
+ fatalError("Mode -jar requires path\n\(Self.helpMessage())")
}
toolMode = .configuration(extraClasspath: input)
} else if fetch {
+ guard let input else {
+ fatalError("Mode -jar requires path\n\(Self.helpMessage())")
+ }
config = try JavaTranslator.readConfiguration(from: URL(fileURLWithPath: input))
guard let dependencies = config.dependencies else {
print("[swift-java] Running in 'fetch dependencies' mode but dependencies list was empty!")
@@ -188,13 +240,23 @@ struct JavaToSwift: AsyncParsableCommand {
}
toolMode = .fetchDependencies
} else {
+ guard let input else {
+ fatalError("Mode -jar requires path\n\(Self.helpMessage())")
+ }
config = try JavaTranslator.readConfiguration(from: URL(fileURLWithPath: input))
toolMode = .classWrappers
}
- let moduleName = self.moduleName ??
- input.split(separator: "/").dropLast().last.map(String.init) ??
- "__UnknownModule"
+ print("[debug][swift-java] Running swift-java in mode: " + "\(toolMode.prettyName)".bold)
+
+ let moduleName: String =
+ if let name = self.moduleName {
+ name
+ } else if let input {
+ input.split(separator: "/").dropLast().last.map(String.init) ?? "__UnknownModule"
+ } else {
+ "__UnknownModule"
+ }
// Load all of the dependent configurations and associate them with Swift
// modules.
@@ -251,18 +313,24 @@ struct JavaToSwift: AsyncParsableCommand {
// print("[debug][swift-java] Found cached dependency resolver classpath: \(dependencyResolverClasspath)")
// classpathEntries += dependencyResolverClasspath
// }
- case .classWrappers:
+ case .classWrappers, .jextract:
break;
}
- // Bring up the Java VM.
+ // Bring up the Java VM when necessary
// TODO: print only in verbose mode
let classpath = classpathEntries.joined(separator: ":")
- print("[debug][swift-java] Initialize JVM with classpath: \(classpath)")
- let jvm = try JavaVirtualMachine.shared(classpath: classpathEntries)
+ let jvm: JavaVirtualMachine!
+ switch toolMode {
+ case .configuration, .classWrappers:
+ print("[debug][swift-java] Initialize JVM with classpath: \(classpath)")
+ jvm = try JavaVirtualMachine.shared(classpath: classpathEntries)
+ default:
+ jvm = nil
+ }
- // * Classespaths from all dependent configuration files
+ // * Classpaths from all dependent configuration files
for (_, config) in dependentConfigs {
// 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
@@ -292,9 +360,6 @@ struct JavaToSwift: AsyncParsableCommand {
guard let dependencies = config.dependencies else {
fatalError("Configuration for fetching dependencies must have 'dependencies' defined!")
}
- guard let moduleName = self.moduleName else {
- fatalError("Fetching dependencies must specify module name (--module-name)!")
- }
guard let effectiveCacheDirectory else {
fatalError("Fetching dependencies must effective cache directory! Specify --output-directory or --cache-directory")
}
@@ -310,6 +375,9 @@ struct JavaToSwift: AsyncParsableCommand {
moduleName: moduleName,
cacheDir: effectiveCacheDirectory,
resolvedClasspath: dependencyClasspath)
+
+ case .jextract:
+ try jextractSwift(config: config)
}
} catch {
// We fail like this since throwing out of the run often ends up hiding the failure reason when it is executed as SwiftPM plugin (!)
@@ -382,7 +450,7 @@ struct JavaToSwift: AsyncParsableCommand {
}
}
-extension JavaToSwift {
+extension SwiftJava {
/// Get base configuration, depending on if we are to 'amend' or 'overwrite' the existing configuration.
package func getBaseConfigurationForWrite() throws -> (Bool, Configuration) {
guard let actualOutputDirectory = self.actualOutputDirectory else {
@@ -396,7 +464,10 @@ extension JavaToSwift {
return (false, .init())
case .amend:
let configPath = actualOutputDirectory
- return (true, try readConfiguration(sourceDir: configPath.path))
+ guard let config = try readConfiguration(sourceDir: configPath.path) else {
+ return (false, .init())
+ }
+ return (true, config)
}
}
}
@@ -425,3 +496,13 @@ extension JavaClass {
public func getSystemClassLoader() -> ClassLoader?
}
+extension SwiftJava.ToolMode {
+ var prettyName: String {
+ switch self {
+ case .configuration: "Configuration"
+ case .fetchDependencies: "Fetch dependencies"
+ case .classWrappers: "Wrap Java classes"
+ case .jextract: "JExtract Swift for Java"
+ }
+ }
+}
diff --git a/Tests/JExtractSwiftTests/Asserts/LoweringAssertions.swift b/Tests/JExtractSwiftTests/Asserts/LoweringAssertions.swift
index cbdcc6dd..b306689d 100644
--- a/Tests/JExtractSwiftTests/Asserts/LoweringAssertions.swift
+++ b/Tests/JExtractSwiftTests/Asserts/LoweringAssertions.swift
@@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//
-@_spi(Testing) import JExtractSwift
+@_spi(Testing) import JExtractSwiftLib
import SwiftSyntax
import Testing
diff --git a/Tests/JExtractSwiftTests/Asserts/TextAssertions.swift b/Tests/JExtractSwiftTests/Asserts/TextAssertions.swift
index 1686f0ab..3923cf3e 100644
--- a/Tests/JExtractSwiftTests/Asserts/TextAssertions.swift
+++ b/Tests/JExtractSwiftTests/Asserts/TextAssertions.swift
@@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//
-import JExtractSwift
+import JExtractSwiftLib
import Testing
import struct Foundation.CharacterSet
diff --git a/Tests/JExtractSwiftTests/CTypeTests.swift b/Tests/JExtractSwiftTests/CTypeTests.swift
index 569296d6..a2339e34 100644
--- a/Tests/JExtractSwiftTests/CTypeTests.swift
+++ b/Tests/JExtractSwiftTests/CTypeTests.swift
@@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//
-import JExtractSwift
+import JExtractSwiftLib
import Testing
@Suite("C type system tests")
diff --git a/Tests/JExtractSwiftTests/ClassPrintingTests.swift b/Tests/JExtractSwiftTests/ClassPrintingTests.swift
index 94cd8a40..1edcdaf0 100644
--- a/Tests/JExtractSwiftTests/ClassPrintingTests.swift
+++ b/Tests/JExtractSwiftTests/ClassPrintingTests.swift
@@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//
-import JExtractSwift
+import JExtractSwiftLib
import Testing
struct ClassPrintingTests {
diff --git a/Tests/JExtractSwiftTests/FuncCallbackImportTests.swift b/Tests/JExtractSwiftTests/FuncCallbackImportTests.swift
index 50022c55..8b401ce3 100644
--- a/Tests/JExtractSwiftTests/FuncCallbackImportTests.swift
+++ b/Tests/JExtractSwiftTests/FuncCallbackImportTests.swift
@@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//
-import JExtractSwift
+import JExtractSwiftLib
import Testing
final class FuncCallbackImportTests {
diff --git a/Tests/JExtractSwiftTests/FunctionDescriptorImportTests.swift b/Tests/JExtractSwiftTests/FunctionDescriptorImportTests.swift
index 9cdcdf58..2963ce9e 100644
--- a/Tests/JExtractSwiftTests/FunctionDescriptorImportTests.swift
+++ b/Tests/JExtractSwiftTests/FunctionDescriptorImportTests.swift
@@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//
-import JExtractSwift
+import JExtractSwiftLib
import Testing
@Suite
diff --git a/Tests/JExtractSwiftTests/FunctionLoweringTests.swift b/Tests/JExtractSwiftTests/FunctionLoweringTests.swift
index dce594ae..b7855e43 100644
--- a/Tests/JExtractSwiftTests/FunctionLoweringTests.swift
+++ b/Tests/JExtractSwiftTests/FunctionLoweringTests.swift
@@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//
-import JExtractSwift
+import JExtractSwiftLib
import SwiftSyntax
import Testing
diff --git a/Tests/JExtractSwiftTests/MethodImportTests.swift b/Tests/JExtractSwiftTests/MethodImportTests.swift
index 25c028ce..48515ff2 100644
--- a/Tests/JExtractSwiftTests/MethodImportTests.swift
+++ b/Tests/JExtractSwiftTests/MethodImportTests.swift
@@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//
-import JExtractSwift
+import JExtractSwiftLib
import Testing
final class MethodImportTests {
diff --git a/Tests/JExtractSwiftTests/MethodThunkTests.swift b/Tests/JExtractSwiftTests/MethodThunkTests.swift
index d57e449e..f6f5ce71 100644
--- a/Tests/JExtractSwiftTests/MethodThunkTests.swift
+++ b/Tests/JExtractSwiftTests/MethodThunkTests.swift
@@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//
-import JExtractSwift
+import JExtractSwiftLib
import Testing
final class MethodThunkTests {
diff --git a/Tests/JExtractSwiftTests/StringPassingTests.swift b/Tests/JExtractSwiftTests/StringPassingTests.swift
index 08190399..ae131b94 100644
--- a/Tests/JExtractSwiftTests/StringPassingTests.swift
+++ b/Tests/JExtractSwiftTests/StringPassingTests.swift
@@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//
-import JExtractSwift
+import JExtractSwiftLib
import Testing
final class StringPassingTests {
diff --git a/Tests/JExtractSwiftTests/SwiftSymbolTableTests.swift b/Tests/JExtractSwiftTests/SwiftSymbolTableTests.swift
index 5d1e5e2b..2bbaa913 100644
--- a/Tests/JExtractSwiftTests/SwiftSymbolTableTests.swift
+++ b/Tests/JExtractSwiftTests/SwiftSymbolTableTests.swift
@@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//
-@_spi(Testing) import JExtractSwift
+@_spi(Testing) import JExtractSwiftLib
import SwiftSyntax
import SwiftParser
import Testing
diff --git a/Tests/JExtractSwiftTests/VariableImportTests.swift b/Tests/JExtractSwiftTests/VariableImportTests.swift
index 55724293..9d8650b4 100644
--- a/Tests/JExtractSwiftTests/VariableImportTests.swift
+++ b/Tests/JExtractSwiftTests/VariableImportTests.swift
@@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//
-import JExtractSwift
+import JExtractSwiftLib
import Testing
final class VariableImportTests {
diff --git a/Tests/Java2SwiftTests/Java2SwiftTests.swift b/Tests/SwiftJavaTests/Java2SwiftTests.swift
similarity index 99%
rename from Tests/Java2SwiftTests/Java2SwiftTests.swift
rename to Tests/SwiftJavaTests/Java2SwiftTests.swift
index 48440522..e2b68a34 100644
--- a/Tests/Java2SwiftTests/Java2SwiftTests.swift
+++ b/Tests/SwiftJavaTests/Java2SwiftTests.swift
@@ -14,7 +14,7 @@
@_spi(Testing)
import JavaKit
-import Java2SwiftLib
+import SwiftJavaLib
import XCTest // NOTE: Workaround for https://github.com/swiftlang/swift-java/issues/43
/// Handy reference to the JVM abstraction.
diff --git a/Tests/Java2SwiftTests/JavaTranslatorValidationTests.swift b/Tests/SwiftJavaTests/JavaTranslatorValidationTests.swift
similarity index 98%
rename from Tests/Java2SwiftTests/JavaTranslatorValidationTests.swift
rename to Tests/SwiftJavaTests/JavaTranslatorValidationTests.swift
index e5c3a951..a203486a 100644
--- a/Tests/Java2SwiftTests/JavaTranslatorValidationTests.swift
+++ b/Tests/SwiftJavaTests/JavaTranslatorValidationTests.swift
@@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//
-import Java2SwiftLib
+import SwiftJavaLib
import XCTest
final class JavaTranslatorValidationTests: XCTestCase {