# gobject-generator - GIR-to-Swift Binding Generator Reads GObject Introspection (`.gir`) XML files and produces a Swift monorepo of low-level wrapper packages for GTK and its dependency stack (GLib, GObject, GIO, Pango, GDK, GSK, GTK, Adwaita, Soup, GStreamer, and more). A single invocation generates every configured package - Swift sources, C bridge targets, re-export umbrellas, and the root `Package.swift` - as a buildable SwiftPM workspace. ## Usage ```bash generator --monorepo-config config.toml --output ./Generated ``` ### Command-line arguments | Argument | Description | |---|---| | `--monorepo-config PATH` | **Required.** Path to the monorepo TOML configuration file. | | `--output DIR` | Root output directory for the generated monorepo (default: `.`). | | `--skip-report` | Write per-module skip reports (`skip-reports/.json`) and a `coverage-summary.json` to the output directory. | | `--smoke-target` | Add a `SmokeTests` test target to the generated `Package.swift`, depending on every generated module. | | `--format-config PATH` | Path to a `.swift-format` configuration file used to format generated output. | | `--help`, `-h` | Print usage information and exit. | ### Monorepo configuration file The `--monorepo-config` argument points to a TOML file describing every package to generate. Each `[packages.]` section declares a `.gir` file to process and optional per-package overrides. ```toml # Top-level output directory (can be overridden by --output on the command line). output_dir = "." # Each [packages.] section becomes one Swift module. # Packages are listed in dependency order (leaf dependencies first). [packages.GLib] gir = "/usr/share/gir-1.0/GLib-2.0.gir" [packages.GObject] gir = "/usr/share/gir-1.0/GObject-2.0.gir" concurrency = "mainActor" [packages.Gtk] gir = "/usr/share/gir-1.0/Gtk-4.0.gir" # Per-type overrides are placed under [packages..object.]. [packages.Gtk.object.Gtk.Widget] status = "generate" # "generate" | "manual" | "ignore" finalType = true concurrency = "mainActor" # "mainActor" | "sendable" | "none" version = "4.0" cfgCondition = "os(macOS)" # #if compilation condition [packages.Gtk.object.Gtk.Builder] generateBuilder = true ``` | Per-package key | Type | Description | |---|---|---| | `gir` | string | **Required.** Path to the `.gir` file to process. | | `concurrency` | string | Default concurrency model for all types in this package: `"mainActor"`, `"sendable"`, or `"none"`. | | Per-type override (`object.`) | Type | Description | |---|---|---| | `status` | string | Override generation status: `"generate"`, `"manual"`, or `"ignore"`. | | `finalType` | bool | Mark the generated class as `final`. | | `concurrency` | string | Per-type concurrency model (same values as the package-level key). | | `version` | string | Minimum version; type is only generated when targeting this version or later. | | `cfgCondition` | string | An `#if` compilation condition wrapping the generated code. | | `generateBuilder` | bool | Emit a builder-pattern struct for constructing this type. | ## Output structure ``` / ├── Package.swift ├── Sources/ │ ├── CGLib/ │ │ ├── CGLib.h # C umbrella header │ │ └── module.modulemap # Clang module map (pkg-config driven) │ ├── GLib/ │ │ ├── GLib.swift # Re-export umbrella (@_exported import) │ │ └── Generated/ │ │ ├── Array.swift │ │ ├── Error.swift │ │ └── ... │ ├── CGObject/ │ │ └── ... │ ├── GObject/ │ │ ├── GObject.swift │ │ └── Generated/ │ │ └── ... │ ├── CGtk/ │ │ └── ... │ └── Gtk/ │ ├── Gtk.swift │ └── Generated/ │ └── ... ``` - **`Package.swift`** - SwiftPM manifest with a `.systemLibrary` target per C bridge and a `.target` per Swift wrapper module. Dependencies between modules are resolved automatically from the GIR `` graph. - **`Sources/C/`** - One Clang module map and umbrella header per generated Swift module, wired to the native library via `pkgConfig`. - **`Sources//Generated/`** - One `.swift` file per generated type (class, protocol, enum, option set, callback typealias, free function). - **`Sources//.swift`** - A re-export umbrella importing every transitive dependency, so consumers only need a single `import Gtk`. ## User-defined test targets The generated `Package.swift` includes marker comments that preserve custom targets across regenerations: ```swift // === USER TARGETS - preserved across generations === // BEGIN_USER_TARGETS // END_USER_TARGETS ``` Add any custom `target()` entries (test targets, executables, plugins) between these markers. The generator splices the existing content back into the freshly generated `Package.swift` on every run. The markers must appear on their own lines and must not be nested. Example: ```swift // BEGIN_USER_TARGETS .testTarget(name: "MyIntegrationTests", dependencies: ["GLib", "Gtk"]), // END_USER_TARGETS ``` ## Example ### Input: `config.toml` ```toml output_dir = "." [packages.GLib] gir = "/usr/share/gir-1.0/GLib-2.0.gir" [packages.GObject] gir = "/usr/share/gir-1.0/GObject-2.0.gir" [packages.Gtk] gir = "/usr/share/gir-1.0/Gtk-4.0.gir" ``` ### Command ```bash generator --monorepo-config config.toml --output ./gen ``` ### Generated output ``` ./gen/ ├── Package.swift ├── Sources/ │ ├── CGLib/ │ │ ├── CGLib.h │ │ └── module.modulemap │ ├── GLib/ │ │ ├── GLib.swift │ │ └── Generated/ │ │ ├── Array.swift │ │ ├── Error.swift │ │ ├── ... │ │ └── Variant.swift │ ├── CGObject/ │ │ ├── CGObject.h │ │ └── module.modulemap │ ├── GObject/ │ │ ├── GObject.swift │ │ └── Generated/ │ │ ├── Binding.swift │ │ ├── Object.swift │ │ └── ... │ ├── CGtk/ │ │ ├── CGtk.h │ │ └── module.modulemap │ └── Gtk/ │ ├── Gtk.swift │ └── Generated/ │ ├── Application.swift │ ├── Widget.swift │ ├── Window.swift │ └── ... ``` ### Generated code sample ```swift // Gtk/Generated/Widget.swift /// The base class for all widgets. public final class Widget: GObject.InitiallyUnowned { let pointer: UnsafeMutableRawPointer init(takingOwnership pointer: UnsafeMutableRawPointer) { self.pointer = pointer } init(retaining pointer: UnsafeMutableRawPointer) { g_object_ref(pointer) self.pointer = pointer } deinit { g_object_unref(pointer) } public func show() { gtk_widget_show(pointer) } public var visible: Bool { get { gtk_widget_get_visible(pointer) != 0 } set { gtk_widget_set_visible(pointer, newValue ? 1 : 0) } } } ``` ## Building for development ```bash # Clone and build the generator git clone cd gobject-generator swift build # Run the test suite (unit + integration) swift test # Generate bindings from a config swift run generator --monorepo-config config.toml --output ./out # Format generated output (requires swift-format) swift run generator --monorepo-config config.toml --format-config .swift-format ``` ## License This project is licensed under the MIT License. See [LICENSE](LICENSE) for the full text.