1
0
Fork 0

Rewrite README and add MIT license

This commit is contained in:
Brendan Szymanski 2026-07-21 20:30:01 -04:00
parent b13f7976cc
commit 8bfeea2ed2
2 changed files with 218 additions and 133 deletions

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 gobject-generator contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

324
README.md
View file

@ -1,102 +1,218 @@
# gobject-generator GIR-to-Swift Binding Generator
# gobject-generator - 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.
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 --gir-file /usr/share/gir-1.0/Gtk-4.0.gir --output ./Gtk
generator --monorepo-config config.toml --output ./Generated
```
Library name and version are derived automatically from the GIR file's `<namespace>` element. Override via `config.toml` (see below).
### Command-line arguments
### 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. |
| 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. | — |
### Monorepo configuration file
### config.toml
Per-type configuration can be specified via a TOML file. Library name and version are auto-extracted from the GIR namespace. Example:
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
target_directory = "Sources/GTK"
girs_directories = ["/usr/share/gir-1.0"]
external_libraries = ["Gdk-4.0", "Gsk-4.0"]
# Top-level output directory (can be overridden by --output on the command line).
output_dir = "."
generate = ["Gtk.Widget", "Gtk.Window", "Gtk.Button"]
manual = ["Gtk.Buildable"]
ignore = ["Gtk.Test"]
# Each [packages.<Name>] section becomes one Swift module.
# Packages are listed in dependency order (leaf dependencies first).
[[objects]]
name = "Gtk.Widget"
[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"
visibility = "public"
[[objects]]
name = "Gtk.Align"
rename = "Alignment"
[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
```
### Generate all types
| 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"`. |
```bash
generator --gir-file Gtk-4.0.gir --output ./Gtk --generate-all
```
| 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. |
### Generate specific types
```bash
generator --gir-file Gtk-4.0.gir --output ./Gtk \
--generate Gtk.Widget,Gtk.Window,Gtk.Button,Gtk.Align
## Output Structure
## Output structure
```
./Gtk/
<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
│ ├── 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:
### Generated code sample
```swift
// Gtk/Generated/Widget.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)
init(takingOwnership pointer: UnsafeMutableRawPointer) {
self.pointer = pointer
}
init(retaining pointer: UnsafeMutableRawPointer) {
g_object_ref(pointer)
self.pointer = pointer
}
@ -104,88 +220,36 @@ public final class Widget: GObject.InitiallyUnowned {
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))
public var visible: Bool {
get { gtk_widget_get_visible(pointer) != 0 }
set { gtk_widget_set_visible(pointer, newValue ? 1 : 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
## Building for development
```bash
# Build the generator
# Clone and build the generator
git clone <repo-url>
cd gobject-generator
swift build
# Run the test suite
# Run the test suite (unit + integration)
swift test
# Format generated code (uses .swift-format config)
swift format lint --configuration .swift-format path/to/generated/file.swift
# 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.