Documentation
¶
Overview ¶
Package scanner drives the first phase of the code-generation pipeline.
It invokes xcrun clang with -ast-dump=json on a framework's umbrella header, unmarshals the resulting Clang JSON AST, and walks it to produce a [meta.FrameworkMeta] value that captures the framework's complete public API: classes, protocols, enums, structs, free functions, extern constants, block types, and typedefs.
Extraction is restricted to declarations whose source file belongs to the named framework's own headers (filter.go), so re-exported types from other frameworks are skipped and attributed to their true owner during the load phase.
Key entry points:
Index ¶
- Constants
- func CLibraryBackend(name string) string
- func CLibraryHeader(sdkPath, name string) string
- func CLibraryHeaderDir(sdkPath, name string) string
- func CLibraryHeaderRelative(name string) string
- func ClangVersion() (string, error)
- func DetectSubFrameworkNames(bundlePath string) []string
- func DumpRecordLayouts(sdkPath, framework, arch string) (map[string]RecordLayout, error)
- func Extract(root *ASTNode, sdkPath, frameworkName, sdkVersion, arch string, ...) *macosplatformmetadata.FrameworkMeta
- func FrameworkBundlePath(sdkPath, name string) string
- func FrameworkHeader(sdkPath, framework string) string
- func FrameworkHeaderDir(sdkPath, framework string) string
- func IsCLibrary(sdkPath, name string) bool
- func IsCLibraryName(name string) bool
- func IsSubFramework(name string) bool
- func IsSwiftOnly(bundlePath string) bool
- func ListCLibraries(sdkPath string) ([]string, error)
- func ListFrameworks(sdkPath string) ([]string, error)
- func LoadCLibrariesFile(path string) (bool, error)
- func LoadScanConfigFile(path string) (bool, error)
- func SDKPath() (string, error)
- func SDKVersion() (string, error)
- func SubFrameworkParts(name string) (parent, child string)
- func XcodeVersion() (string, error)
- type ASTNode
- type ASTRef
- type ASTType
- type CLibraryDef
- type IncludedFromRef
- type Location
- type RawValue
- type RecordLayout
- type ScanConfig
- type SrcRange
Constants ¶
const BackendPurego = "purego"
BackendPurego is the CLibraryDef.Backend value selecting the purego pipeline.
Variables ¶
This section is empty.
Functions ¶
func CLibraryBackend ¶ added in v0.19.0
CLibraryBackend returns the configured binding backend for a registered C library: BackendPurego, or "" for the default CGo backend (also returned for unknown names).
func CLibraryHeader ¶
CLibraryHeader returns the umbrella header path for a known Apple C library. If the library definition specifies a custom Header path, that is used; otherwise the default {Name}/{Name}.h convention applies.
func CLibraryHeaderDir ¶
CLibraryHeaderDir returns the filter path for a known Apple C library. This is the path prefix used to decide whether an AST node belongs to the library. It may be a directory (e.g. "bsm/") or an exact file (e.g. "sandbox.h") depending on how the library's headers are laid out.
func CLibraryHeaderRelative ¶
CLibraryHeaderRelative returns the umbrella header include path for a known Apple C library, relative to {SDK}/usr/include/ and slash-separated — the form used in a generated "#include <…>" directive (e.g. "compression.h", "os/log.h", "bsm/libbsm.h"). Defaults to the {Name}/{Name}.h convention when the library definition has no custom Header.
func ClangVersion ¶
ClangVersion returns the version line of the clang binary that DumpAST invokes (e.g. "Apple clang version 21.0.0 (clang-2100.3.9.2)"). Recorded in scanned metadata because clang releases have changed AST output in ways that affect extraction (Clang 21 stopped emitting availability versions).
func DetectSubFrameworkNames ¶
DetectSubFrameworkNames returns the names of sub-frameworks inside bundlePath/Frameworks/ that have a valid umbrella header. Returns nil when the framework is not an umbrella.
func DumpRecordLayouts ¶ added in v0.18.0
func DumpRecordLayouts(sdkPath, framework, arch string) (map[string]RecordLayout, error)
DumpRecordLayouts invokes xcrun clang with -fdump-record-layouts-simple on the framework's umbrella header and returns the authoritative record layouts keyed by bare record name (struct/union tag or typedef name). Record layout is target-dependent, so the target/isysroot/header args mirror DumpAST exactly. The dump lands on stdout during codegen (-emit-llvm), so stdout is parsed. A record with a non-byte-aligned field offset (a bitfield) or an unnamed tag is omitted; the emitter falls back to its computed layout for those. clang only lays out records used by value, so pointer-only-referenced structs are absent.
func Extract ¶
func Extract(root *ASTNode, sdkPath, frameworkName, sdkVersion, arch string, layouts map[string]RecordLayout) *macosplatformmetadata.FrameworkMeta
Extract walks the Clang AST root node and produces a FrameworkMeta containing only declarations that originate from the named framework's headers.
func FrameworkBundlePath ¶
FrameworkBundlePath returns the path to a framework's .framework bundle. It handles both top-level frameworks and "Parent/Child" sub-frameworks.
func FrameworkHeader ¶
FrameworkHeader returns the path to the umbrella header for a framework. framework may be "Name" (top-level) or "Parent/Child" (sub-framework). Falls back to the C library header path for known Apple C libraries. A per-framework ScanConfig.HeaderOverride (SDK-relative slash path) takes precedence over the default <Framework>.h naming convention, allowing frameworks that ship no conventional umbrella (e.g. IOKit) to be scanned.
func FrameworkHeaderDir ¶
FrameworkHeaderDir returns the directory containing all headers for a framework. framework may be "Name" (top-level) or "Parent/Child" (sub-framework). Falls back to the C library header directory for known Apple C libraries.
func IsCLibrary ¶
IsCLibrary reports whether name is a known Apple C library whose umbrella header exists on the filesystem.
func IsCLibraryName ¶
IsCLibraryName reports whether name is registered as a known Apple C library, without performing any filesystem check. Use this when an SDK path is not available (e.g. when constructing metadata output paths during a scan).
func IsSubFramework ¶
IsSubFramework reports whether name uses "Parent/Child" sub-framework notation.
func IsSwiftOnly ¶
IsSwiftOnly reports whether the framework at bundlePath has no ObjC surface and is implemented entirely in Swift (indicated by a .swiftmodule directory).
func ListCLibraries ¶
ListCLibraries returns the sorted names of known Apple C libraries present in sdkPath. If sdkPath is empty it is auto-detected via xcrun.
func ListFrameworks ¶
ListFrameworks returns the sorted names of all frameworks available in sdkPath that have a valid umbrella header (Framework.framework/Headers/Framework.h). If sdkPath is empty it is auto-detected via xcrun. Sub-frameworks nested inside umbrella frameworks (e.g. Carbon/HIToolbox) are included using "Parent/Child" notation so the scanner can locate them.
func LoadCLibrariesFile ¶
LoadCLibrariesFile replaces the active C library registry with the contents of a JSON config file (map of library name → CLibraryDef). Adding a new Apple C library is then a data change plus re-scan, not a Go change. Returns false without error when the file does not exist.
func LoadScanConfigFile ¶
LoadScanConfigFile replaces the active per-framework scan configuration with the contents of a JSON config file (map of framework name → ScanConfig). Returns false without error when the file does not exist.
func SDKVersion ¶
SDKVersion returns the macOS SDK version string (e.g. "26.5").
func SubFrameworkParts ¶
SubFrameworkParts splits a "Parent/Child" name into parent and child.
func XcodeVersion ¶
XcodeVersion returns the active Xcode version and build, joined on one line (e.g. "Xcode 26.0 Build version 17A321"). Recorded in scanned metadata as toolchain provenance.
Types ¶
type ASTNode ¶
type ASTNode struct {
ID string `json:"id"`
Kind string `json:"kind"`
Loc *Location `json:"loc"`
Range *SrcRange `json:"range"`
Name string `json:"name"`
MangledName string `json:"mangledName"`
Type *ASTType `json:"type"`
ReturnType *ASTType `json:"returnType"`
Inner []ASTNode `json:"inner"`
// PreviousDecl is the hex ID string of the previous declaration of this
// name in the same translation unit. When set, this node is a redeclaration
// (e.g. @class Foo; repeated after the canonical @interface Foo...@end, or
// an empty @class Foo; that precedes the canonical definition). Used in
// extractClass to distinguish canonical definitions from foreign-class
// forward declarations.
PreviousDecl string `json:"previousDecl"`
// ObjCInterfaceDecl / ObjCCategoryDecl
Super *ASTRef `json:"super"`
Protocols []ASTRef `json:"protocols"`
// ObjCCategoryDecl: the class this category extends
Interface *ASTRef `json:"interface"`
// ObjCMethodDecl — Clang uses "instance": true for instance methods,
// absence of the field (or false) means class method.
IsInstance bool `json:"instance"`
IsVariadic bool `json:"variadic"`
IsImplicit bool `json:"implicit"`
// ObjCPropertyDecl
Getter *ASTRef `json:"getter"`
Setter *ASTRef `json:"setter"`
// property attribute flags: "readonly", "copy", "weak", "assign", etc.
PropertyAttributes []string `json:"propertyAttributes"`
// EnumDecl
FixedUnderlyingType *ASTType `json:"fixedUnderlyingType"`
// RecordDecl (struct/union)
TagUsed string `json:"tagUsed"` // "struct" or "union"
CompleteDefinition bool `json:"completeDefinition"` // true for full record decl, false/missing for forward decl
// VarDecl
StorageClass string `json:"storageClass"` // "extern"
// IntegerLiteral / FloatingLiteral / ConstantExpr
// Clang emits numeric literals as JSON numbers; use RawMessage to handle both
// number and string variants uniformly.
Value RawValue `json:"value"`
// Availability
Availability []ASTNode `json:"availability"` // AvailabilityAttr nodes
// AvailabilityAttr fields
Platform string `json:"platform"` // "macos", "ios"
Introduced string `json:"introduced"`
Deprecated string `json:"deprecated"`
Obsoleted string `json:"obsoleted"`
Message string `json:"message"`
// ObjCTypeParamDecl — generic type params on a class
// appears as inner nodes of ObjCInterfaceDecl
Bound *ASTType `json:"bound"` // upper bound (usually "id")
// Nullability qualifier attached to a type
NullabilityQual string `json:"nullabilityQual"` // "nullable", "nonnull", "unspecified"
// SwiftNameAttr carries the NS_SWIFT_NAME value; appears as an inner node.
SwiftName string `json:"swiftName,omitempty"`
}
ASTNode is a node in the Clang JSON AST produced by clang -ast-dump=json. Only fields we actually use are decoded; unknown fields are silently ignored.
type CLibraryDef ¶
type CLibraryDef struct {
// LinkLib is the dylib name passed to -l (e.g. "EndpointSecurity" → -lEndpointSecurity).
LinkLib string `json:"link_lib"`
// Header is the umbrella header path relative to {SDK}/usr/include/.
// Empty means use the default {Name}/{Name}.h convention.
Header string `json:"header,omitempty"`
// HeaderDir is the filter path relative to {SDK}/usr/include/ used to decide
// whether an AST node belongs to this library. Empty means derive from Header.
// Use a directory path (e.g. "bsm/") to accept all headers under that directory,
// or a file path (e.g. "sandbox.h") to match only that exact file.
HeaderDir string `json:"header_dir,omitempty"`
// ShimHeader is a repo-relative path to a hand-maintained prototype header
// for libraries that ship a linkable .tbd stub in the SDK but no public
// header (private dylibs such as IOReport). When set it takes precedence
// over Header/HeaderDir: the scan parses this file, the node filter accepts
// only declarations made in it, and the bridge emitter ships a copy inside
// the generated package's bridge/ directory.
ShimHeader string `json:"shim_header,omitempty"`
// Backend selects the binding backend for this library: "cgo" (default when
// empty) emits the ObjC-shim bridge via the CGo pipeline; "purego" emits
// dlopen/RegisterLibFunc bindings via the purego frameworks pipeline. The
// per-library key is the migration ratchet — libraries flip one at a time.
Backend string `json:"backend,omitempty"`
}
CLibraryDef describes a known Apple C library under {SDK}/usr/include/.
type IncludedFromRef ¶
type IncludedFromRef struct {
File string `json:"file"`
}
IncludedFromRef holds the file that directly includes the file containing a source location. Clang emits this when the declaration file is not the translation unit root.
type Location ¶
type Location struct {
FilePath string `json:"file"`
Line int `json:"line"`
Col int `json:"col"`
// When the loc is a macro expansion the actual file is in ExpansionLoc
ExpansionLoc *Location `json:"expansionLoc"`
// Spelling location (pre-macro-expansion)
SpellingLoc *Location `json:"spellingLoc"`
// IncludedFrom is the file that directly includes the file this loc is in.
// Present when loc.file is absent (Clang cursor optimisation) or when Clang
// wants to indicate the include chain.
IncludedFrom *IncludedFromRef `json:"includedFrom"`
}
func (*Location) IncludedFromFile ¶
IncludedFromFile returns the path of the file that directly includes the file this location is in, or "" if none was recorded. Used by the framework filter to determine true framework ownership when loc.file is absent.
func (*Location) ResolvedFile ¶
ResolvedFile returns the most useful file path from this location, unwrapping macro expansions to find the real header file. For macro-expanded declarations (NS_ENUM, NS_OPTIONS, etc.) the expansion location is the call site in the SDK header, while the spelling location is the macro definition inside CoreFoundation. We want the call site.
func (*Location) ResolvedLine ¶
ResolvedLine returns the source line number, preferring spellingLoc over expansionLoc.
type RawValue ¶
type RawValue string
RawValue holds an AST literal value which Clang may emit as a JSON number or as a JSON string. It normalises both to a plain string.
func (RawValue) MarshalJSON ¶
MarshalJSON writes the value as a JSON string.
func (*RawValue) UnmarshalJSON ¶
type RecordLayout ¶ added in v0.18.0
RecordLayout is a C record's authoritative ABI layout from clang: the total size and each field's offset, in BYTES.
type ScanConfig ¶
type ScanConfig struct {
// ExtraIncludeDirs lists additional directories (relative to the SDK root,
// slash-separated) whose headers count as belonging to this framework.
ExtraIncludeDirs []string `json:"extra_include_dirs,omitempty"`
// HeaderOverride is the SDK-relative slash-separated path to the entry
// header to pass to clang, for frameworks that do not ship a conventional
// <Framework>.framework/Headers/<Framework>.h umbrella (e.g. IOKit, which
// only exposes individual headers). When set it overrides the default
// umbrella path computed by FrameworkHeader.
HeaderOverride string `json:"header_override,omitempty"`
}
ScanConfig holds per-framework scan customisations.