Skip to content

Commit 8d517bf

Browse files
ktosomadsodgaardpelekon
authored
Fix jextract subdirectory handling in input Sources (#456)
* config: log-level should encode as string * Properly handle nested directories of Swift Sources in jextract * wip * fix test and cleanup (#1) Co-authored-by: pelekon <13712101+pelekon@users.noreply.github.com> Co-authored-by: Konrad `ktoso` Malawski <konrad_malawski@apple.com> Co-authored-by: Bartłomiej Bukowiecki <pelekon@users.noreply.github.com> Fix `allowGlobalAutomatic` mode for interfaces (#466) Fix JNI caching for native threads (#464) fix extensions (#473) fix protocols that return java classes. (#479) --------- Co-authored-by: Mads Odgaard <mads@madsodgaard.com> Co-authored-by: pelekon <13712101+pelekon@users.noreply.github.com> Co-authored-by: Bartłomiej Bukowiecki <pelekon@users.noreply.github.com>
1 parent c6a56cd commit 8d517bf

14 files changed

Lines changed: 253 additions & 61 deletions

File tree

‎Plugins/JExtractSwiftPlugin/JExtractSwiftPlugin.swift‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ struct JExtractSwiftBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin {
9696
$0.pathExtension == "swift"
9797
}
9898

99-
// Output Swift files are just Java filename based converted to Swift files one-to-one
99+
// Output files are flattened filenames of the inputs, with the appended +SwiftJava suffix.
100100
var outputSwiftFiles: [URL] = swiftFiles.compactMap { sourceFileURL in
101101
guard sourceFileURL.isFileURL else {
102102
return nil as URL?
@@ -107,7 +107,6 @@ struct JExtractSwiftBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin {
107107
fatalError("Could not get relative path for source file \(sourceFilePath)")
108108
}
109109
let outputURL = outputSwiftDirectory
110-
.appending(path: String(sourceFilePath.dropFirst(sourceDir.count).dropLast(sourceFileURL.lastPathComponent.count + 1)))
111110

112111
let inputFileName = sourceFileURL.deletingPathExtension().lastPathComponent
113112
return outputURL.appending(path: "\(inputFileName)+SwiftJava.swift")

‎Plugins/SwiftJavaPlugin/SwiftJavaPlugin.swift‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,10 @@ struct SwiftJavaBuildToolPlugin: SwiftJavaPluginProtocol, BuildToolPlugin {
173173
if !outputSwiftFiles.isEmpty {
174174
let displayName = "Wrapping \(classes.count) Java classes in Swift target '\(sourceModule.name)'"
175175
log("Prepared: \(displayName)")
176+
177+
for f in outputSwiftFiles {
178+
log("Swift output file: \(f)")
179+
}
176180
commands += [
177181
.buildCommand(
178182
displayName: displayName,
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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+
public final class SwiftTypeInSubDirectory {
16+
public init() {}
17+
18+
public func hello() -> Int {
19+
12
20+
}
21+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
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+
package com.example.swift;
16+
17+
import org.junit.jupiter.api.Disabled;
18+
import org.junit.jupiter.api.Test;
19+
import org.swift.swiftkit.core.SwiftLibraries;
20+
import org.swift.swiftkit.ffm.AllocatingSwiftArena;
21+
22+
import java.io.File;
23+
import java.util.stream.Stream;
24+
25+
import static org.junit.jupiter.api.Assertions.*;
26+
27+
public class SwiftTypeInSubDirectoryTest {
28+
29+
@Test
30+
void test_MySwiftClass_voidMethod() {
31+
try (var arena = AllocatingSwiftArena.ofConfined()) {
32+
SwiftTypeInSubDirectory o = SwiftTypeInSubDirectory.init(arena);
33+
var num = o.hello();
34+
assertEquals(12, num);
35+
}
36+
}
37+
38+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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+
public final class SwiftTypeInSubDirectory {
16+
public init() {}
17+
18+
public func hello() -> Int64 {
19+
12
20+
}
21+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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+
package com.example.swift;
16+
17+
import org.junit.jupiter.api.Test;
18+
import org.swift.swiftkit.core.SwiftArena;
19+
20+
import static org.junit.jupiter.api.Assertions.*;
21+
22+
public class SwiftTypeInSubDirectoryTest {
23+
24+
@Test
25+
void test_SwiftTypeInSubDirectory_hello() {
26+
try (var arena = SwiftArena.ofConfined()) {
27+
SwiftTypeInSubDirectory o = SwiftTypeInSubDirectory.init(arena);
28+
var num = o.hello();
29+
assertEquals(12, num);
30+
}
31+
}
32+
33+
}

‎Sources/JExtractSwiftLib/CodePrinter.swift‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@
1414

1515
import Foundation
1616

17-
let PATH_SEPARATOR = "/" // TODO: Windows
17+
#if os(Windows)
18+
let PATH_SEPARATOR = "\\"
19+
#else
20+
let PATH_SEPARATOR = "/"
21+
#endif
1822

1923
public struct CodePrinter {
2024
var contents: String = ""

‎Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator+SwiftThunkPrinting.swift‎

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,15 @@ extension FFMSwift2JavaGenerator {
2222
}
2323

2424
package func writeSwiftExpectedEmptySources() throws {
25-
let pendingFileCount = self.expectedOutputSwiftFiles.count
25+
let pendingFileCount = self.expectedOutputSwiftFileNames.count
2626
guard pendingFileCount > 0 else {
2727
return // no need to write any empty files, yay
2828
}
2929

30-
print("[swift-java] Write empty [\(self.expectedOutputSwiftFiles.count)] 'expected' files in: \(swiftOutputDirectory)/")
30+
log.info("[swift-java] Write empty [\(self.expectedOutputSwiftFileNames.count)] 'expected' files in: \(swiftOutputDirectory)/")
3131

32-
for expectedFileName in self.expectedOutputSwiftFiles {
33-
log.debug("Write SwiftPM-'expected' empty file: \(expectedFileName.bold)")
34-
32+
for expectedFileName in self.expectedOutputSwiftFileNames {
33+
log.info("Write SwiftPM-'expected' empty file: \(expectedFileName.bold)")
3534

3635
var printer = CodePrinter()
3736
printer.print("// Empty file generated on purpose")
@@ -55,7 +54,7 @@ extension FFMSwift2JavaGenerator {
5554
javaPackagePath: nil,
5655
filename: moduleFilename) {
5756
log.info("Generated: \(moduleFilenameBase.bold).swift (at \(outputFile.absoluteString))")
58-
self.expectedOutputSwiftFiles.remove(moduleFilename)
57+
self.expectedOutputSwiftFileNames.remove(moduleFilename)
5958
}
6059
} catch {
6160
log.warning("Failed to write to Swift thunks: \(moduleFilename)")
@@ -93,7 +92,7 @@ extension FFMSwift2JavaGenerator {
9392
javaPackagePath: nil,
9493
filename: filename) {
9594
log.info("Done writing Swift thunks to: \(outputFile.absoluteString)")
96-
self.expectedOutputSwiftFiles.remove(filename)
95+
self.expectedOutputSwiftFileNames.remove(filename)
9796
}
9897
} catch {
9998
log.warning("Failed to write to Swift thunks: \(filename), error: \(error)")

‎Sources/JExtractSwiftLib/FFM/FFMSwift2JavaGenerator.swift‎

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,10 @@ package class FFMSwift2JavaGenerator: Swift2JavaGenerator {
3939

4040
/// Because we need to write empty files for SwiftPM, keep track which files we didn't write yet,
4141
/// and write an empty file for those.
42-
var expectedOutputSwiftFiles: Set<String>
42+
///
43+
/// Since Swift files in SwiftPM builds needs to be unique, we use this fact to flatten paths into plain names here.
44+
/// For uniqueness checking "did we write this file already", just checking the name should be sufficient.
45+
var expectedOutputSwiftFileNames: Set<String>
4346

4447
package init(
4548
config: Configuration,
@@ -57,19 +60,22 @@ package class FFMSwift2JavaGenerator: Swift2JavaGenerator {
5760
self.javaOutputDirectory = javaOutputDirectory
5861
self.lookupContext = translator.lookupContext
5962

60-
// If we are forced to write empty files, construct the expected outputs
63+
// If we are forced to write empty files, construct the expected outputs.
64+
// It is sufficient to use file names only, since SwiftPM requires names to be unique within a module anyway.
6165
if translator.config.writeEmptyFiles ?? false {
62-
self.expectedOutputSwiftFiles = Set(translator.inputs.compactMap { (input) -> String? in
63-
guard let filePathPart = input.path.split(separator: "/\(translator.swiftModuleName)/").last else {
66+
self.expectedOutputSwiftFileNames = Set(translator.inputs.compactMap { (input) -> String? in
67+
guard let fileName = input.path.split(separator: PATH_SEPARATOR).last else {
6468
return nil
6569
}
66-
67-
return String(filePathPart.replacing(".swift", with: "+SwiftJava.swift"))
70+
guard fileName.hasSuffix(".swift") else {
71+
return nil
72+
}
73+
return String(fileName.replacing(".swift", with: "+SwiftJava.swift"))
6874
})
69-
self.expectedOutputSwiftFiles.insert("\(translator.swiftModuleName)Module+SwiftJava.swift")
70-
self.expectedOutputSwiftFiles.insert("Foundation+SwiftJava.swift")
75+
self.expectedOutputSwiftFileNames.insert("\(translator.swiftModuleName)Module+SwiftJava.swift")
76+
self.expectedOutputSwiftFileNames.insert("Foundation+SwiftJava.swift")
7177
} else {
72-
self.expectedOutputSwiftFiles = []
78+
self.expectedOutputSwiftFileNames = []
7379
}
7480
}
7581

‎Sources/JExtractSwiftLib/JNI/JNISwift2JavaGenerator+SwiftThunkPrinting.swift‎

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,15 @@ extension JNISwift2JavaGenerator {
2626
}
2727

2828
package func writeSwiftExpectedEmptySources() throws {
29-
let pendingFileCount = self.expectedOutputSwiftFiles.count
29+
let pendingFileCount = self.expectedOutputSwiftFileNames.count
3030
guard pendingFileCount > 0 else {
3131
return // no need to write any empty files, yay
3232
}
33-
34-
print("[swift-java] Write empty [\(self.expectedOutputSwiftFiles.count)] 'expected' files in: \(swiftOutputDirectory)/")
35-
36-
for expectedFileName in self.expectedOutputSwiftFiles {
37-
logger.debug("Write SwiftPM-'expected' empty file: \(expectedFileName.bold)")
3833

34+
logger.info("[swift-java] Write empty [\(self.expectedOutputSwiftFileNames.count)] 'expected' files in: \(swiftOutputDirectory)/")
35+
36+
for expectedFileName in self.expectedOutputSwiftFileNames {
37+
logger.info("Write SwiftPM-'expected' empty file: \(expectedFileName.bold)")
3938

4039
var printer = CodePrinter()
4140
printer.print("// Empty file generated on purpose")
@@ -61,7 +60,7 @@ extension JNISwift2JavaGenerator {
6160
filename: moduleFilename
6261
) {
6362
logger.info("Generated: \(moduleFilenameBase.bold).swift (at \(outputFile.absoluteString))")
64-
self.expectedOutputSwiftFiles.remove(moduleFilename)
63+
self.expectedOutputSwiftFileNames.remove(moduleFilename)
6564
}
6665

6766
// === All types
@@ -96,7 +95,7 @@ extension JNISwift2JavaGenerator {
9695
javaPackagePath: nil,
9796
filename: filename) {
9897
logger.info("Done writing Swift thunks to: \(outputFile.absoluteString)")
99-
self.expectedOutputSwiftFiles.remove(filename)
98+
self.expectedOutputSwiftFileNames.remove(filename)
10099
}
101100
} catch {
102101
logger.warning("Failed to write to Swift thunks: \(filename), error: \(error)")

0 commit comments

Comments
 (0)