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.
154 lines
6.5 KiB
Swift
154 lines
6.5 KiB
Swift
import Foundation
|
|
import SwiftGtkGenCore
|
|
|
|
/// Command-line interface for the GIR-to-Swift binding generator.
|
|
///
|
|
/// Parses command-line arguments, invokes the GIR parser, analyzer, and code
|
|
/// generator, then writes the resulting Swift source to a file. Designed as
|
|
/// the subprocess entry point invoked by both the build tool plugin and the
|
|
/// command plugin.
|
|
@main
|
|
struct SwiftGtkGenCLI {
|
|
/// Program entry point. Parses arguments, generates code, and writes output.
|
|
static func main() {
|
|
let args = parseArguments()
|
|
if args.showHelp {
|
|
printHelp()
|
|
return
|
|
}
|
|
|
|
do {
|
|
let parser = GIRParser()
|
|
let primaryGIR = try parser.parse(fileURL: URL(fileURLWithPath: args.girFile))
|
|
|
|
let generateList = args.generateAll ? [] : args.generate
|
|
let config = GenerationConfig(
|
|
library: args.library,
|
|
version: args.version,
|
|
girsDirectories: args.girsDirs,
|
|
targetDirectory: args.output,
|
|
externalLibraries: args.externalLibs,
|
|
generate: generateList,
|
|
manual: args.manual,
|
|
ignore: args.ignore,
|
|
objects: []
|
|
)
|
|
|
|
let analyzer = Analyzer(config: config)
|
|
let analysis = analyzer.analyze(repository: primaryGIR)
|
|
|
|
let generator = CodeGenerator(config: config)
|
|
|
|
let outputDir = URL(fileURLWithPath: args.output)
|
|
|
|
if args.emitSingleFile {
|
|
let output = try generator.generate(repository: primaryGIR, analysis: analysis)
|
|
try FileManager.default.createDirectory(at: outputDir, withIntermediateDirectories: true)
|
|
let outputFile = outputDir.appendingPathComponent("\(config.library).swift")
|
|
try output.write(to: outputFile, atomically: true, encoding: .utf8)
|
|
print("Generated \(outputFile.path)")
|
|
} else {
|
|
let files = try generator.generateFiles(repository: primaryGIR, analysis: analysis)
|
|
let sourcesDir = outputDir.appendingPathComponent("Sources/\(config.library)")
|
|
try FileManager.default.createDirectory(at: sourcesDir, withIntermediateDirectories: true)
|
|
|
|
for (fileName, content) in files.sorted(by: { $0.key < $1.key }) {
|
|
let fileURL = sourcesDir.appendingPathComponent(fileName)
|
|
try content.write(to: fileURL, atomically: true, encoding: .utf8)
|
|
print("Generated \(fileURL.path)")
|
|
}
|
|
}
|
|
|
|
let scaffolding = CodeGenerator.generatePackageScaffolding(config: config, repository: primaryGIR)
|
|
for (relativePath, content) in scaffolding.sorted(by: { $0.key < $1.key }) {
|
|
let fileURL = outputDir.appendingPathComponent(relativePath)
|
|
try FileManager.default.createDirectory(at: fileURL.deletingLastPathComponent(), withIntermediateDirectories: true)
|
|
try content.write(to: fileURL, atomically: true, encoding: .utf8)
|
|
print("Generated \(fileURL.path)")
|
|
}
|
|
} catch {
|
|
print("Error: \(error)")
|
|
exit(1)
|
|
}
|
|
}
|
|
|
|
/// Parsed command-line arguments for the GIR generator CLI.
|
|
struct CLIArgs {
|
|
var showHelp: Bool = false
|
|
var emitSingleFile: Bool = false
|
|
var girFile: String = ""
|
|
var library: String = ""
|
|
var version: String = ""
|
|
var output: String = "."
|
|
var girsDirs: [String] = []
|
|
var externalLibs: [String] = []
|
|
var generate: [String] = []
|
|
var generateAll: Bool = false
|
|
var manual: [String] = []
|
|
var ignore: [String] = []
|
|
}
|
|
|
|
/// Parses command-line arguments into a ``CLIArgs`` value.
|
|
///
|
|
/// Supports the flags `--help`, `--gir-file`, `--library`, `--version`,
|
|
/// `--output`, `--girs-dirs`, `--external-libs`, `--generate`, `--manual`,
|
|
/// and `--ignore`. Multi-value flags (`--girs-dirs`, etc.) accept
|
|
/// comma-separated lists.
|
|
///
|
|
/// - Returns: A populated ``CLIArgs`` extracted from `CommandLine.arguments`.
|
|
static func parseArguments() -> CLIArgs {
|
|
var args = Array(CommandLine.arguments.dropFirst())
|
|
var cli = CLIArgs()
|
|
|
|
while let flag = args.first {
|
|
args.removeFirst()
|
|
switch flag {
|
|
case "--emit-single-file":
|
|
cli.emitSingleFile = true
|
|
case "--help", "-h":
|
|
cli.showHelp = true
|
|
case "--gir-file":
|
|
cli.girFile = args.removeFirst()
|
|
case "--library":
|
|
cli.library = args.removeFirst()
|
|
case "--version":
|
|
cli.version = args.removeFirst()
|
|
case "--output":
|
|
cli.output = args.removeFirst()
|
|
case "--girs-dirs":
|
|
cli.girsDirs = args.removeFirst().components(separatedBy: ",")
|
|
case "--external-libs":
|
|
cli.externalLibs = args.removeFirst().components(separatedBy: ",")
|
|
case "--generate-all":
|
|
cli.generateAll = true
|
|
case "--generate":
|
|
cli.generate = args.removeFirst().components(separatedBy: ",")
|
|
case "--manual":
|
|
cli.manual = args.removeFirst().components(separatedBy: ",")
|
|
case "--ignore":
|
|
cli.ignore = args.removeFirst().components(separatedBy: ",")
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
|
|
return cli
|
|
}
|
|
|
|
/// Prints usage information and the list of accepted flags to stdout.
|
|
static func printHelp() {
|
|
print("Usage: swift-gtk-gen [options]")
|
|
print(" --gir-file PATH Path to the .gir file")
|
|
print(" --library NAME GIR library namespace (e.g., GLib)")
|
|
print(" --version VER GIR version (e.g., 2.0)")
|
|
print(" --output DIR Output directory (default: .)")
|
|
print(" --girs-dirs DIRS Comma-separated GIR directories")
|
|
print(" --external-libs LIBS Comma-separated external libraries")
|
|
print(" --generate TYPES Comma-separated types to generate")
|
|
print(" --generate-all Generate all types in the namespace")
|
|
print(" --manual TYPES Comma-separated types to mark manual")
|
|
print(" --ignore TYPES Comma-separated types to ignore")
|
|
print(" --emit-single-file Emit a single file instead of per-type files")
|
|
print(" --help, -h Show this help")
|
|
}
|
|
}
|