Skip to content

Commit 8e628a3

Browse files
committed
refactor jextract plugin to be a BUILD plugin; unblocks swift 6.2
1 parent 7001b09 commit 8e628a3

File tree

11 files changed

+220
-102
lines changed

11 files changed

+220
-102
lines changed

Package.swift

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -175,12 +175,12 @@ let package = Package(
175175
"JExtractSwiftPlugin"
176176
]
177177
),
178-
.plugin(
179-
name: "JExtractSwiftCommandPlugin",
180-
targets: [
181-
"JExtractSwiftCommandPlugin"
182-
]
183-
),
178+
// .plugin(
179+
// name: "JExtractSwiftCommandPlugin",
180+
// targets: [
181+
// "JExtractSwiftCommandPlugin"
182+
// ]
183+
// ),
184184

185185
// ==== Examples
186186

@@ -429,16 +429,16 @@ let package = Package(
429429
"SwiftJavaTool"
430430
]
431431
),
432-
.plugin(
433-
name: "JExtractSwiftCommandPlugin",
434-
capability: .command(
435-
intent: .custom(verb: "jextract", description: "Extract Java accessors from Swift module"),
436-
permissions: [
437-
]),
438-
dependencies: [
439-
"SwiftJavaTool"
440-
]
441-
),
432+
// .plugin(
433+
// name: "JExtractSwiftCommandPlugin",
434+
// capability: .command(
435+
// intent: .custom(verb: "jextract", description: "Extract Java accessors from Swift module"),
436+
// permissions: [
437+
// ]),
438+
// dependencies: [
439+
// "SwiftJavaTool"
440+
// ]
441+
// ),
442442

