1
0
Fork 0
gobject-generator/README.md

255 lines
7.7 KiB
Markdown

# 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/<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.
```toml
# 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:
```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 <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](LICENSE) for the
full text.