pipeline

package
v0.19.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 11, 2026 License: MIT Imports: 17 Imported by: 0

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:

  1. Topologically sorts frameworks by superclass dependency (Kahn's algorithm) so a class's embedding type is always emitted before the class that embeds it.
  2. Detects import cycles between frameworks and breaks them by substituting unsafe.Pointer for the minimum-weight set of cross-framework type references ([resolveBlockedImports]).
  3. 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

func EmitObjCClassHierarchy(metadataPaths []string, outputPath string) error

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

func LoadAll(paths []string, modulePrefix string) (*Registry, error)

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

func (r *Registry) SuperclassIndex() map[string]bool

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL