kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

commit 00b46f1426b781000d7beda4b4812737c12eca2c
parent 49b6fb2e582e31592612da787fc1af47163ab9cf
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Fri, 17 Jul 2026 15:32:07 -0700

driver: depend only on the public API; drop all relative includes

Enforce two boundary invariants and make the build itself uphold them.

No source uses a relative "../" include. The five offenders (src/build,
driver/env, driver/cmd) now include via their -I roots.

The driver depends only on the public include/ surface; it no longer reaches
into src/ or lang/:

  * build_coord.c parsed WORKSPACE.kit through src/build/{defn,workspace}.h.
    The workspace and config value types, their constants, and
    kit_build_workspace_{init,parse,external_find} are now public in
    kit/build_coord.h. The internal cfg.h/workspace.h typedef the short
    Build* names to the public KitBuild* types (one definition site), and
    src/api/build_coord.c adds thin public wrappers.

  * cc.c's #include "c/c.h" was dead (its CC_*/cc_* knobs are all local, and
    it never referenced kit_c_frontend_vtable). Removed it and dropped -Ilang
    from DRIVER_CFLAGS/DRIVER_ENV_CFLAGS. The library keeps its own -Ilang for
    lang_registry.c.

With neither -Ilang nor -Isrc on the driver build, a private-header include
now fails to compile, so the boundary cannot silently regress.

Tests: make test-build green (build_pure 62/0, buildcoord 352/0,
build-public-link); kit cc and kit build repo list smoked end-to-end.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cu5rjrydtNn6LAEwLYqQeB

Diffstat:
Mdriver/cmd/build_coord.c | 46++++++++++++++++++++++------------------------
Mdriver/cmd/cc.c | 2--
Mdriver/cmd/targets.c | 2+-
Mdriver/env/build_host_posix.c | 2+-
Mdriver/env/build_host_stub.c | 2+-
Mdriver/env/build_host_windows.c | 2+-
Minclude/kit/build_coord.h | 88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mmk/flags.mk | 14+++++++-------
Msrc/api/build_coord.c | 23+++++++++++++++++++++++
Msrc/build/cfg.h | 17+++++------------
Msrc/build/coord.c | 2+-
Msrc/build/workspace.h | 47++++++++++++-----------------------------------
12 files changed, 162 insertions(+), 85 deletions(-)

diff --git a/driver/cmd/build_coord.c b/driver/cmd/build_coord.c @@ -8,8 +8,6 @@ #include <stdlib.h> #include <string.h> -#include "../../src/build/defn.h" -#include "../../src/build/workspace.h" #include "dist_host.h" #include "driver.h" #include "env.h" @@ -50,7 +48,7 @@ typedef struct BuildCli { } BuildCli; typedef struct BuildListTarget { - char label[BUILD_TARGET_MAX]; + char label[KIT_BUILD_TARGET_MAX]; } BuildListTarget; void driver_help_build(void) { @@ -218,7 +216,7 @@ static int build_load_file(DriverEnv* env, const char* path, DriverLoad* load, } static int build_load_workspace(DriverEnv* env, const char* root, - BuildWorkspace* ws, int* present) { + KitBuildWorkspace* ws, int* present) { char path[KIT_BUILD_PATH_MAX]; DriverLoad load; KitSlice bytes; @@ -226,13 +224,13 @@ static int build_load_workspace(DriverEnv* env, const char* root, if (present) *present = 0; if (build_join_path(path, sizeof path, root, "WORKSPACE.kit") != 0) return 1; if (!driver_path_exists(path)) { - build_workspace_init(ws); + kit_build_workspace_init(ws); return 0; } if (present) *present = 1; if (build_load_file(env, path, &load, &bytes) != 0) return 1; - if (build_workspace_parse(bytes.data, bytes.len, ws, err, sizeof err) != - BUILD_OK) { + if (kit_build_workspace_parse(bytes.data, bytes.len, ws, err, sizeof err) != + KIT_OK) { driver_errf(BUILD_TOOL, "bad WORKSPACE.kit: %s", err); driver_release_bytes(&env->file_io, &load); return 1; @@ -346,9 +344,9 @@ static int build_list_generated_from_projection(DriverEnv* env, KitSlice line, BuildListTarget* out, size_t* n, size_t cap) { - char pat[BUILD_PATH_MAX], tmpl[BUILD_TARGET_MAX]; - char dir_rel[BUILD_PATH_MAX], dir_abs[KIT_BUILD_PATH_MAX]; - char prefix[128], suffix[128], label[BUILD_TARGET_MAX], local[BUILD_TARGET_MAX]; + char pat[KIT_BUILD_PATH_MAX], tmpl[KIT_BUILD_TARGET_MAX]; + char dir_rel[KIT_BUILD_PATH_MAX], dir_abs[KIT_BUILD_PATH_MAX]; + char prefix[128], suffix[128], label[KIT_BUILD_TARGET_MAX], local[KIT_BUILD_TARGET_MAX]; DriverDirHandle* dh; size_t i, arrow = (size_t)-1, star = (size_t)-1, slash = (size_t)-1; if (!build_slice_starts(line, "list ")) return 0; @@ -390,7 +388,7 @@ static int build_list_generated_from_projection(DriverEnv* env, uint64_t ino, size, mtime; uint8_t ftype; size_t pn = driver_strlen(prefix), sn = driver_strlen(suffix); - char stem[BUILD_TARGET_MAX]; + char stem[KIT_BUILD_TARGET_MAX]; if (driver_read_dir_entry(dh, i, &name, &name_len, &ino, &size, &mtime, &ftype) != 0) break; @@ -434,7 +432,7 @@ static int build_list_package(DriverEnv* env, const char* root, while (build_line_next(bytes, &pos, &line) == 0) { if (build_slice_starts(line, "[target ") && line.len > 9u && line.s[line.len - 1u] == ']') { - char local[BUILD_TARGET_MAX], label[BUILD_TARGET_MAX]; + char local[KIT_BUILD_TARGET_MAX], label[KIT_BUILD_TARGET_MAX]; build_copy_slice0(local, sizeof local, (KitSlice){.s = line.s + 8u, .len = line.len - 9u}); @@ -467,7 +465,7 @@ static int build_list_package(DriverEnv* env, const char* root, uint32_t name_len; uint64_t ino, size, mtime; uint8_t ftype; - char child_pkg[BUILD_PATH_MAX], child_dir[KIT_BUILD_PATH_MAX], + char child_pkg[KIT_BUILD_PATH_MAX], child_dir[KIT_BUILD_PATH_MAX], child_def[KIT_BUILD_PATH_MAX]; if (driver_read_dir_entry(dh, idx, &name, &name_len, &ino, &size, &mtime, &ftype) != 0) @@ -707,7 +705,7 @@ static int build_export_set(DriverEnv* env, int argc, char** argv, return 1; } { - char line[BUILD_VAL_MAX + 32u]; + char line[KIT_BUILD_VAL_MAX + 32u]; snprintf(line, sizeof line, "[var %s]\n", argv[first_arg]); if (build_file_append(env, exports_path, line) != 0) { driver_errf(BUILD_TOOL, "failed to append exports variable"); @@ -715,7 +713,7 @@ static int build_export_set(DriverEnv* env, int argc, char** argv, } } for (i = (size_t)first_arg + 2u; i < (size_t)argc; ++i) { - char line[BUILD_VAL_MAX + 2u]; + char line[KIT_BUILD_VAL_MAX + 2u]; snprintf(line, sizeof line, "%s\n", argv[i]); if (build_file_append(env, exports_path, line) != 0) { driver_errf(BUILD_TOOL, "failed to append exports value"); @@ -1270,7 +1268,7 @@ static int build_cmd_list(int argc, char** argv, int cmd_index) { const char* pattern = "//..."; int scan_do = 0; int i, recursive = 0; - char pkg[BUILD_PATH_MAX]; + char pkg[KIT_BUILD_PATH_MAX]; BuildListTarget targets[512]; size_t ntargets = 0, j; (void)store_ignored; @@ -1351,7 +1349,7 @@ static int build_cmd_list(int argc, char** argv, int cmd_index) { static int build_cmd_repo(int argc, char** argv, int cmd_index) { DriverEnv env; const char *root, *def_name_ignored, *store_ignored; - BuildWorkspace ws; + KitBuildWorkspace ws; int present = 0; size_t i; (void)def_name_ignored; @@ -1369,13 +1367,13 @@ static int build_cmd_repo(int argc, char** argv, int cmd_index) { } if (driver_streq(argv[cmd_index + 1], "list")) { for (i = 0; i < ws.n_externals; ++i) { - char hex[BUILD_HEX_LEN]; - const char* fmt = ws.externals[i].format == BUILD_WS_EXT_TREE + char hex[KIT_BUILD_HEX_LEN]; + const char* fmt = ws.externals[i].format == KIT_BUILD_WS_EXT_TREE ? "tree" - : ws.externals[i].format == BUILD_WS_EXT_TARGZ + : ws.externals[i].format == KIT_BUILD_WS_EXT_TARGZ ? "tar.gz" : "kpkg"; - kit_hex_encode(hex, ws.externals[i].archive, BUILD_HASH_LEN); + kit_hex_encode(hex, ws.externals[i].archive, KIT_BUILD_HASH_LEN); driver_printf("%s %s %s\n", ws.externals[i].name, fmt, hex); } } else if (driver_streq(argv[cmd_index + 1], "fetch")) { @@ -1384,7 +1382,7 @@ static int build_cmd_repo(int argc, char** argv, int cmd_index) { driver_env_fini(&env); return 2; } - if (!build_workspace_external_find(&ws, kit_slice_cstr(argv[cmd_index + 2]))) { + if (!kit_build_workspace_external_find(&ws, kit_slice_cstr(argv[cmd_index + 2]))) { driver_errf(BUILD_TOOL, "unknown external repo: %s", argv[cmd_index + 2]); driver_env_fini(&env); return 1; @@ -1396,7 +1394,7 @@ static int build_cmd_repo(int argc, char** argv, int cmd_index) { const char* src; const char* format = "tar.gz"; const char* strip = NULL; - char ws_path[KIT_BUILD_PATH_MAX], line[2048], hex[BUILD_HEX_LEN]; + char ws_path[KIT_BUILD_PATH_MAX], line[2048], hex[KIT_BUILD_HEX_LEN]; DriverLoad load; KitSlice bytes; KitBlobInfo bi; @@ -1422,7 +1420,7 @@ static int build_cmd_repo(int argc, char** argv, int cmd_index) { } kit_blob_info(&bi, bytes.data, bytes.len); driver_release_bytes(&env.file_io, &load); - kit_hex_encode(hex, bi.id, BUILD_HASH_LEN); + kit_hex_encode(hex, bi.id, KIT_BUILD_HASH_LEN); if (build_join_path(ws_path, sizeof ws_path, root, "WORKSPACE.kit") != 0) { driver_env_fini(&env); return 1; diff --git a/driver/cmd/cc.c b/driver/cmd/cc.c @@ -1,5 +1,3 @@ -#include "c/c.h" - #include <kit/asm_emit.h> #include <kit/build.h> #include <kit/compile.h> diff --git a/driver/cmd/targets.c b/driver/cmd/targets.c @@ -1,4 +1,4 @@ -#include "../driver.h" +#include "driver.h" #include <kit/target.h> #include <stdint.h> diff --git a/driver/env/build_host_posix.c b/driver/env/build_host_posix.c @@ -1,4 +1,4 @@ -#include "../env_build.h" +#include "env_build.h" #include "dist_host.h" diff --git a/driver/env/build_host_stub.c b/driver/env/build_host_stub.c @@ -1,4 +1,4 @@ -#include "../env_build.h" +#include "env_build.h" #include <string.h> diff --git a/driver/env/build_host_windows.c b/driver/env/build_host_windows.c @@ -1,4 +1,4 @@ -#include "../env_build.h" +#include "env_build.h" #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN diff --git a/include/kit/build_coord.h b/include/kit/build_coord.h @@ -523,4 +523,92 @@ KIT_API KitStatus kit_build_client_need_await(KitBuildClient*, KitBuildNeedToken token, KitBuildResult* out); +/* ------------------------------------------------------------------ * + * Workspace definition and configuration values + * ------------------------------------------------------------------ * + * + * A workspace (WORKSPACE.kit at the build root) names the project, declares + * named [config NAME] profiles, and pins external repositories. These types + * expose the parsed form for tooling that inspects or renders a workspace (for + * example `kit build repo list`); the coordinator itself consumes a workspace + * through KitBuildOptions.workspace_root/profile and resolves it internally, so + * a caller that only runs builds never needs them. + * + * All storage is inline and fixed-size (VLA-free), so a KitBuildWorkspace is + * safe to hold by value on the stack. Fixed string capacities match the + * canonical build text format. */ +#define KIT_BUILD_TARGET_MAX 256u /* label, e.g. "//app:server" */ +#define KIT_BUILD_KEY_MAX 64u /* config key name */ +#define KIT_BUILD_VAL_MAX 512u /* config value */ +#define KIT_BUILD_URL_MAX 1024u /* one fetch URL hint */ +#define KIT_BUILD_HEX_LEN (2u * KIT_BUILD_HASH_LEN + 1u) /* lowercase hex + NUL */ + +/* One key=value entry of a propagated-config map. */ +typedef struct KitBuildConfigEntry { + char key[KIT_BUILD_KEY_MAX]; + char value[KIT_BUILD_VAL_MAX]; +} KitBuildConfigEntry; + +/* A propagated-config map over caller-owned `entries` storage; kept sorted by + * key with no duplicates once canonicalized. */ +typedef struct KitBuildConfig { + KitBuildConfigEntry* entries; + size_t n; + size_t cap; +} KitBuildConfig; + +/* How an external repository's pinned content is delivered. */ +typedef enum KitBuildWorkspaceExternalFormat { + KIT_BUILD_WS_EXT_NONE = 0, + KIT_BUILD_WS_EXT_TREE, + KIT_BUILD_WS_EXT_KPKG, + KIT_BUILD_WS_EXT_TARGZ, +} KitBuildWorkspaceExternalFormat; + +/* One pinned external repository. */ +typedef struct KitBuildWorkspaceExternal { + char name[KIT_BUILD_KEY_MAX]; + KitBuildWorkspaceExternalFormat format; + uint8_t archive[KIT_BUILD_HASH_LEN]; + int has_archive; + uint8_t package[KIT_BUILD_HASH_LEN]; + int has_package; + char strip_prefix[KIT_BUILD_PATH_MAX]; + char urls[8][KIT_BUILD_URL_MAX]; + size_t n_urls; +} KitBuildWorkspaceExternal; + +/* One named [config NAME] profile: inline entry storage plus a KitBuildConfig + * view over it. */ +typedef struct KitBuildWorkspaceConfigProfile { + char name[KIT_BUILD_KEY_MAX]; + char inherits[KIT_BUILD_KEY_MAX]; + KitBuildConfigEntry entries[64]; + KitBuildConfig cfg; +} KitBuildWorkspaceConfigProfile; + +/* A parsed WORKSPACE.kit: identity, config profiles, and external repos. */ +typedef struct KitBuildWorkspace { + char name[KIT_BUILD_KEY_MAX]; + char version[KIT_BUILD_VAL_MAX]; + char def_name[KIT_BUILD_PATH_MAX]; + KitBuildWorkspaceConfigProfile profiles[16]; + size_t n_profiles; + KitBuildWorkspaceExternal externals[16]; + size_t n_externals; +} KitBuildWorkspace; + +/* Initialize an empty workspace (no profiles, no externals). */ +KIT_API void kit_build_workspace_init(KitBuildWorkspace* out); + +/* Parse canonical WORKSPACE.kit bytes into `out`. On a parse error, returns + * KIT_INVALID and writes a human-readable reason into `err` (errcap bytes). */ +KIT_API KitStatus kit_build_workspace_parse(const uint8_t* data, size_t len, + KitBuildWorkspace* out, char* err, + size_t errcap); + +/* Find an external repository by name; NULL if absent. */ +KIT_API const KitBuildWorkspaceExternal* kit_build_workspace_external_find( + const KitBuildWorkspace* ws, KitSlice name); + #endif diff --git a/mk/flags.mk b/mk/flags.mk @@ -135,17 +135,17 @@ FREESTANDING_CFLAGS = $(CFLAGS_COMMON) $(FREESTANDING_CONFIG_CFLAGS) -ffreestand LIB_VISIBILITY_CFLAGS = -fvisibility=hidden LIB_CFLAGS = $(FREESTANDING_CFLAGS) $(LIB_VISIBILITY_CFLAGS) -Iinclude -Isrc -Ivendor -# Driver: mostly freestanding CLI binary. Sees only the public include/ tree — -# that's what makes the driver the first consumer of libkit. -Ilang lets `cc` -# reach the C frontend's public header ("c/c.h") for the JIT REPL; it -# deliberately does NOT get -Isrc, so internal headers ("core/...", "link/...") -# are unreachable from the driver. +# Driver: mostly freestanding CLI binary. Sees ONLY the public include/ tree — +# that's what makes the driver the first consumer of libkit, and the build +# itself enforces it: with neither -Ilang nor -Isrc, a driver source +# physically cannot include a frontend (lang/) or libkit-internal (src/) +# header, so the driver depends on nothing but the public API. # # driver/env/ holds all hosted OS/libc adapter code and is compiled with # DRIVER_ENV_CFLAGS. The per-OS feature-test macros and the exact source # list (DRIVER_ENV_OS_CFLAGS / DRIVER_ENV_SRCS) come from mk/env.mk. -DRIVER_CFLAGS = $(FREESTANDING_CFLAGS) -Iinclude -Ilang -Idriver -Idriver/lib -DRIVER_ENV_CFLAGS = $(HOST_CFLAGS) -Iinclude -Ilang -Idriver -Idriver/lib +DRIVER_CFLAGS = $(FREESTANDING_CFLAGS) -Iinclude -Idriver -Idriver/lib +DRIVER_ENV_CFLAGS = $(HOST_CFLAGS) -Iinclude -Idriver -Idriver/lib TEST_HOST_CFLAGS = $(HOST_CFLAGS) -Iinclude -Ilang # `kit update` release trust is generated per build. Development binaries keep diff --git a/src/api/build_coord.c b/src/api/build_coord.c @@ -5,6 +5,7 @@ #include "build/coord.h" #include "build/protocol.h" #include "build/resolve.h" +#include "build/workspace.h" #include <string.h> @@ -495,3 +496,25 @@ KitStatus kit_build_client_need_await(KitBuildClient* c, req.token = token.id; return build_client_need_result(c, &req, out); } + +/* ------------------------------------------------------------------ * + * Workspace inspection (public wrappers over the internal parser) + * ------------------------------------------------------------------ */ + +void kit_build_workspace_init(KitBuildWorkspace* out) { + build_workspace_init(out); +} + +KitStatus kit_build_workspace_parse(const uint8_t* data, size_t len, + KitBuildWorkspace* out, char* err, + size_t errcap) { + if (!data || !out) return KIT_INVALID; + return build_workspace_parse(data, len, out, err, errcap) == BUILD_OK + ? KIT_OK + : KIT_INVALID; +} + +const KitBuildWorkspaceExternal* kit_build_workspace_external_find( + const KitBuildWorkspace* ws, KitSlice name) { + return build_workspace_external_find(ws, name); +} diff --git a/src/build/cfg.h b/src/build/cfg.h @@ -26,18 +26,11 @@ * and the api layer owns sizing. */ -typedef struct BuildConfigEntry { - char key[BUILD_KEY_MAX]; - char value[BUILD_VAL_MAX]; -} BuildConfigEntry; - -/* A propagated config map. `entries` is caller-owned; kept sorted by key with - * no duplicates once canonicalized. */ -typedef struct BuildConfig { - BuildConfigEntry* entries; - size_t n; - size_t cap; -} BuildConfig; +/* The propagated-config value types are part of the public build model + * (<kit/build_coord.h>, included above); keep the internal short names as + * aliases so src/build code is unchanged and there is one definition site. */ +typedef KitBuildConfigEntry BuildConfigEntry; +typedef KitBuildConfig BuildConfig; /* A local argv vector. `args` is caller-owned; order is significant and * preserved (argv is positional, not a map). */ diff --git a/src/build/coord.c b/src/build/coord.c @@ -1,7 +1,7 @@ #include "coord.h" #include "bundle.h" -#include "../dist/tar.h" +#include "dist/tar.h" #include <kit/compress.h> #include <kit/package.h> diff --git a/src/build/workspace.h b/src/build/workspace.h @@ -1,6 +1,7 @@ #ifndef KIT_BUILD_WORKSPACE_H #define KIT_BUILD_WORKSPACE_H +#include <kit/build_coord.h> #include <kit/core.h> #include <stddef.h> #include <stdint.h> @@ -8,41 +9,17 @@ #include "build.h" #include "cfg.h" -typedef enum BuildWorkspaceExternalFormat { - BUILD_WS_EXT_NONE = 0, - BUILD_WS_EXT_TREE, - BUILD_WS_EXT_KPKG, - BUILD_WS_EXT_TARGZ, -} BuildWorkspaceExternalFormat; - -typedef struct BuildWorkspaceConfigProfile { - char name[BUILD_KEY_MAX]; - char inherits[BUILD_KEY_MAX]; - BuildConfigEntry entries[64]; - BuildConfig cfg; -} BuildWorkspaceConfigProfile; - -typedef struct BuildWorkspaceExternal { - char name[BUILD_KEY_MAX]; - BuildWorkspaceExternalFormat format; - uint8_t archive[BUILD_HASH_LEN]; - int has_archive; - uint8_t package[BUILD_HASH_LEN]; - int has_package; - char strip_prefix[BUILD_PATH_MAX]; - char urls[8][BUILD_URL_MAX]; - size_t n_urls; -} BuildWorkspaceExternal; - -typedef struct BuildWorkspace { - char name[BUILD_KEY_MAX]; - char version[BUILD_VAL_MAX]; - char def_name[BUILD_PATH_MAX]; - BuildWorkspaceConfigProfile profiles[16]; - size_t n_profiles; - BuildWorkspaceExternal externals[16]; - size_t n_externals; -} BuildWorkspace; +/* The workspace value types are part of the public build model + * (<kit/build_coord.h>); keep the internal short names as aliases so src/build + * code is unchanged and there is one definition site. */ +typedef KitBuildWorkspaceExternalFormat BuildWorkspaceExternalFormat; +typedef KitBuildWorkspaceExternal BuildWorkspaceExternal; +typedef KitBuildWorkspaceConfigProfile BuildWorkspaceConfigProfile; +typedef KitBuildWorkspace BuildWorkspace; +#define BUILD_WS_EXT_NONE KIT_BUILD_WS_EXT_NONE +#define BUILD_WS_EXT_TREE KIT_BUILD_WS_EXT_TREE +#define BUILD_WS_EXT_KPKG KIT_BUILD_WS_EXT_KPKG +#define BUILD_WS_EXT_TARGZ KIT_BUILD_WS_EXT_TARGZ void build_workspace_init(BuildWorkspace*); int build_workspace_parse(const uint8_t* data, size_t len, BuildWorkspace* out,