Skip to content

Commit 95e56ef

Browse files
committed
snapshot
1 parent c3ad3c1 commit 95e56ef

File tree

12 files changed

+294
-57
lines changed

12 files changed

+294
-57
lines changed

.github/workflows/pull_request.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ jobs:
88
soundness:
99
uses: swiftlang/github-workflows/.github/workflows/soundness.yml@main
1010
with:
11+
# Not API stable package (yet)
1112
api_breakage_check_enabled: false
1213
# FIXME: Something is off with the format task and it gets "stuck", need to investigate
1314
format_check_enabled: false

Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ javakit-generate: generate-JavaKit generate-JavaKitReflection generate-JavaKitJa
9494

9595
clean:
9696
rm -rf .build; \
97+
rm -rf build; \
98+
rm -rf Samples/JExtractPluginSampleApp/.build; \
99+
rm -rf Samples/JExtractPluginSampleApp/build; \
97100
rm -rf Samples/SwiftKitExampleApp/src/generated/java/*
98101

99102
format:

Package.swift

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,13 @@ let package = Package(
133133
"JExtractSwiftPlugin"
134134
]
135135
),
136-
136+
.plugin(
137+
name: "JExtractSwiftCommandPlugin",
138+
targets: [
139+
"JExtractSwiftCommandPlugin"
140+
]
141+
),
142+
137143
// ==== Examples
138144

139145
.library(
@@ -347,6 +353,16 @@ let package = Package(
347353
"JExtractSwiftTool"
348354
]
349355
),
356+
.plugin(
357+
name: "JExtractSwiftCommandPlugin",
358+
capability: .command(
359+
intent: .custom(verb: "jextract", description: "Extract Java accessors from Swift module"),
360+
permissions: [
361+
]),
362+
dependencies: [
363+
"JExtractSwiftTool"
364+
]
365+
),
350366

351367
.testTarget(
352368
name: "JavaKitTests",
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
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+
import Foundation
16+
import PackagePlugin
17+
18+
@main
19+
final class JExtractSwiftCommandPlugin: BuildToolPlugin, CommandPlugin {
20+
21+
var verbose: Bool = false
22+
23+
func createBuildCommands(context: PackagePlugin.PluginContext, target: any PackagePlugin.Target) async throws -> [PackagePlugin.Command] {
24+
// FIXME: This is not a build plugin but SwiftPM forces us to impleme the protocol anyway? rdar://139556637
25+
return []
26+
}
27+
28+
func performCommand(context: PluginContext, arguments: [String]) throws {
29+
self.verbose = arguments.contains("-v") || arguments.contains("--verbose")
30+
31+
let selectedTargets: [String] =
32+
if let last = arguments.lastIndex(where: { $0.starts(with: "-")}),
33+
last < arguments.endIndex {
34+
Array(arguments[..<last])
35+
} else {
36+
[]
37+
}
38+
39+
for target in context.package.targets {
40+
guard hasSwiftJavaConfig(target: target) else {
41+
log("Skipping target '\(target.name), has no 'swift-java.config' file")
42+
continue
43+
}
44+
45+
do {
46+
print("[swift-java] Extracting Java wrappers from target: '\(target.name)'...")
47+
try performCommand(context: context, target: target, arguments: arguments)
48+
} catch {
49+
print("[swift-java] error: Failed to extract from target '\(target.name)': \(error)")
50+
}
51+
}
52+
}
53+
54+
/// Perform the command on a specific target.
55+
func performCommand(context: PluginContext, target: Target, arguments: [String]) throws {
56+
// Make sure the target can builds properly
57+
try self.packageManager.build(.target(target.name), parameters: .init())
58+
59+
guard let sourceModule = target.sourceModule else { return }
60+
61+
// Note: Target doesn't have a directoryURL counterpart to directory,
62+
// so we cannot eliminate this deprecation warning.
63+
let sourceDir = target.directory.string
64+
65+
let configuration = try readConfiguration(sourceDir: "\(sourceDir)")
66+
67+
// We use the the usual maven-style structure of "src/[generated|main|test]/java/..."
68+
// that is common in JVM ecosystem
69+
let outputDirectoryJava = context.pluginWorkDirectoryURL
70+
.appending(path: "src")
71+
.appending(path: "generated")
72+
.appending(path: "java")
73+
let outputDirectorySwift = context.pluginWorkDirectoryURL
74+
.appending(path: "src")
75+
.appending(path: "generated")
76+
.appending(path: "Sources")
77+
78+
var arguments: [String] = [
79+
"--swift-module", sourceModule.name,
80+
"--package-name", configuration.javaPackage,
81+
"--output-directory-java", outputDirectoryJava.path(percentEncoded: false),
82+
"--output-directory-swift", outputDirectorySwift.path(percentEncoded: false),
83+
// TODO: "--build-cache-directory", ...
84+
// Since plugins cannot depend on libraries we cannot detect what the output files will be,
85+
// as it depends on the contents of the input files. Therefore we have to implement this as a prebuild plugin.
86+
// We'll have to make up some caching inside the tool so we don't re-parse files which have not changed etc.
87+
]
88+
arguments.append(sourceDir)
89+
90+
print("PLUGIN: jextract \(arguments.joined(separator: " "))")
91+
92+
try runExtract(context: context, target: target, arguments: arguments)
93+
}
94+
95+
func runExtract(context: PluginContext, target: Target, arguments: [String]) throws {
96+
let process = Process()
97+
process.executableURL = try context.tool(named: "JExtractSwiftTool").url
98+
process.arguments = arguments
99+
100+
do {
101+
try process.run()
102+
process.waitUntilExit()
103+
104+
assert(process.terminationStatus == 0, "Process failed with exit code: \(process.terminationStatus)")
105+
} catch {
106+
print("[swift-java][command] Failed to extract Java sources for target: '\(target.name); Error: \(error)")
107+
}
108+
}
109+
110+
func log(message: @autoclosure () -> String) {
111+
if self.verbose {
112+
print("[swift-java] \(message())")
113+
}
114+
}
115+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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+
import Foundation
16+
import PackagePlugin
17+
18+
// Note: the JAVA_HOME environment variable must be set to point to where
19+
// Java is installed, e.g.,
20+
// Library/Java/JavaVirtualMachines/openjdk-21.jdk/Contents/Home.
21+
func findJavaHome() -> String {
22+
if let home = ProcessInfo.processInfo.environment["JAVA_HOME"] {
23+
return home
24+
}
25+
26+
// This is a workaround for envs (some IDEs) which have trouble with
27+
// picking up env variables during the build process
28+
let path = "\(FileManager.default.homeDirectoryForCurrentUser.path()).java_home"
29+
if let home = try? String(contentsOfFile: path, encoding: .utf8) {
30+
if let lastChar = home.last, lastChar.isNewline {
31+
return String(home.dropLast())
32+
}
33+
34+
return home
35+
}
36+
37+
fatalError("Please set the JAVA_HOME environment variable to point to where Java is installed.")
38+
}
39+
40+
func hasSwiftJavaConfig(target: Target) -> Bool {
41+
target.directory
42+
}

Plugins/JExtractSwiftPlugin/JExtractSwiftPlugin.swift

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ struct JExtractSwiftBuildToolPlugin: BuildToolPlugin {
2424
// so we cannot eliminate this deprecation warning.
2525
let sourceDir = target.directory.string
2626

27+
let toolURL = try context.tool(named: "JExtractSwiftTool").url
2728
let configuration = try readConfiguration(sourceDir: "\(sourceDir)")
2829

2930
// We use the the usual maven-style structure of "src/[generated|main|test]/java/..."
@@ -52,7 +53,7 @@ struct JExtractSwiftBuildToolPlugin: BuildToolPlugin {
5253
return [
5354
.prebuildCommand(
5455
displayName: "Generate Java wrappers for Swift types",
55-
executable: try context.tool(named: "JExtractSwiftTool").url,
56+
executable: toolURL,
5657
arguments: arguments,
5758
// inputFiles: [ configFile ] + swiftFiles,
5859
// outputFiles: outputJavaFiles
@@ -62,24 +63,3 @@ struct JExtractSwiftBuildToolPlugin: BuildToolPlugin {
6263
}
6364
}
6465

65-
// Note: the JAVA_HOME environment variable must be set to point to where
66-
// Java is installed, e.g.,
67-
// Library/Java/JavaVirtualMachines/openjdk-21.jdk/Contents/Home.
68-
func findJavaHome() -> String {
69-
if let home = ProcessInfo.processInfo.environment["JAVA_HOME"] {
70-
return home
71-
}
72-
73-
// This is a workaround for envs (some IDEs) which have trouble with
74-
// picking up env variables during the build process
75-
let path = "\(FileManager.default.homeDirectoryForCurrentUser.path()).java_home"
76-
if let home = try? String(contentsOfFile: path, encoding: .utf8) {
77-
if let lastChar = home.last, lastChar.isNewline {
78-
return String(home.dropLast())
79-
}
80-
81-
return home
82-
}
83-
84-
fatalError("Please set the JAVA_HOME environment variable to point to where Java is installed.")
85-
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
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+
import Foundation
16+
17+
/// Configuration for the JExtractSwift translation tool, provided on a per-target
18+
/// basis.
19+
struct Configuration: Codable {
20+
var javaPackage: String
21+
}
22+
23+
func readConfiguration(sourceDir: String) throws -> Configuration {
24+
let configFile = URL(filePath: sourceDir).appending(path: "JExtractSwift.config")
25+
do {
26+
let configData = try Data(contentsOf: configFile)
27+
return try JSONDecoder().decode(Configuration.self, from: configData)
28+
} catch {
29+
throw ConfigurationError(message: "Failed to parse JExtractSwift configuration at '\(configFile)!'", error: error)
30+
}
31+
}
32+
33+
struct ConfigurationError: Error {
34+
let message: String
35+
let error: any Error
36+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
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+
import Foundation
16+
17+
// Note: the JAVA_HOME environment variable must be set to point to where
18+
// Java is installed, e.g.,
19+
// Library/Java/JavaVirtualMachines/openjdk-21.jdk/Contents/Home.
20+
func findJavaHome() -> String {
21+
if let home = ProcessInfo.processInfo.environment["JAVA_HOME"] {
22+
return home
23+
}
24+
25+
// This is a workaround for envs (some IDEs) which have trouble with
26+
// picking up env variables during the build process
27+
let path = "\(FileManager.default.homeDirectoryForCurrentUser.path()).java_home"
28+
if let home = try? String(contentsOfFile: path, encoding: .utf8) {
29+
if let lastChar = home.last, lastChar.isNewline {
30+
return String(home.dropLast())
31+
}
32+
33+
return home
34+
}
35+
36+
fatalError("Please set the JAVA_HOME environment variable to point to where Java is installed.")
37+
}

Samples/JExtractPluginSampleApp/Package.swift

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -40,31 +40,32 @@ let javaIncludePath = "\(javaHome)/include"
4040
#endif
4141

4242
let package = Package(
43-
name: "JExtractPluginSampleApp",
44-
platforms: [
45-
.macOS(.v10_15),
46-
],
47-
products: [
48-
.library(
49-
name: "JExtractPluginSampleLib",
50-
type: .dynamic,
51-
targets: ["JExtractPluginSampleLib"]
52-
),
53-
],
54-
dependencies: [
55-
.package(name: "swift-java", path: "../../"),
56-
],
57-
targets: [
58-
.target(
59-
name: "JExtractPluginSampleLib",
60-
dependencies: [
61-
],
62-
swiftSettings: [
63-
.unsafeFlags(["-I\(javaIncludePath)", "-I\(javaPlatformIncludePath)"])
64-
],
65-
plugins: [
66-
.plugin(name: "JExtractSwiftPlugin", package: "swift-java"),
67-
]
68-
),
69-
]
43+
name: "JExtractPluginSampleApp",
44+
platforms: [
45+
.macOS(.v10_15)
46+
],
47+
products: [
48+
.library(
49+
name: "JExtractPluginSampleLib",
50+
type: .dynamic,
51+
targets: ["JExtractPluginSampleLib"]
52+
)
53+
],
54+
dependencies: [
55+
.package(name: "swift-java", path: "../../")
56+
],
57+
targets: [
58+
.target(
59+
name: "JExtractPluginSampleLib",
60+
dependencies: [],
61+
swiftSettings: [
62+
.unsafeFlags(["-I\(javaIncludePath)", "-I\(javaPlatformIncludePath)"])
63+
],
64+
plugins: [
65+
.plugin(name: "JExtractSwiftPlugin", package: "swift-java")
66+
,
67+
.plugin(name: "JExtractSwiftCommandPlugin", package: "swift-java")
68+
]
69+
)
70+
]
7071
)

0 commit comments

Comments
 (0)