9.6 KiB
9.6 KiB
013 — Build & Packaging
- Status: Draft
- Normative language:
MUST,MUST NOT,SHOULD,SHOULD NOT, andMAYare to be interpreted as described in RFC 2119.
1. Purpose
This file specifies how libVCT is built, what it produces, what it exposes to embedders, and who owns memory across the API boundary. It also fixes the configuration, threading, versioning, and determinism contracts that the rest of the specification depends on.
2. Scope
Covers the toolchain, the build system, the shipped artifacts, the two API surfaces, module
visibility, arena ownership, the Config struct, the threading contract, versioning, and the
determinism guarantee. It does not restate stage semantics; those live in the stage files.
3. Definitions
| Term | Meaning |
|---|---|
| C API | The extern(C) surface exposed to non-D callers. |
| D API | The native D surface; the implementation itself. |
| Shim | The thin translation layer implementing the C API over the D API. |
| Arena | A region of memory reclaimed as a unit, not per object. |
| Bump allocator | The default in-tree allocator that serves requests by advancing a pointer. |
| Cold path | Code that runs at most a few times per compilation: driver, diagnostics, CLI. |
4. Toolchain
- The library MUST be written in D.
- Release builds MUST use LDC2, chosen for generated-code quality.
- Debug builds MUST use DMD, chosen for compile and iteration speed.
- libVCT MUST have zero runtime dependencies beyond its own code. It MUST NOT require a third-party library at build time or at load time.
- A D compiler is required to build libVCT. A system C compiler is required only when the C path is used, and it MUST be discovered at runtime (see 010 — Driver & CLI). Prebuilt binaries MUST NOT require a D compiler at load time.
5. Build system
- The build system MUST be xmake. A single
xmake.luaMUST drive every target. - The build system MUST NOT be dub.
- The
releaseprofile MUST select LDC2. Thedebugprofile MUST select DMD. - Building libVCT MUST NOT require an external package manager.
6. Artifacts
- A conforming build MUST produce all of the following:
| Artifact | Kind | Purpose |
|---|---|---|
libvct.a |
static library | Static linking of the full library. |
libvct.so |
shared library | Dynamic linking; embedders load it at runtime. |
vct |
executable | The command-line driver (see 010 — Driver & CLI). |
vctc.h |
C header | The declarations of the C API. |
vct.test.hirbuild |
D module | The fixture harness, shipped publicly (see 012 — Testing). |
- The static and shared libraries MUST expose the same symbols and behavior; choosing one over the other MUST NOT change observable results.
7. Public API surfaces
- The C API MUST be the primary public surface in v1. It MUST be declared
extern(C)so that C, C++, and other FFI callers can use it without a D toolchain. - The C API MUST represent library state through opaque handles for
Context,Module,Builder, andConfig. Callers MUST NOT depend on the layout of these types, and the header MUST NOT expose their internal fields. - The C API MUST provide operations to build IR, run the pipeline, and query diagnostics.
- The D API MUST be the full-feature implementation surface. The C API is a shim over it.
- The shim MUST NOT contain logic beyond argument marshalling, error translation, and handle conversion. Every behavior reachable through the C API MUST be implemented in the D API, so that every C API call exercises the D API.
- An implementation MUST NOT place optimizer, lowering, or backend logic in the header or the shim.
An illustrative header shape (not a complete declaration set):
typedef struct vct_context vct_context;
typedef struct vct_module vct_module;
typedef struct vct_builder vct_builder;
typedef struct vct_config vct_config;
vct_context *vct_context_create(const vct_config *cfg);
void vct_context_destroy(vct_context *ctx);
8. Module visibility
- The following modules MUST be public:
vct.ir.hir,vct.traits,vct.context, the entry points ofvct.backend.candvct.backend.llvm,vct.driver,vct.diag, andvct.test.hirbuild. - The following modules MUST be internal:
vct.ir.vir,vct.lower,vct.hir.opt,vct.vir.opt, and the internals ofvct.comptime. - A public module MUST NOT expose internal types in its public signatures in a way that forces embedders to depend on internal layout. The trait vocabulary and node identity cross this boundary and are versioned accordingly (see section 12).
9. Memory ownership and lifecycle
- A
ContextMUST own one or more arenas. An arena is the unit of reclamation. The default is one arena perModule, freed wholesale. - All IR and optimizer objects MUST be arena-owned and non-GC. Passes MUST mutate them in place under epoch guards (see 002 — Traits).
- Garbage collection MUST be permitted only on cold paths: the driver, diagnostics, and the CLI. The optimizer, lowering, and backends MUST NOT depend on the GC for IR objects.
- The
ContextMUST accept anArenaAllocatorinterface so embedders can supply their own backing memory. The interface MUST provide exactly these operations:allocate(size, alignment)returns uninitialized storage owned by the arena; callers MUST NOT assume zeroed storage;reset()returns the arena to its initial state so it can be reused;destroy()releases the arena's backing memory.
- A default bump allocator MUST ship in-tree and MUST be the allocator used when the embedder supplies none.
- Ownership rules:
- Objects allocated into a
Contextor arena live until that arena is reset or destroyed. - A caller MUST NOT free an individual arena-owned object. Freeing happens only through
resetordestroy. - A pointer or handle returned across the API MUST remain valid until the owning arena is reset or destroyed.
- Use of an object after its arena has been reset or destroyed is undefined, and the implementation MUST NOT be required to detect it.
- Objects allocated into a
10. Configuration
- A single
ConfigMUST carry every setting that affects output. At minimum it MUST carry:
| Field group | Contents |
|---|---|
| Optimization level | -O0, -O1, -O2, -O3, -Ofast, -Oz. |
| Target | -march, -mcpu, -target <triple>. |
| Budgets | comptime and HIR budgets (see 004 — HIR Optimizer) and VIR budgets (see 007 — VIR Optimizer). |
| Pass toggles | enable and disable for every pass exposed as -f and -fno-. |
| Warning policy | -Wall, -Wextra, -Werror, -Wno-error[=<category>], -w. |
| C compiler selection | -cc=gcc or -cc=clang, or automatic discovery. |
| Mode | -S, -emit-llvm/-llvm, or -mangled. |
- The CLI MUST be a pure function from
argvto aConfig. The library MUST take aConfigand MUST NOT read process arguments itself. - Programmatic callers MUST be able to bypass the CLI and construct a
Configdirectly. - The determinism guarantee (section 13) is stated relative to a fixed
Config.
11. Threading
- libVCT MUST be thread-safe when each compilation unit has its own
Contextand arenas. - libVCT MUST NOT hold shared mutable global state.
- Intra-module parallelism is internal and MUST be bounded by the
-jsetting. The observed output MUST NOT depend on-j(see 000 — Overview).
12. Versioning
- The library MUST follow semantic versioning.
- The textual IR format MUST carry its own version, independent of the library version.
- The trait vocabulary MUST carry its own version. Adding an attribute or request is a backward-compatible change; changing the meaning of an existing one is a major change.
- Experimental passes MUST be gated behind feature flags so that default behavior stays stable within a minor version.
13. Determinism guarantee
- For a fixed
Configand a fixed input, libVCT MUST produce byte-identical output on every run, independent of thread count. This binds HIR optimization, lowering, VIR optimization, and both backends. It is a correctness property, not an optimization. - Determinism MUST be demonstrated in CI as specified in 012 — Testing.
14. Invariants
- The C API and the D API MUST expose the same behavior; a divergence is a bug in the shim.
- An arena MUST be reclaimable as a unit; no arena-owned object may outlive its arena.
- A stage MUST NOT depend on shared mutable global state.
- The same
Configand input MUST yield the same bytes regardless of-j.
15. Cross-references
- 000 — Overview for goals, non-goals, and the determinism guarantee.
- 001 — Architecture for the module map and interfaces.
- 002 — Traits for epochs and the trait vocabulary version.
- 004 — HIR Optimizer for budget names and defaults.
- 007 — VIR Optimizer for VIR budget names and defaults.
- 010 — Driver & CLI for flag semantics and C compiler discovery.
- 012 — Testing for determinism tests and the fixture harness.