1
0
Fork 0
GIR-to-Swift binding generator for GTK 4/libadwaita and its GObject dependency stack (GLib, GObject, GIO, GDK, GSK, Pango, Cairo, Soup, GStreamer, GdkPixbuf). Modelled on gtk-rs/gir.
Find a file
2026-08-11 23:47:16 -04:00
regression Bind the GIO async pattern as Swift async methods 2026-08-11 23:47:16 -04:00
scripts Update generator tier tooling 2026-08-11 17:39:02 -04:00
Sources Bind the GIO async pattern as Swift async methods 2026-08-11 23:47:16 -04:00
Tests Bind the GIO async pattern as Swift async methods 2026-08-11 23:47:16 -04:00
.gitignore Initial commit: SwiftGtkGen GIR-to-Swift binding generator 2026-07-01 03:27:41 -04:00
.swift-format Initial commit: SwiftGtkGen GIR-to-Swift binding generator 2026-07-01 03:27:41 -04:00
LICENSE Rewrite README and add MIT license 2026-07-21 21:10:05 -04:00
Package.resolved Re-point plugins and re-enable lint gate (E6/E7) 2026-07-20 23:44:49 -04:00
Package.swift Rename swift-gtk-gen to gobject-generator with generator binary 2026-07-21 18:51:15 -04:00
README.md Rewrite README and add MIT license 2026-07-21 21:10:05 -04:00

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

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/<Module>.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.<Name>] section declares a .gir file to process and optional per-package overrides.

# Top-level output directory (can be overridden by --output on the command line).
output_dir = "."

# Each [packages.<Name>] 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.<Name>.object.<TypeName>].
[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.<TypeName>) 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

<output-dir>/
├── 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 <include> graph.
  • Sources/C<Module>/ - One Clang module map and umbrella header per generated Swift module, wired to the native library via pkgConfig.
  • Sources/<Module>/Generated/ - One .swift file per generated type (class, protocol, enum, option set, callback typealias, free function).
  • Sources/<Module>/<Module>.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:

// === 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:

// BEGIN_USER_TARGETS
        .testTarget(name: "MyIntegrationTests", dependencies: ["GLib", "Gtk"]),
// END_USER_TARGETS

Example

Input: config.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

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

// 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

# Clone and build the generator
git clone <repo-url>
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 for the full text.