Documentation
¶
Overview ¶
Package pipeline orchestrates the load and generate phases of the code-generation pipeline.
Loading ¶
LoadAll reads one or more .gometa.json files produced by the scanner and builds a Registry. The registry resolves cross-framework concerns that cannot be determined per-framework in isolation:
- Class ownership: the framework with the fewest non-zero methods for a class name wins ("fewest methods wins" heuristic), preventing re-exported declarations in umbrella headers from stealing ownership.
- Protocol and enum ownership: scored by member count; ties broken by name-prefix match against the framework name.
- Superclass cycle detection: a DFS validates that no class is its own ancestor before generation begins.
Generation ¶
[Generate] consumes a Registry and a [Config] and writes the frameworks/ tree. Before writing it:
- Topologically sorts frameworks by superclass dependency (Kahn's algorithm) so a class's embedding type is always emitted before the class that embeds it.
- Detects import cycles between frameworks and breaks them by substituting unsafe.Pointer for the minimum-weight set of cross-framework type references ([resolveBlockedImports]).
- Removes stale .go and bridge files from the output directory before writing new ones.
The [Config] struct controls output directory, module prefix, verbosity, and which frameworks to include or skip.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func EmitObjCClassHierarchy ¶
EmitObjCClassHierarchy reads all .gometa.json files in metadataPaths, derives the canonical superclass and owning framework for every ObjC class, and writes the result to outputPath as a committed Go source file containing ObjCClassSuperclassIndex and ObjCClassFrameworkIndex.
Canonical ownership is determined by "fewest non-zero methods wins" — the same heuristic used by LoadAll. The output carries no darwin build constraint and is the authoritative ObjC class hierarchy for the code generator's inherited-method filter and foreign-extension resolution.
func GenerateBindings ¶
func GenerateBindings(cfg BindingsConfig) error
GenerateBindings writes the raw C library packages, emitted in topological dependency order. The libraries output directory is wiped before generation so renamed or removed libraries do not leave stale packages behind.
func GenerateIdiomaticLibraries ¶ added in v0.5.0
func GenerateIdiomaticLibraries(cfg IdiomaticConfig) error
GenerateIdiomaticLibraries emits the opinionated idiomatic wrapper layer for every CGo C-library package (framework.LinkLib != "") into OutDir/<name>/. It mirrors the frameworks idiomatic pipeline but targets the CGo libraries, wrapping the already-clean raw bindings with handle-method/free-function wrappers and reusing the spec/slice/async scaffolding for any class-bearing idiolib.
Types ¶
type BindingsConfig ¶
type BindingsConfig struct {
// Registry is the combined metadata for all frameworks.
Registry *Registry
// LibrariesOutDir is the root output directory for C library packages.
// Canonical value: <repo-root>/bindings/internal/raw/libraries
LibrariesOutDir string
// Verbose enables diagnostic output for unsafe.Pointer type degradations.
Verbose bool
// Strict returns an error when any type degrades to unsafe.Pointer.
Strict bool
// IsNSStringOverloads enables Go-string convenience overloads for NSString * params.
IsNSStringOverloads bool
// DiagnosticsSink, when non-nil, receives every type-degradation diagnostic
// recorded by the type mapper. The CLI uses this to enforce a committed
// diagnostics baseline.
DiagnosticsSink *[]string
// LibraryFilter, when non-nil, restricts library emission (LinkLib != "")
// to the metas it accepts. The cgo→purego migration ratchet passes a filter
// rejecting purego-backed libraries, which are emitted by the purego
// pipeline into the same output tree instead. When set, LibrariesOutDir is
// NOT wiped wholesale — rejected libraries' package dirs are left alone.
LibraryFilter func(name string) bool
}
BindingsConfig controls raw Go binding generation for the C library packages. ObjC frameworks are generated by the purego pipeline (internal/codegen/frameworks/pipeline); metas without a LinkLib are ignored here.
type IdiomaticConfig ¶ added in v0.5.0
type IdiomaticConfig struct {
Registry *Registry
OutDir string // output root, e.g. ./bindings/libraries
Libraries []string // optional case-insensitive filter; empty = all libraries
Verbose bool
// RawSourceRoot is the directory holding the raw C-library packages the
// idiomatic layer wraps and re-exports (one <name>/ subdirectory each).
// Defaults to ./bindings/libraries when empty. The alias emitter reads each
// raw package's emitted source from here to re-export its exported symbols.
RawSourceRoot string
}
IdiomaticConfig configures GenerateIdiomaticLibraries.
type Registry ¶
type Registry struct {
Frameworks []*macosplatformmetadata.FrameworkMeta
ClassNameIndex map[string]bool // all class names across all loaded frameworks
GenericClasses map[string]bool // classes with ObjC generic params
// GenericParamIndex maps a generic class name to its ordered list of
// ObjC generic type parameter names (e.g. "NSArray" → ["ObjectType"],
// "NSDictionary" → ["KeyType", "ObjectType"]). Used by the bridge emitter
// to substitute placeholders in block-type casts on foreign-extension
// methods (categories defined on classes owned by another framework).
GenericParamIndex map[string][]string
OwnerIndex map[string]string // className → framework name (e.g. "NSString" → "Foundation")
// ProtocolIndex maps protocol name → owning framework (e.g. "NSCopying" → "Foundation").
// Used by the protocol emitter to resolve cross-framework parent protocol embeds.
ProtocolIndex map[string]string
// ProtocolProxyIndex maps protocol name → owning framework for protocols that
// have generated proxy types. Currently mirrors ProtocolIndex (every protocol
// gets a proxy). Used by the type mapper to resolve return-position id<Protocol>
// to *<GoProtoName>Proxy instead of unsafe.Pointer.
ProtocolProxyIndex map[string]string
// EnumIndex maps enum type name → owning framework (e.g. "VZVirtualMachineState" → "Virtualization").
// Used to resolve enum-typed return values that would otherwise fall through to unsafe.Pointer.
EnumIndex map[string]string
// LocalEnums maps framework name → the set of enum type names it declares
// locally. An enum whose header is shared by several libraries (e.g.
// xpc_listener_create_flags_t, pulled in by both xpc and oslog) is emitted
// in every declaring package, so a reference from a declaring framework
// must resolve to the LOCAL copy — qualifying it against the global
// EnumIndex owner manufactures a cross-package import (xpc → oslog), which
// on the purego backend drags a still-cgo library's cgo dependency into an
// otherwise-pure-Go package.
LocalEnums map[string]map[string]bool
// EnumGoTypeIndex maps enum type name → underlying Go integer type (e.g. "int64", "uint64").
// Used by the bridge emitter to produce correct C integer casts for enum-typed arguments.
EnumGoTypeIndex map[string]string
// TypedefIndex maps typedef name → target ObjC qualType, merged across all frameworks.
// e.g. "VZMemorySize" → "NSInteger", "AVMIDINoteDuration" → "double"
// Used by the typemap as a last-resort fallback before degrading to unsafe.Pointer.
TypedefIndex map[string]string
// TypedefOwnerIndex maps typedef name → the framework that defined it
// (e.g. "CFRunLoopRef" → "CoreFoundation"). Used by cycle detection so that
// typedef-based cross-framework references (CF opaque pointers like CFArrayRef)
// contribute import edges, not just class/enum references.
TypedefOwnerIndex map[string]string
// StructIndex maps a struct name (CGSize, CGRect, NSOperatingSystemVersion,
// ether_addr_t, …) to the framework that owns the complete definition.
// Used by the type mapper to resolve value-type struct references as
// `<packageName>.<Name>` (or bare `<Name>` when same-framework) instead of falling
// through to unsafe.Pointer. Population prefers the first metadata entry
// with non-empty fields — forward-declared/placeholder entries from
// transitively-included headers do not claim ownership.
StructIndex map[string]string
// CFTypeIndex maps framework-specific CF opaque typedef names to
// their owning framework. These are CF-style reference types (e.g. CFHostRef,
// CFHTTPMessageRef from CFNetwork) that are defined outside CoreFoundation
// and therefore not in cfTypedefSet. The mapper routes them to
// *<pkgAlias>.TypedefName rather than the corefoundation package.
CFTypeIndex map[string]string
// ClassIndex maps every class name to its full definition across all loaded frameworks.
// Used by the class emitter to walk cross-framework superclass chains when building
// struct embedding hierarchies and value-chain constructors.
ClassIndex map[string]macosplatformmetadata.Class
// ModulePrefix is the Go module path prefix for framework packages,
// e.g. "github.com/deploymenttheory/go-bindings-macosplatform/frameworks".
// Cross-framework import paths are built as ModulePrefix + "/" + pkgName.
ModulePrefix string
}
Registry holds combined metadata from multiple frameworks. It is the single source of truth for cross-framework type resolution: OwnerIndex tells every emitter which Go package owns each ObjC class name, enabling precise import statements rather than unsafe.Pointer fallbacks.
func LoadAll ¶
LoadAll reads one or more .gometa.json files and builds a Registry. paths may be individual .gometa.json files or directories; directories are scanned one level deep for all *.gometa.json files. When a directory contains multiple arch variants, arm64 is preferred.
func (*Registry) SuperclassIndex ¶
SuperclassIndex returns the set of class names that appear as the Super field of at least one other class across all loaded frameworks. This identifies classes that Apple itself subclasses — the population that SubclassSpec targets.