Add link modes: consume a dependency as a Zig import, not just a C-ABI link - #6
Merged
Conversation
…I link
azazel modelled every `deps` edge as a C-ABI link: each module became its own
compiled artifact and dependents linked it over `pub export fn` / `extern fn`.
That is correct for shared libraries and C/C++ interop, but for a pure
Zig-to-Zig edge it means one artifact and one link step per module, plus a build
graph that Zig re-validates step by step on every build. On a 150-module graph a
no-op build took ~4.5s and a one-module change ~4.9s, scaling linearly with the
module count.
Add a `link` field to `#Module`, one of "abi" (default, the existing behaviour)
or "import". An `import` dependency merges into each dependent as a plain Zig
module reached with `@import("name")`: one compilation, no separate artifact, no
link step. The default stays "abi", so every existing project builds unchanged.
A `shared` module is forced to "abi" by the schema.
Measured through the real pipeline on a 150-module graph:
operation abi import
clean build 12.7s 5.2s
no-op build 4.5s 0.3s
one-module change 4.9s 0.5s
import mode is roughly 10x faster on incremental builds and stays flat as the
module count grows, because the whole subgraph is a single compilation that Zig
caches and links once.
- schema.cue: #Link and the `link` field, with `shared` pinned to "abi".
- export.cue, gen_build_spec.sh: thread `link` through to build_spec.zig.
- build.zig: create a module for every declared module, a compile step only for
real artifacts, and wire import deps with addImport / abi deps with
linkLibrary. Install only real artifacts.
- build_spec_test.zig: assert shared is abi and that an import dep is a static
module.
- examples/05-import-mode: a runnable import-edge project.
- docs/WIKI.md, README.md: document `link` and the source contract.
- Sync the shared schema.cue / gen_build_spec.sh into examples 01-04.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds a
linkfield to#Module, one of"abi"(default) or"import"."abi"is the current behaviour: the module is a separately compiled artifact linked over the C ABI (pub export fn/extern fn). Required for shared libraries and C/C++ interop."import"merges the module into each dependent as a plain Zig module reached with@import("name"). One compilation, no separate artifact, no link step.The default stays
"abi", so every existing project builds unchanged. Asharedmodule is forced to"abi"by the schema.Why
Every
depsedge was a C-ABI link, so a pure Zig-to-Zig graph paid for one artifact and one link step per module, plus a build graph Zig re-validates step by step each build. That overhead scales linearly with the module count.Measured through the real CUE -> build_spec.zig -> zig build pipeline on a 150-module graph:
abiimportimport mode is ~10x faster on incremental builds and stays flat as the module count grows, because the subgraph is a single compilation that Zig caches and links once.
Changes
schema.cue:#Linkand thelinkfield,sharedpinned to"abi".export.cue,gen_build_spec.sh: threadlinkthrough to the generated spec.build.zig: module per declared module, compile step only for real artifacts, wire import deps withaddImportand abi deps withlinkLibrary, install only real artifacts.build_spec_test.zig: two invariants (shared is abi; an import dep is static).examples/05-import-mode/: a runnable import-edge project.docs/WIKI.md,README.md: documentlinkand the source contract.schema.cue/gen_build_spec.shinto examples 01-04.Verification
zig buildunchanged;zig build test58/58 pass (2 new).🤖 Generated with Claude Code