Novolis Docs
novolis-codegen / specs/binding-codegen-library/initial-idea-v2.md

Binding CodeGen Library — Specification v2

dotnetcodegennovolis

Status: implementation baseline (supersedes initial-idea.md for build work) Summary: summary.md · Analysis: analysis.md

Locked decisions

TopicDecision
Parity gateT1 AST-normalized equivalence
MilestoneC-ABI emit library wired through Raylib and Audio
Binding modelL0–L3 stack with CompanionDeclaration
Manifest authorityC# fragments defined by the consumer (Novolis.Raylib.Manifests)
IOIFileSystem via CodegenEnvironment (tests use MockFileSystem)
InliningShared façade emitter owns expression-body inlining; hooks retain XML docs + EndDrawing behavior
Native scopeC ABI: C libraries and C++ extern "C" shims; no C++ class bindings

L0–L3 binding stack

LayerRoleRaylib examples
L0Native DLLsraylib.dll, novolis_imgui.dll
L1Generated interopRaylib6Native.g.cs, ImguiShimExports.g.cs
L2Hand companions (declared, not emitted)GuiControls, ImguiShimHost, Utf8StringMarshaller
L3Generated façadesGraphics.g.cs, Gui.g.cs

Merge points must include L2 companion declarations for validation; façades reference companions (GuiControls.*), not shim pointers directly.

Packages (novolis-codegen)

PackageContents
Novolis.CodeGen.PipelineIPipelineStep, PipelineRunner, skip/cache, result.json
Novolis.CodeGen.BindingsTyped NativeSignature fragments, C-ABI emitters, IBindingEmitter, BindingCodegenExecutor, CodegenEnvironment
Novolis.CodeGen.Bindings.RoslynICodegenHook, default BindingCodegenHost, RoslynEmitWriter, CompilationUnitComparer

Consumer manifests (C#)

Raylib defines fragments in codegen/Novolis.Raylib.Manifests/*.cs and exposes them via RaylibBindingManifestSource.Instance.

Fragment kindRaylib idGenerated output
InteropExportsraylib6Raylib6Native.g.cs
ShimExportsimgui, rayguiImguiShimExports.g.cs, RayguiShimExports.g.cs
DebugConfigraylib-debugRaylibDebugFrameHooks.g.cs
FacadeTypesfacades, hud, gui, rayguiRuntime / Raygui façades

Manifest fingerprints use ManifestFingerprint.Sha256Hex(fragment) — not JSON serialization.

API surface

  • IPipelineLayout — injectable paths (raylib: RaylibPipelineLayout)
  • NativeSignature, NativeType, NativeParameter — typed C ABI return and named parameter metadata
  • LibraryImportEmitter, DynamicExportsEmitter, FacadeForwardEmitter — shared string emitters registered per EmitStrategy
  • BindingCodegenHost<TPhase, TContext> — default consumer job runner over RoslynEmitWriter
  • IBindingCodegenHost — consumer entry (RaylibBindingCodegenHost, AudioBindingCodegenHost)
  • BindingEmitContext — only config channel for hooks (no disk reads)
  • CompanionDeclaration — required hand-written files per stack
  • CodegenEnvironment — IFileSystem + repo root for all codegen IO

Parity

TierCheck
T0ManifestSha256 header line (fragment fingerprint)
T1Gate: CompilationUnitComparer structural match
T2Byte-identical (not required)

14 generated outputs — see summary.md.

Default codegen host

BindingCodegenHost<TPhase, TContext> validates companions, filters optional jobs, fingerprints fragments, invokes the selected string emitter, and preserves the existing parse → hook → format → write path. Raylib and Audio hosts only compose jobs, hooks, and consumer-owned verification:

  • Pipeline step_06_codegen
  • MSBuild GenerateRaylibBindings
  • Novolis.Raylib.CodeGen generate

Regenerate hint: dotnet run --project codegen/Novolis.Raylib.Pipeline -- run generate

Implemented consumers

  • Raylib uses typed signatures for LibraryImport, ImGui/Raygui dynamic export tables, debug hooks, and one façade job per generated type.
  • Audio uses the same LibraryImport and façade emitters for its nine na_* imports. Speech and voice catalogs remain Audio-local.

Deferred

  • Phase 6: Automated façade doc enrichment back into C# manifest sources
  • Backlog: NativePack generator and BindingSurface sugar