443443
.testTarget(
444444
name: "JavaKitTests",

Plugins/JExtractSwiftCommandPlugin/JExtractSwiftCommandPlugin.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ final class JExtractSwiftCommandPlugin: SwiftJavaPluginProtocol, BuildToolPlugin
7272

7373
var arguments: [String] = [
7474
/*subcommand=*/"jextract",
75-
"--input-swift", sourceDir,
7675
"--swift-module", sourceModule.name,
76+
"--input-swift", sourceDir,
7777
"--output-java", context.outputJavaDirectory.path(percentEncoded: false),
7878
"--output-swift", context.outputSwiftDirectory.path(percentEncoded: false),
7979
// TODO: "--build-cache-directory", ...

Plugins/JExtractSwiftPlugin/JExtractSwiftPlugin.swift

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ struct JExtractSwiftBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin {
4040
}
4141

4242
let sourceDir = target.directory.string
43+
44+
// The name of the configuration file JavaKit.config from the target for
45+
// which we are generating Swift wrappers for Java classes.
46+
let configFile = URL(filePath: sourceDir).appending(path: "swift-java.config")
4347
let configuration = try readConfiguration(sourceDir: "\(sourceDir)")
4448

4549
guard let javaPackage = configuration?.javaPackage else {
@@ -65,18 +69,53 @@ struct JExtractSwiftBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin {
6569
// We'll have to make up some caching inside the tool so we don't re-parse files which have not changed etc.
6670
]
6771
if !javaPackage.isEmpty {
68-
arguments.append(contentsOf: ["--java-package", javaPackage])
72+
arguments += ["--java-package", javaPackage]
73+
}
74+
75+
let swiftFiles = sourceModule.sourceFiles.map { $0.url }.filter {
76+
$0.pathExtension == "swift"
77+
}
78+
79+
let outputSwiftFiles: [URL] = swiftFiles.compactMap { sourceFileURL in
80+
guard sourceFileURL.isFileURL else {
81+
return nil as URL?
82+
}
83+
84+
let sourceFilePath = sourceFileURL.path
85+
guard sourceFilePath.starts(with: sourceDir) else {
86+
fatalError("Could not get relative path for source file \(sourceFilePath)")
87+
}
88+
var outputURL = outputSwiftDirectory
89+
.appending(path: String(sourceFilePath.dropFirst(sourceDir.count).dropLast(sourceFileURL.lastPathComponent.count + 1)))
90+
91+
let inputFileName = sourceFileURL.deletingPathExtension().lastPathComponent
92+
print(" inputFileName = \(inputFileName)")
93+
let isModuleFile = inputFileName.contains("Library") // FIXME: this is a hack
94+
print(" isModuleFile = \(isModuleFile)")
95+
96+
return if isModuleFile {
97+
outputURL.appending(path: "\(inputFileName)Module+SwiftJava.swift")
98+
} else {
99+
outputURL.appending(path: "\(inputFileName)+SwiftJava.swift")
100+
}
69101
}
70102

71103
return [
72-
.prebuildCommand(
104+
.buildCommand(
73105
displayName: "Generate Java wrappers for Swift types",
74106
executable: toolURL,
75107
arguments: arguments,
76-
// inputFiles: [ configFile ] + swiftFiles,
77-
// outputFiles: outputJavaFiles
78-
outputFilesDirectory: outputSwiftDirectory
108+
inputFiles: [ configFile ] + swiftFiles,
109+
outputFiles: outputSwiftFiles
79110
)
111+
// .prebuildCommand(
112+
// displayName: "Generate Java wrappers for Swift types",
113+
// executable: toolURL,
114+
// arguments: arguments,
115+
// // inputFiles: [ configFile ] + swiftFiles,
116+
// // outputFiles: outputJavaFiles
117+
// outputFilesDirectory: outputSwiftDirectory
118+
// )
80119
]
81120
}
82121
}

Plugins/JavaCompilerPlugin/JavaCompilerPlugin.swift

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ struct JavaCompilerBuildToolPlugin: BuildToolPlugin {
3434

3535
// The name of the configuration file JavaKit.config from the target for
3636
// which we are generating Swift wrappers for Java classes.
37-
let configFile = URL(filePath: sourceDir).appending(path: "Java2Swift.config")
37+
let configFile = URL(filePath: sourceDir).appending(path: "swift-java.config")
3838
let config: Configuration?
3939

4040
if let configData = try? Data(contentsOf: configFile) {
@@ -45,18 +45,21 @@ struct JavaCompilerBuildToolPlugin: BuildToolPlugin {
4545

4646
// The class files themselves will be generated into the build directory
4747
// for this target.
48-
let classFiles = javaFiles.map { sourceFileURL in
48+
let classFiles = javaFiles.compactMap { sourceFileURL in
49+
guard sourceFileURL.isFileURL else {
50+
return nil as URL?
51+
}
52+
4953
let sourceFilePath = sourceFileURL.path
5054
guard sourceFilePath.starts(with: sourceDir) else {
5155
fatalError("Could not get relative path for source file \(sourceFilePath)")
5256
}
5357

54-
return URL(
55-
filePath: context.pluginWorkDirectoryURL.path
56-
).appending(path: "Java")
57-
.appending(path: String(sourceFilePath.dropFirst(sourceDir.count)))
58-
.deletingPathExtension()
59-
.appendingPathExtension("class")
58+
return URL(filePath: context.pluginWorkDirectoryURL.path)
59+
.appending(path: "Java")
60+
.appending(path: String(sourceFilePath.dropFirst(sourceDir.count)))
61+
.deletingPathExtension()
62+
.appendingPathExtension("class")
6063
}
6164

6265
let javaHome = URL(filePath: findJavaHome())
@@ -73,7 +76,7 @@ struct JavaCompilerBuildToolPlugin: BuildToolPlugin {
7376
"-parameters", // keep parameter names, which allows us to emit them in generated Swift decls
7477
] + (config?.compilerVersionArgs ?? []),
7578
inputFiles: javaFiles,
76-
outputFiles: classFiles
79+
outputFiles: classFiles // FIXME: this is not quite enough, javac may generate more files for closures etc, which we don't know about unless we compile first
7780
)
7881
]
7982
}

Plugins/SwiftJavaPlugin/SwiftJavaPlugin.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ struct SwiftJavaBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin {
4444
log("Config was: \(config)")
4545
var javaDependencies = config.dependencies ?? []
4646

47-
/// Find the manifest files from other Java2Swift executions in any targets
47+
/// Find the manifest files from other swift-java executions in any targets
4848
/// this target depends on.
4949
var dependentConfigFiles: [(String, URL)] = []
5050
func searchForConfigFiles(in target: any Target) {
@@ -95,7 +95,7 @@ struct SwiftJavaBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin {
9595
let classes = config.classes ?? [:]
9696
print("[swift-java-plugin] Classes to wrap (\(classes.count)): \(classes.map(\.key))")
9797

98-
/// Determine the set of Swift files that will be emitted by the Java2Swift tool.
98+
/// Determine the set of Swift files that will be emitted by the swift-java tool.
9999
// TODO: this is not precise and won't work with more advanced Java files, e.g. lambdas etc.
100100
let outputDirectoryGenerated = self.outputDirectory(context: context, generated: true)
101101
let outputSwiftFiles = classes.map { (javaClassName, swiftName) in
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2024 Apple Inc. and the Swift.org project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of Swift.org project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
// This is a "plain Swift" file containing various types of declarations,
16+
// that is exported to Java by using the `jextract-swift` tool.
17+
//
18+
// No annotations are necessary on the Swift side to perform the export.
19+
20+
#if os(Linux)
21+
import Glibc
22+
#else
23+
import Darwin.C
24+
#endif
25+
26+
public class MySwiftClass {
27+
28+
public var len: Int
29+
public var cap: Int
30+
31+
public init(len: Int, cap: Int) {
32+
self.len = len
33+
self.cap = cap
34+
35+
p("\(MySwiftClass.self).len = \(self.len)")
36+
p("\(MySwiftClass.self).cap = \(self.cap)")
37+
let addr = unsafeBitCast(self, to: UInt64.self)
38+
p("initializer done, self = 0x\(String(addr, radix: 16, uppercase: true))")
39+
}
40+
41+
deinit {
42+
let addr = unsafeBitCast(self, to: UInt64.self)
43+
p("Deinit, self = 0x\(String(addr, radix: 16, uppercase: true))")
44+
}
45+
46+
public var counter: Int32 = 0
47+
48+
public func voidMethod() {
49+
p("")
50+
}
51+
52+
public func takeIntMethod(i: Int) {
53+
p("i:\(i)")
54+
}
55+
56+
public func echoIntMethod(i: Int) -> Int {
57+
p("i:\(i)")
58+
return i
59+
}
60+
61+
public func makeIntMethod() -> Int {
62+
p("make int -> 12")
63+
return 12
64+
}
65+
66+
public func makeRandomIntMethod() -> Int {
67+
return Int.random(in: 1..<256)
68+
}
69+
}

Samples/SwiftAndJavaJarSampleLib/Sources/MySwiftLibrary/MySwiftLibrary.swift

Lines changed: 46 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -38,55 +38,55 @@ public func globalTakeIntInt(i: Int, j: Int) {
3838
public func globalCallMeRunnable(run: () -> ()) {
3939
run()
4040
}
41-
42-
public class MySwiftClass {
43-
44-
public var len: Int
45-
public var cap: Int
46-
47-
public init(len: Int, cap: Int) {
48-
self.len = len
49-
self.cap = cap
50-
51-
p("\(MySwiftClass.self).len = \(self.len)")
52-
p("\(MySwiftClass.self).cap = \(self.cap)")
53-
let addr = unsafeBitCast(self, to: UInt64.self)
54-
p("initializer done, self = 0x\(String(addr, radix: 16, uppercase: true))")
55-
}
56-
57-
deinit {
58-
let addr = unsafeBitCast(self, to: UInt64.self)
59-
p("Deinit, self = 0x\(String(addr, radix: 16, uppercase: true))")
60-
}
61-
62-
public var counter: Int32 = 0
63-
64-
public func voidMethod() {
65-
p("")
66-
}
67-
68-
public func takeIntMethod(i: Int) {
69-
p("i:\(i)")
70-
}
71-
72-
public func echoIntMethod(i: Int) -> Int {
73-
p("i:\(i)")
74-
return i
75-
}
76-
77-
public func makeIntMethod() -> Int {
78-
p("make int -> 12")
79-
return 12
80-
}
81-
82-
public func makeRandomIntMethod() -> Int {
83-
return Int.random(in: 1..<256)
84-
}
85-
}
41+
//
42+
//public class MySwiftClass {
43+
//
44+
// public var len: Int
45+
// public var cap: Int
46+
//
47+
// public init(len: Int, cap: Int) {
48+
// self.len = len
49+
// self.cap = cap
50+
//
51+
// p("\(MySwiftClass.self).len = \(self.len)")
52+
// p("\(MySwiftClass.self).cap = \(self.cap)")
53+
// let addr = unsafeBitCast(self, to: UInt64.self)
54+
// p("initializer done, self = 0x\(String(addr, radix: 16, uppercase: true))")
55+
// }
56+
//
57+
// deinit {
58+
// let addr = unsafeBitCast(self, to: UInt64.self)
59+
// p("Deinit, self = 0x\(String(addr, radix: 16, uppercase: true))")
60+
// }
61+
//
62+
// public var counter: Int32 = 0
63+
//
64+
// public func voidMethod() {
65+
// p("")
66+
// }
67+
//
68+
// public func takeIntMethod(i: Int) {
69+
// p("i:\(i)")
70+
// }
71+
//
72+
// public func echoIntMethod(i: Int) -> Int {
73+
// p("i:\(i)")
74+
// return i
75+
// }
76+
//
77+
// public func makeIntMethod() -> Int {
78+
// p("make int -> 12")
79+
// return 12
80+
// }
81+
//
82+
// public func makeRandomIntMethod() -> Int {
83+
// return Int.random(in: 1..<256)
84+
// }
85+
//}
8686

8787
// ==== Internal helpers
8888

89-
private func p(_ msg: String, file: String = #fileID, line: UInt = #line, function: String = #function) {
89+
func p(_ msg: String, file: String = #fileID, line: UInt = #line, function: String = #function) {
9090
print("[swift][\(file):\(line)](\(function)) \(msg)")
9191
fflush(stdout)
9292
}

0 commit comments

Comments
 (0)