Extracted from gtk-swift monorepo. Previous history contains 38 commits across the full Phase 1 development including GIR XML parsing, IR model, analysis engine, code generation, CLI, plugins, and documentation.
75 lines
2.9 KiB
Swift
75 lines
2.9 KiB
Swift
import PackagePlugin
|
|
import Foundation
|
|
|
|
/// SwiftPM build tool plugin that automatically generates Swift GIR bindings.
|
|
///
|
|
/// Inspects each target for a `Config.swift` file and `.gir` files, then
|
|
/// invokes the `swift-gtk-gen` executable to produce Swift source before compilation.
|
|
/// Targets without a config or GIR files are silently skipped.
|
|
@main
|
|
struct SwiftGtkGenBuildPlugin: BuildToolPlugin {
|
|
/// Creates build commands for GIR code generation for the given target.
|
|
///
|
|
/// Returns a single `.buildCommand` that runs `swift-gtk-gen` with the target's
|
|
/// config and GIR files as inputs. If the target has no `Config.swift` or
|
|
/// no `.gir` files, returns an empty array.
|
|
///
|
|
/// - Parameters:
|
|
/// - context: The plugin context providing access to tools and work directories.
|
|
/// - target: The target to generate bindings for.
|
|
/// - Returns: An array of build commands (empty if no GIR files present).
|
|
func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] {
|
|
let targetDir = target.directoryURL
|
|
let configURL = targetDir.appending(path: "Config.swift")
|
|
|
|
guard FileManager.default.fileExists(atPath: configURL.path()) else {
|
|
return []
|
|
}
|
|
|
|
let executable = try context.tool(named: "swift-gtk-gen")
|
|
|
|
let girFiles = findGIRFiles(in: targetDir)
|
|
guard !girFiles.isEmpty else { return [] }
|
|
|
|
let outputDir = context.pluginWorkDirectoryURL
|
|
|
|
return [
|
|
.buildCommand(
|
|
displayName: "Generating \(target.name) GIR bindings...",
|
|
executable: executable.url,
|
|
arguments: [
|
|
"--config", configURL.path(),
|
|
"--library", target.name,
|
|
"--version", "4.0",
|
|
"--output", outputDir.appending(path: target.name).path(),
|
|
],
|
|
inputFiles: [configURL] + girFiles,
|
|
outputFiles: [
|
|
outputDir.appending(path: "\(target.name)/Generated.swift")
|
|
]
|
|
)
|
|
]
|
|
}
|
|
|
|
/// Recursively finds all `.gir` files in the given directory.
|
|
///
|
|
/// Uses a directory enumerator to walk the file tree and collect URLs
|
|
/// whose path extension is `"gir"`.
|
|
///
|
|
/// - Parameter directory: The root directory to search.
|
|
/// - Returns: An array of URLs pointing to discovered `.gir` files.
|
|
private func findGIRFiles(in directory: URL) -> [URL] {
|
|
guard let enumerator = FileManager.default.enumerator(
|
|
at: directory, includingPropertiesForKeys: [.isRegularFileKey]
|
|
) else {
|
|
return []
|
|
}
|
|
var girFiles: [URL] = []
|
|
for case let fileURL as URL in enumerator {
|
|
if fileURL.pathExtension == "gir" {
|
|
girFiles.append(fileURL)
|
|
}
|
|
}
|
|
return girFiles
|
|
}
|
|
}
|