Skip to content

Commit 784ec9c

Browse files
committed
extend jextract build plugin to compile java sources
1 parent 7d87b6e commit 784ec9c

File tree

2 files changed

+106
-3
lines changed

2 files changed

+106
-3
lines changed

Plugins/JExtractSwiftPlugin/JExtractSwiftPlugin.swift

Lines changed: 88 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,16 @@ struct JExtractSwiftBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin {
2525

2626
func createBuildCommands(context: PluginContext, target: Target) throws -> [Command] {
2727
let toolURL = try context.tool(named: "SwiftJavaTool").url
28-
28+
29+
// The URL of the compiled Java sources
30+
let javaClassFileURL = context.pluginWorkDirectoryURL
31+
.appending(path: "compiled-java-output")
32+
33+
var commands: [Command] = []
34+
2935
guard let sourceModule = target.sourceModule else { return [] }
3036

37+
3138
// Note: Target doesn't have a directoryURL counterpart to directory,
3239
// so we cannot eliminate this deprecation warning.
3340
for dependency in target.dependencies {
@@ -123,15 +130,71 @@ struct JExtractSwiftBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin {
123130

124131
print("[swift-java-plugin] Output swift files:\n - \(outputSwiftFiles.map({$0.absoluteString}).joined(separator: "\n - "))")
125132

126-
return [
133+
// Extract list of all sources
134+
let javaSourcesFile = outputJavaDirectory.appending(path: "sources.txt")
135+
136+
commands += [
127137
.buildCommand(
128138
displayName: "Generate Java wrappers for Swift types",
129139
executable: toolURL,
130140
arguments: arguments,
131141
inputFiles: [ configFile ] + swiftFiles,
132-
outputFiles: outputSwiftFiles
142+
outputFiles: outputSwiftFiles + [javaSourcesFile]
133143
)
134144
]
145+
146+
// Build SwiftKitCore and get the classpath
147+
// as the jextracted sources will depend on that
148+
149+
guard let swiftJavaDirectory = findSwiftJavaDirectory(for: target) else {
150+
// FIXME: Error
151+
fatalError()
152+
}
153+
log("Found swift-java at \(swiftJavaDirectory)")
154+
155+
commands += [
156+
.buildCommand(
157+
displayName: "Build SwiftKitCore",
158+
executable: swiftJavaDirectory.appending(path: "gradlew"),
159+
arguments: [
160+
":SwiftKitCore:build",
161+
"-p", swiftJavaDirectory.path(percentEncoded: false),
162+
"--configure-on-demand",
163+
"--no-daemon"
164+
],
165+
environment: [:],
166+
inputFiles: [swiftJavaDirectory],
167+
outputFiles: []
168+
)
169+
]
170+
171+
let swiftKitCoreClassPath = swiftJavaDirectory.appending(path: "SwiftKitCore/build/classes/java/main")
172+
173+
// Compile the jextracted sources
174+
let javaHome = URL(filePath: findJavaHome())
175+
#if os(Windows)
176+
let javac = "javac.exe"
177+
#else
178+
let javac = "javac"
179+
#endif
180+
commands += [
181+
.buildCommand(
182+
displayName: "Build extracted Java sources",
183+
executable: javaHome
184+
.appending(path: "bin")
185+
.appending(path: javac),
186+
arguments: [
187+
"@\(javaSourcesFile.path(percentEncoded: false))",
188+
"-d", javaClassFileURL.path,
189+
"-parameters",
190+
"-classpath", swiftKitCoreClassPath.path(percentEncoded: false)
191+
],
192+
inputFiles: [javaSourcesFile],
193+
outputFiles: []
194+
)
195+
]
196+
197+
return commands
135198
}
136199

137200
/// Find the manifest files from other swift-java executions in any targets
@@ -181,5 +244,27 @@ struct JExtractSwiftBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin {
181244

182245
return dependentConfigFiles
183246
}
247+
248+
private func findSwiftJavaDirectory(for target: any Target) -> URL? {
249+
for dependency in target.dependencies {
250+
switch dependency {
251+
case .target(let target):
252+
continue
253+
254+
case .product(let product):
255+
guard let swiftJava = product.sourceModules.first(where: { $0.name == "SwiftJava" }) else {
256+
return nil
257+
}
258+
259+
// We are inside Sources/SwiftJava
260+
return swiftJava.directoryURL.deletingLastPathComponent().deletingLastPathComponent()
261+
262+
@unknown default:
263+
continue
264+
}
265+
}
266+
267+
return nil
268+
}
184269
}
185270

Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+JavaBindingsPrinting.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
//
1313
//===----------------------------------------------------------------------===//
1414

15+
import Foundation
1516
import JavaTypes
1617

1718
// MARK: Defaults
@@ -40,6 +41,8 @@ extension JNISwift2JavaGenerator {
4041
package func writeExportedJavaSources(_ printer: inout CodePrinter) throws {
4142
let importedTypes = analysis.importedTypes.sorted(by: { (lhs, rhs) in lhs.key < rhs.key })
4243

44+
var exportedFileNames: Set<String> = []
45+
4346
// Each parent type goes into its own file
4447
// any nested types are printed inside the body as `static class`
4548
for (_, ty) in importedTypes.filter({ _, type in type.parent == nil }) {
@@ -52,6 +55,7 @@ extension JNISwift2JavaGenerator {
5255
javaPackagePath: javaPackagePath,
5356
filename: filename
5457
) {
58+
exportedFileNames.insert(outputFile.path(percentEncoded: false))
5559
logger.info("[swift-java] Generated: \(ty.swiftNominal.name.bold).java (at \(outputFile))")
5660
}
5761
}
@@ -65,10 +69,24 @@ extension JNISwift2JavaGenerator {
6569
javaPackagePath: javaPackagePath,
6670
filename: filename
6771
) {
72+
exportedFileNames.insert(outputFile.path(percentEncoded: false))
6873
logger.info("[swift-java] Generated: \(self.swiftModuleName).java (at \(outputFile))")
6974
}
75+
76+
// Write sources.txt file
77+
if !exportedFileNames.isEmpty {
78+
let outputPath = URL(fileURLWithPath: javaOutputDirectory).appending(path: "sources.txt")
79+
try exportedFileNames.joined(separator: "\n").write(
80+
to: outputPath,
81+
atomically: true,
82+
encoding: .utf8
83+
)
84+
logger.info("Generated file at \(outputPath)")
85+
}
7086
}
7187

88+
89+
7290
private func printModule(_ printer: inout CodePrinter) {
7391
printHeader(&printer)
7492
printPackage(&printer)

0 commit comments

Comments
 (0)