kitc support library
This document sketches a future kitc library: a Kit-provided C utility
library that is distributed with the toolchain, built on demand for the active
target, and linkable from both file-output builds and JIT runs.
kitc is deliberately not libc and not the compiler runtime. It is an
ordinary opt-in support library for data structures, algorithms, encoding,
small platform abstractions, and other reusable C utilities that are useful to
programs compiled by Kit.
Goals
- Ship reusable C utility APIs under a Kit-owned namespace.
- Make the library available to C programs, C "scripts" run through
kit run, and cross-compiled targets. - Build archives on demand from source, using Kit itself, instead of shipping a prebuilt archive for every target and ABI variant.
- Use the normal linker and archive semantics once the archive exists: no special symbol resolution path, no JIT-only library path.
- Keep freestanding code usable without libc or host syscalls.
- Distribute the source tree through the existing signed package/CAS machinery once package-based support assets are user-facing.
Non-goals
kitcis not a C standard library implementation.kitcmust not define standard libc symbols such asprintf,malloc, ormemcpy.kitcmust not be required for ordinary C code generation. Compiler helper routines remain inlibkit_rt.a.kitcmust not introduce hidden global state. Stateful APIs take explicit context structs or caller-owned storage.- The initial implementation does not need a new public libkit API. Driver-side support is enough until embeddings need the same facility.
Relationship to existing support libraries
libkit_rt.a is part of the compiler substrate: integer/floating helpers,
atomics, setjmp/coroutines, freestanding header support, and other pieces that
compiled code may need even when the user did not ask for a utility library.
The driver already resolves a target runtime variant, builds the archive on
demand, caches it under build/rt or the user cache, and inserts it into the
link at the policy point required by the target.
kitc should reuse that shape, but with different policy:
- headers are under
<kitc/...>, not the freestanding libc header namespace; - symbols are prefixed with
kitc_; - linking is explicit, normally via
-lkitcor a driver sugar flag; - archive insertion is lazy and ordinary, just like any other static library;
- hosted/OS-dependent helpers live in a separate component from freestanding core utilities.
By the time a link session sees kitc, it should be just another archive input.
All special behavior belongs before linking: locating the source package,
choosing the target variant, compiling the source set, caching the archive, and
inserting the archive in the requested link order.
Source layout
The library should live outside rt/:
kitc/
include/
kitc/
base.h
vec.h
str.h
...
src/
vec.c
str.c
...
manifest.kitc
LICENSE
The manifest is the source of truth for the driver-side builder. It should record the library version, components, source files, public include roots, and target/feature gates. It should be canonical text so it can be hashed directly or stored as a CAS blob later.
Possible component split:
| Component | Scope |
|---|---|
kitc-core |
Freestanding utilities: containers, string slices, hashing adapters, encoders, parsers, formatting into caller-provided buffers, no syscalls. |
kitc-hosted |
File, environment, time, process, terminal, and other helpers that require hosted OS/libc facilities. |
kitc-extra |
Optional heavier modules that should not be pulled in by the default utility library. |
The default -lkitc spelling should start with kitc-core. Hosted helpers can
be exposed as -lkitc_hosted or a later explicit feature flag.
Command-line surface
The primary interface should be ordinary library spelling:
kit cc app.c -lkitc
kit run script.c -lkitc
kit cc -target aarch64-linux app.c -lkitc
A convenience flag such as --kitc can be added later, but it should lower to
"add the kitc include root and lazy-link the selected kitc archive". The driver
should not auto-link merely because a source included <kitc/foo.h>: include
resolution and link input selection should stay separate.
Header search policy can be friendlier than link policy. It is reasonable for
the driver to add the kitc/include root to the system include set when Kit
support headers are enabled, so a source can write:
#include <kitc/vec.h>
But a reference to kitc_vec_* still requires an explicit library input.
On-demand build and cache identity
The first implementation can mirror driver/lib/runtime.c:
- Resolve the active
KitTargetSpec. - Select the
kitcvariant/component frommanifest.kitc. - Build each source file with a
KitCompilerconfigured for the target. - Archive the resulting object builders or object bytes with
kit_ar_write. - Insert the archive path as a normal lazy archive input.
The cache key should be content-based rather than only mtime-based:
kitc source tree id
+ manifest version
+ component name
+ target triple / target key
+ object format and OS
+ ABI/data-model axes: pointer size, alignment, float ABI, long double, int128
+ -march / -mabi or equivalent target ISA options
+ codegen-affecting feature flags
+ debug/profile/sanitizer variant when those are supported
Recommended cache locations:
<checkout>/build/kitc/<target-key>/<config-id>/libkitc.a
$KIT_HOME/cache/kitc/<target-key>/<config-id>/libkitc.a
In a checkout or explicit support directory, prefer the in-tree cache so local
development shares artifacts with make targets. In an installed distribution,
prefer the user cache so the tool never writes into the install tree.
Staleness should eventually be determined by the source tree id and config id. An initial mtime fallback is acceptable if the tree-id plumbing is not ready, but the design target is reproducible content identity.
Distribution
kitc should be distributed as source, not as prebuilt target archives.
Prebuilt archives multiply across architecture, OS, object format, ABI, ISA
options, and feature flags. Source distribution keeps the package small and
matches Kit's self-hosting story: any target Kit can compile can get a matching
kitc archive on demand.
Long-term distribution should use the existing signed package and CAS layers:
- Release packaging stores the
kitcsource tree as a CAS tree. - A signed
.kpkgclaims the tree id, version, and metadata. - Install or first use materializes the tree under the Kit support root, or reads it from the local CAS when direct tree reads are available.
- The on-demand builder keys compiled archives by that source tree id plus the target/config id.
This gives kitc the same verification story as other support assets without
requiring a new distribution format.
JIT and C scripts
The JIT path should need no special linker support. For:
kit run script.c -lkitc
the driver should:
- Compile
script.cto an object builder for the host-compatible target. - Ensure the selected
libkitc.aexists for that same target. - Add
libkitc.aas a lazy archive input after user objects. - Add
libkit_rt.aaccording to the existing runtime policy. - Open a link session with
KIT_LINK_OUTPUT_JIT. - Call
kit_link_session_jit.
Because the JIT uses the same object, archive, relocation, and symbol-resolution
machinery as file output, archive member selection should behave identically.
If kitc-hosted calls host libc functions, those are resolved through the
existing JIT extern resolver and call-stub/GOT machinery. kitc-core should not
depend on that path.
Driver integration
The first cut can stay driver-local:
driver/lib/kitc.c
driver/lib/kitc.h
kitc/manifest.kitc
kitc/include/...
kitc/src/...
Proposed driver helper responsibilities:
- locate the
kitcsource/support root; - parse or load the source manifest;
- select a component and target variant;
- compute or approximate the archive cache key;
- build missing/stale archives;
- return a
DriverArchiveInputcompatible with the existing link input set.
cc, ld, and run should not grow independent kitc logic. They should call
the shared helper when -lkitc or a future sugar flag requires it, then insert
the returned archive through the same DriverLinkInputSet path used for other
archives.
If embeddings later need this feature, promote the concept into a public support library API. Until then, keeping it in the driver avoids freezing a broad API too early.
Link ordering
For normal links, libkitc.a should appear where the user requested -lkitc.
That preserves ordinary archive behavior and lets users control dependency
order.
For a future --kitc sugar flag, insert the archive after user source/object
inputs and before the compiler runtime. This order lets user code pull needed
kitc members lazily, and lets both user code and kitc pull compiler-runtime
helpers as needed.
Windows runtime special cases should remain owned by the runtime insertion code.
kitc should not duplicate runtime archive placement rules.
Open questions
- Manifest format: use a small canonical custom text format, or reuse a broader package/build manifest format once that stabilizes?
- Header availability: should
<kitc/...>be on by default forccandrun, or only enabled when-lkitc/--kitcis present? - Hosted split: should hosted helpers be a separate archive from day one, or a component selected from one manifest?
- Build coordinator integration: should
kitcarchive builds eventually be modeled as content-addressed build targets, so remote trace reuse can avoid rebuilding popular variants? - Version policy: is
kitcversioned exactly with Kit releases, or can package channels ship newerkitcsource trees to older compatible Kit binaries?
Phased implementation
Phase 1: local source archive
- Add the
kitc/tree with a small freestandingkitc-coresurface. - Add a driver-local builder modeled on runtime archive generation.
- Recognize
-lkitcand replace it with an ensured archive path. - Add targeted tests for
kit cc app.c -lkitcandkit run app.c -lkitcon the native target.
Phase 2: target matrix
- Extend the variant table/manifest across the release support set.
- Add cross-target archive build tests for a small source corpus.
- Validate freestanding targets do not accidentally depend on hosted libc symbols.
Phase 3: content identity
- Compute a source tree id and config id for archive caches.
- Stop relying on mtimes when content identity is available.
- Share cache layout with the support/install root policy.
Phase 4: signed package distribution
- Package the
kitcsource tree as a signed.kpkg. - Materialize it under the support root during install or first use.
- Key archive builds by the package tree id.
Phase 5: broader library surface
- Add hosted and optional components behind explicit link spellings.
- Consider public support-library APIs only after the driver-local shape has real users and stable requirements.