1
0
Fork 0
gobject-generator/README.md

192 lines
6.8 KiB
Markdown

# SwiftGtkGen — 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
swift-gtk-gen --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 `<namespace>` 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
swift-gtk-gen --gir-file Gtk-4.0.gir --output ./Gtk --generate-all
```
### Generate specific types
```bash
swift-gtk-gen --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<Library>/`** — Clang module map and umbrella header, derived from the GIR file's `<c:include>` and `shared-library` attributes.
- **`Sources/<Library>/`** — 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<AnyObject>.fromOpaque(data!).takeUnretainedValue() as! () -> Void
stored()
}
let destroy: @convention(c) (UnsafeMutableRawPointer?) -> Void = {
Unmanaged<AnyObject>.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 |
|---|---|
| `<class>` | `final class` with `UnsafeMutableRawPointer` storage, ref-counted `init`/`deinit`, GValue-based properties, C function-call methods, `g_signal_connect_data` signal handlers, convenience constructors |
| `<interface>` | `protocol` with method requirements and property requirements |
| `<enumeration>` | `enum: Int` with camelCase cases |
| `<bitfield>` | `struct: OptionSet` with `rawValue: Int` and bit-shifted constants |
| `<callback>` | `typealias` with `@convention(c)` |
| `<function>` | `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
```