# gobject-generator — GIR-to-Swift Binding Generator Reads GObject Introspection (`.gir`) XML files and produces low-level Swift wrapper libraries for GTK and its dependency stack. Each wrapper package is a self-contained SwiftPM project with a Clang module map for C interop and per-type Swift source files. ## Usage ```bash generator --gir-file /usr/share/gir-1.0/Gtk-4.0.gir --output ./Gtk ``` Library name and version are derived automatically from the GIR file's `` element. Override via `config.toml` (see below). ### Arguments | Argument | Description | Example | |---|---|---| | `--gir-file PATH` | Path to the `.gir` XML file to process (required). | `/usr/share/gir-1.0/Gtk-4.0.gir` | | `--output DIR` | Output directory for generated files (default: `.`). | `./Sources/GTK` | | `--config-toml PATH` | Path to `config.toml` for per-type config (default: `config.toml`). | `Sources/GTK/config.toml` | | `--namespace NAME` | Namespace to generate (for multi-namespace GIR files). | `Gtk` | | `--list-output-files` | Print expected output file paths and exit. | — | | `--girs-dirs DIRS` | Comma-separated list of directories to search for `.gir` files. | `/usr/share/gir-1.0,vendor/gir-files` | | `--external-libs LIBS` | Comma-separated external library names for link flags. | `Gdk,Gsk,Pango` | | `--generate TYPES` | Comma-separated list of types to generate (e.g. `Gtk.Widget,Gtk.Window`). When combined with `--generate-all`, this is ignored. | `Gtk.Widget,Gtk.Align` | | `--generate-all` | Generate all types found in the namespace. Default if `--generate` is omitted. | — | | `--manual TYPES` | Comma-separated types to mark as manually implemented (skipped during generation). | `Gtk.Buildable` | | `--ignore TYPES` | Comma-separated types to skip entirely. | `Gtk.Test` | | `--emit-single-file` | Emit a single concatenated Swift file instead of one file per type. | — | | `--help`, `-h` | Show help text. | — | ### config.toml Per-type configuration can be specified via a TOML file. Library name and version are auto-extracted from the GIR namespace. Example: ```toml target_directory = "Sources/GTK" girs_directories = ["/usr/share/gir-1.0"] external_libraries = ["Gdk-4.0", "Gsk-4.0"] generate = ["Gtk.Widget", "Gtk.Window", "Gtk.Button"] manual = ["Gtk.Buildable"] ignore = ["Gtk.Test"] [[objects]] name = "Gtk.Widget" concurrency = "mainActor" visibility = "public" [[objects]] name = "Gtk.Align" rename = "Alignment" ``` ### Generate all types ```bash generator --gir-file Gtk-4.0.gir --output ./Gtk --generate-all ``` ### Generate specific types ```bash generator --gir-file Gtk-4.0.gir --output ./Gtk \ --generate Gtk.Widget,Gtk.Window,Gtk.Button,Gtk.Align ## Output Structure ``` ./Gtk/ ├── Package.swift ├── Sources/ │ ├── CGtk/ │ │ ├── CGtk.h │ │ └── module.modulemap │ └── Gtk/ │ ├── Widget.swift │ ├── Window.swift │ ├── Button.swift │ ├── Align.swift │ └── ... ``` - **`Package.swift`** — SwiftPM manifest with a `systemLibrary` target (for C interop via pkgConfig) and a Swift target for the generated wrappers. - **`Sources/C/`** — Clang module map and umbrella header, derived from the GIR file's `` and `shared-library` attributes. - **`Sources//`** — One `.swift` file per generated type (class, protocol, enum, OptionSet, callback typealias, free function). ## Generated Code Example The following is a sample of generated output for a subset of GTK types: ```swift /// The base class for all widgets. /// /// It manages the widget lifecycle, layout, states and style. public final class Widget: GObject.InitiallyUnowned { let pointer: UnsafeMutableRawPointer public init(pointer: UnsafeMutableRawPointer) { g_object_ref_sink(pointer) self.pointer = pointer } deinit { g_object_unref(pointer) } public var halign: Align { get { var value = GValue() g_value_init(&value, G_TYPE_OBJECT) g_object_get_property(pointer, "halign", &value) let result = g_value_get_object(&value) g_value_unset(&value) return result } set { var value = GValue() g_value_init(&value, G_TYPE_OBJECT) g_value_set_object(&value, newValue) g_object_set_property(pointer, "halign", &value) g_value_unset(&value) } } public func show() { gtk_widget_show(pointer) } public func getVisible() -> Bool { return (gtk_widget_get_visible(pointer) != 0) } public func getParent() -> Widget? { return gtk_widget_get_parent(pointer).map { Widget(pointer: $0) } } public func connectDestroy(_ handler: @escaping () -> Void) -> Int { let boxed = Unmanaged.passRetained(handler as AnyObject).toOpaque() let callback: @convention(c) (UnsafeMutableRawPointer?, UnsafeMutableRawPointer?) -> Void = { (_, data) in let stored = Unmanaged.fromOpaque(data!).takeUnretainedValue() as! () -> Void stored() } let destroy: @convention(c) (UnsafeMutableRawPointer?) -> Void = { Unmanaged.fromOpaque($0!).release() } return Int(g_signal_connect_data(pointer, "destroy", callback, boxed, destroy, 0)) } } ``` ```swift /// stretch to fill all space, but align the baseline. public enum Align: Int { case fill = 0 case start = 1 case end = 2 case center = 3 case baselineFill = 4 case baseline = 4 case baselineCenter = 5 } ``` ## What Gets Generated | GIR Type | Swift Output | |---|---| | `` | `final class` with `UnsafeMutableRawPointer` storage, ref-counted `init`/`deinit`, GValue-based properties, C function-call methods, `g_signal_connect_data` signal handlers, convenience constructors | | `` | `protocol` with method requirements and property requirements | | `` | `enum: Int` with camelCase cases | | `` | `struct: OptionSet` with `rawValue: Int` and bit-shifted constants | | `` | `typealias` with `@convention(c)` | | `` | `public func` wrapping the C function call with type conversion | ## Generated Package Buildability The generated `Package.swift` includes a `systemLibrary` target with `pkgConfig` for the native library. The host system must have the corresponding development packages installed (e.g. `libgtk-4-dev` for Gtk, `libglib2.0-dev` for GLib) for the generated package to compile. ## Development ```bash # Build the generator swift build # Run the test suite swift test # Format generated code (uses .swift-format config) swift format lint --configuration .swift-format path/to/generated/file.swift ```