Skip to content

Extract mangled names from .swiftinterface rather than using nm #27

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Oct 10, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,9 @@ define make_swiftinterface
-emit-module-interface-path ${JEXTRACT_BUILD_DIR}/${$@_MODULE}/${$@_FILENAME}.swiftinterface \
-emit-module-path ${JEXTRACT_BUILD_DIR}/${$@_MODULE}/${$@_FILENAME}.swiftmodule \
-enable-library-evolution \
-Xfrontend -abi-comments-in-module-interface \
-module-name ${$@_MODULE} \
-Xfrontend -abi-comments-in-module-interface \
Sources/${$@_MODULE}/${$@_FILENAME}.swift
echo "Generated: ${JEXTRACT_BUILD_DIR}/${$@_MODULE}/${$@_FILENAME}.swiftinterface"
endef
Expand Down
9 changes: 0 additions & 9 deletions Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 4 additions & 21 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ func findJavaHome() -> String {
// picking up env variables during the build process
let path = "\(FileManager.default.homeDirectoryForCurrentUser.path()).java_home"
if let home = try? String(contentsOfFile: path) {
if let lastChar = home.last, lastChar.isNewline {
return String(home.dropLast())
}

return home
}

Expand Down Expand Up @@ -97,7 +101,6 @@ let package = Package(
dependencies: [
.package(url: "https://github.com/swiftlang/swift-syntax.git", branch: "main"),
.package(url: "https://github.com/apple/swift-argument-parser", from: "1.5.0"),
.package(url: "https://github.com/apple/swift-system", from: "1.0.0"),
],
targets: [
.macro(
Expand Down Expand Up @@ -195,33 +198,13 @@ let package = Package(
]
),

// FIXME: This is swift-foundation's proposed Subprocess; remove when available
// https://github.com/apple/swift-foundation/pull/439
.target(
name: "_Subprocess",
dependencies: [
"_SubprocessCShims",
.product(name: "SystemPackage", package: "swift-system"),
]
),
.target(
name: "_SubprocessCShims",
cSettings: [
.define(
"_CRT_SECURE_NO_WARNINGS",
.when(platforms: [.windows])
)
]
),

.target(
name: "JExtractSwift",
dependencies: [
.product(name: "SwiftBasicFormat", package: "swift-syntax"),
.product(name: "SwiftSyntax", package: "swift-syntax"),
.product(name: "SwiftSyntaxBuilder", package: "swift-syntax"),
.product(name: "ArgumentParser", package: "swift-argument-parser"),
"_Subprocess",
"JavaTypes",
]
),
Expand Down
24 changes: 0 additions & 24 deletions Sources/JExtractSwift/Convenience/Collection+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,30 +11,6 @@
//
//===----------------------------------------------------------------------===//

extension Collection {

@_alwaysEmitIntoClient
public func _mapAsync<T, E>(
_ transform: (Element) async throws(E) -> T
) async throws(E) -> [T] {
let initialCapacity = underestimatedCount
var result = Array<T>()
result.reserveCapacity(initialCapacity)

var iterator = self.makeIterator()

// Add elements up to the initial capacity without checking for regrowth.
for _ in 0..<initialCapacity {
result.append(try await transform(iterator.next()!))
}
// Add remaining elements, if any.
while let element = iterator.next() {
result.append(try await transform(element))
}
return Array(result)
}
}

public extension Dictionary {
/// Same values, corresponding to mapped keys.
func mapKeys<Transformed>(
Expand Down
6 changes: 3 additions & 3 deletions Sources/JExtractSwift/Swift2Java.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import SwiftSyntax
import SwiftSyntaxBuilder

/// Command-line utility, similar to `jextract` to export Swift types to Java.
public struct SwiftToJava: AsyncParsableCommand {
public struct SwiftToJava: ParsableCommand {
public init() {}

public static var _commandName: String {
Expand All @@ -40,7 +40,7 @@ public struct SwiftToJava: AsyncParsableCommand {
@Argument(help: "The Swift interface files to export to Java.")
var swiftInterfaceFiles: [String]

public func run() async throws {
public func run() throws {
let interfaceFiles = self.swiftInterfaceFiles.dropFirst()
print("Interface files: \(interfaceFiles)")

Expand All @@ -55,7 +55,7 @@ public struct SwiftToJava: AsyncParsableCommand {
print("[\(fileNo)/\(interfaceFiles.count)] Importing module '\(swiftModule)', interface file: \(interfaceFile)")
defer { fileNo += 1 }

try await translator.analyze(swiftInterfacePath: interfaceFile)
try translator.analyze(swiftInterfacePath: interfaceFile)
try translator.writeImportedTypesTo(outputDirectory: outputDirectory)

print("[\(fileNo)/\(interfaceFiles.count)] Imported interface file: \(interfaceFile) " + "done.".green)
Expand Down
59 changes: 3 additions & 56 deletions Sources/JExtractSwift/Swift2JavaTranslator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ extension Swift2JavaTranslator {
public func analyze(
swiftInterfacePath: String,
text: String? = nil
) async throws {
) throws {
if text == nil {
precondition(
swiftInterfacePath.hasSuffix(Self.SWIFT_INTERFACE_SUFFIX),
Expand All @@ -84,12 +84,12 @@ extension Swift2JavaTranslator {
log.trace("Analyze: \(swiftInterfacePath)")
let text = try text ?? String(contentsOfFile: swiftInterfacePath)

try await analyzeSwiftInterface(interfaceFilePath: swiftInterfacePath, text: text)
try analyzeSwiftInterface(interfaceFilePath: swiftInterfacePath, text: text)

log.info("Done processing: \(swiftInterfacePath)")
}

package func analyzeSwiftInterface(interfaceFilePath: String, text: String) async throws {
package func analyzeSwiftInterface(interfaceFilePath: String, text: String) throws {
assert(interfaceFilePath.hasSuffix(Self.SWIFT_INTERFACE_SUFFIX))

let sourceFileSyntax = Parser.parse(source: text)
Expand All @@ -104,59 +104,6 @@ extension Swift2JavaTranslator {
translator: self
)
visitor.walk(sourceFileSyntax)

try await self.postProcessImportedDecls()
}

public func postProcessImportedDecls() async throws {
log.info(
"Post process imported decls...",
metadata: [
"types": "\(importedTypes.count)",
"global/funcs": "\(importedGlobalFuncs.count)",
]
)

// FIXME: the use of dylibs to get symbols is a hack we need to remove and replace with interfaces containing mangled names
let dylibPath = ".build/arm64-apple-macosx/debug/lib\(swiftModuleName).dylib"
guard var dylib = SwiftDylib(path: dylibPath) else {
log.warning(
"""
Unable to find mangled names for imported symbols. Dylib not found: \(dylibPath) This method of obtaining symbols is a workaround; it will be removed.
"""
)
return
}

importedGlobalFuncs = try await importedGlobalFuncs._mapAsync { funcDecl in
let funcDecl = try await dylib.fillInMethodMangledName(funcDecl)
log.info("Mapped method '\(funcDecl.identifier)' -> '\(funcDecl.swiftMangledName)'")
return funcDecl
}

importedTypes = Dictionary(uniqueKeysWithValues: try await importedTypes._mapAsync { (tyName, tyDecl) in
var tyDecl = tyDecl
log.info("Mapping type: \(tyDecl.swiftTypeName)")

tyDecl = try await dylib.fillInTypeMangledName(tyDecl)

log.info("Mapping members of: \(tyDecl.swiftTypeName)")
tyDecl.initializers = try await tyDecl.initializers._mapAsync { initDecl in
dylib.log.logLevel = .trace

let initDecl = try await dylib.fillInAllocatingInitMangledName(initDecl)
log.info("Mapped initializer '\(initDecl.identifier)' -> '\(initDecl.swiftMangledName)'")
return initDecl
}

tyDecl.methods = try await tyDecl.methods._mapAsync { funcDecl in
let funcDecl = try await dylib.fillInMethodMangledName(funcDecl)
log.info("Mapped method '\(funcDecl.identifier)' -> '\(funcDecl.swiftMangledName)'")
return funcDecl
}

return (tyName, tyDecl)
})
}
}

Expand Down
Loading