Rewrite README and add MIT license
This commit is contained in:
parent
b13f7976cc
commit
8bfeea2ed2
2 changed files with 218 additions and 133 deletions
21
LICENSE
Normal file
21
LICENSE
Normal 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
324
README.md
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue