255 lines
7.7 KiB
Markdown
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.
|