kit

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

commit 977cc8c48aacd19bd104c05e46851cd5724acce5
parent 68162c4ade84c734b1bbaecc249b14ce28cc95ab
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Tue, 23 Jun 2026 07:48:22 -0700

Add reusable C build rules

Diffstat:
MBUILD.kit | 34++++++++++++++++++++++++++++++----
Ado/c.sh | 8++++++++
Ado/default.a.do | 6++++++
Ado/default.exe.do | 6++++++
Ado/default.o.do | 6++++++
Ado/default.objs.do | 6++++++
Mdoc/BUILD_COORDINATOR.md | 11++++++++++-
Minclude/kit/build_coord.h | 5++++-
Mrecipes/buildkit/common.sh | 216+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Drecipes/buildkit/driver.sh | 30------------------------------
Drecipes/buildkit/kit.sh | 30------------------------------
Drecipes/buildkit/libkit.sh | 56--------------------------------------------------------
Arules/c/common.sh | 212+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Arules/c/default.a.do | 11+++++++++++
Arules/c/default.exe.do | 11+++++++++++
Arules/c/default.o.do | 11+++++++++++
Arules/c/default.objs.do | 11+++++++++++
Msrc/build/runner.c | 137+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Mtest/buildcoord/run.sh | 7+++++++
19 files changed, 636 insertions(+), 178 deletions(-)

diff --git a/BUILD.kit b/BUILD.kit @@ -1,7 +1,33 @@ -kit-build 1 +kit-build 2 + +[default c.executable] +recipe //do/default.exe.do + +[default c.object] +recipe //do/default.o.do + +[default c.objects] +recipe //do/default.objs.do + +[default c.static-library] +recipe //do/default.a.do + +[rule c-object] +match *.o +type c.object + +[rule c-objects] +match *.objs +type c.objects + [target driver] -recipe recipes/buildkit/driver.sh +type c.objects [target kit] -recipe recipes/buildkit/kit.sh +type c.executable [target libkit] -recipe recipes/buildkit/libkit.sh +type c.static-library + +[redo-defaults] +enabled true +search do +walk-parents true diff --git a/do/c.sh b/do/c.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +set -eu + +: "${KIT:=./build/kit}" + +common=$("$KIT" build source recipes/buildkit/common.sh) +. "$common" diff --git a/do/default.a.do b/do/default.a.do @@ -0,0 +1,6 @@ +#!/bin/sh +set -eu + +: "${KIT:=./build/kit}" +rule=$("$KIT" build source rules/c/default.a.do) +. "$rule" diff --git a/do/default.exe.do b/do/default.exe.do @@ -0,0 +1,6 @@ +#!/bin/sh +set -eu + +: "${KIT:=./build/kit}" +rule=$("$KIT" build source rules/c/default.exe.do) +. "$rule" diff --git a/do/default.o.do b/do/default.o.do @@ -0,0 +1,6 @@ +#!/bin/sh +set -eu + +: "${KIT:=./build/kit}" +rule=$("$KIT" build source rules/c/default.o.do) +. "$rule" diff --git a/do/default.objs.do b/do/default.objs.do @@ -0,0 +1,6 @@ +#!/bin/sh +set -eu + +: "${KIT:=./build/kit}" +rule=$("$KIT" build source rules/c/default.objs.do) +. "$rule" diff --git a/doc/BUILD_COORDINATOR.md b/doc/BUILD_COORDINATOR.md @@ -288,6 +288,15 @@ tracked inputs (`source`, `glob`, `config-get`, `need`, or a future equivalent); the resolver itself remains a client-side organization layer, not hidden cache identity. +Reusable language defaults should therefore be ordinary recipe libraries, not +implicit catalog semantics. For example, a generic C `.do` recipe can implement +the mechanics of compiling, archiving, linking, depfile logging, and profile +flag merging, while project-local shell hooks compute the actual sources, +target-level flags, dependency labels, and outputs by using `source`, `glob`, +`config-get`, and `need`. The coordinator-provided target pieces +(`KIT_BUILD_REPO`, `KIT_BUILD_PACKAGE`, `KIT_BUILD_LOCAL`) keep such shell rule +libraries from reparsing labels themselves. + ### Workspace manifest, defaults, and external repositories A workspace may also have a root `WORKSPACE.kit` manifest. `BUILD.kit` files @@ -1032,7 +1041,7 @@ run_recipe(T, cfg, argv, chain): spawn recipe (process argv = argv, the request's argv or empty when none given) with a CLEAN env (host inherits nothing): { KIT_BUILD_SOCK, KIT_BUILD_OUT=out, KIT_BUILD_TARGET=T, KIT_BUILD_REPO=<repo>, KIT_BUILD_PACKAGE=<package>, - current workspace root } + cfg's `env.*` keys as declared env vars + KIT_BUILD_LOCAL=<local-name> } + cfg's `env.*` keys as declared env vars service the recipe's protocol requests, logging each as a dep (next section); config-get reads cfg; source returns the live current-workspace path + pinned blob-id; need releases this recipe's job slot, recurses resolve(...) under cfg ⊕ overrides diff --git a/include/kit/build_coord.h b/include/kit/build_coord.h @@ -40,11 +40,14 @@ * creates a per-recipe endpoint (KitBuildTransport.listen) and passes its name * in KIT_BUILD_SOCK; the recipe dials that name back to the coordinator and * writes its output tree under KIT_BUILD_OUT. KIT_BUILD_TARGET names the target - * being built. */ + * being built; KIT_BUILD_REPO, KIT_BUILD_PACKAGE, and KIT_BUILD_LOCAL expose + * the canonical label's pieces for recipe rule libraries. */ #define KIT_BUILD_ENV_SOCK "KIT_BUILD_SOCK" #define KIT_BUILD_ENV_OUT "KIT_BUILD_OUT" #define KIT_BUILD_ENV_TARGET "KIT_BUILD_TARGET" +#define KIT_BUILD_ENV_REPO "KIT_BUILD_REPO" #define KIT_BUILD_ENV_PACKAGE "KIT_BUILD_PACKAGE" +#define KIT_BUILD_ENV_LOCAL "KIT_BUILD_LOCAL" /* Propagated-config keys under this prefix declare the recipe's pass-through * environment: a key "env.PATH" sets $PATH (to its config value) in the recipe's diff --git a/recipes/buildkit/common.sh b/recipes/buildkit/common.sh @@ -7,6 +7,9 @@ export PATH : "${KIT:=./build/kit}" +c_rules=$("$KIT" build source rules/c/common.sh) +. "$c_rules" + bk_source() { "$KIT" build source "$1" } @@ -33,6 +36,13 @@ bk_depfile() { fi } +c_depfile_filter() { + sed -e 's@driver/cmd/\.\./\.\./@@g' \ + -e 's@driver/env/\.\./@driver/@g' \ + -e 's@src/build/\.\./@src/@g' \ + "$1" +} + bk_host_detect() { uname_s=$(uname -s) uname_m=$(uname -m) @@ -217,12 +227,41 @@ bk_flat_obj() { printf '%s/%s/%s/%s\n' "$KIT_BUILD_OUT" "$dest" "$dir" "$flat" } +bk_flat_obj_rel() { + src=$1 + root=$2 + dest=$3 + rel=${src#"$root"/} + dir=$(dirname "$rel") + base=${rel%.c} + flat=$(printf '%s' "$base" | tr '/' '_').o + if [ "$dir" = "." ]; then + printf '%s/%s\n' "$dest" "$flat" + else + printf '%s/%s/%s\n' "$dest" "$dir" "$flat" + fi +} + bk_driver_obj() { src=$1 rel=${src#driver/} printf '%s/driver/%s.o\n' "$KIT_BUILD_OUT" "${rel%.c}" } +bk_driver_obj_rel() { + src=$1 + rel=${src#driver/} + printf 'driver/%s.o\n' "${rel%.c}" +} + +bk_target_local() { + printf '%s\n' "${KIT_BUILD_TARGET##*:}" +} + +bk_obj_target() { + printf '%s\n' "$1" | sed 's@/@_@g; s@[.]c$@.o@' +} + bk_sort_words() { printf '%s\n' "$@" | awk 'NF' | sort -u } @@ -652,3 +691,180 @@ bk_version_defs() { host_triple=$(bk_config host.triple "$triple_arch-$triple_os") printf '%s\n' "-DKIT_VERSION_STR=\"$version\" -DKIT_BUILD_ID=\"$build_id\" -DKIT_HOST_TRIPLE=\"$host_triple\"" } + +bk_libkit_object_plan() { + for src in $(bk_lib_sources); do + flags=$BK_LIB_CFLAGS + root=src + dest=lib + case "$src" in + src/api/lang_registry.c) + flags="$BK_FREESTANDING_CFLAGS $BK_LIB_VISIBILITY_CFLAGS -Iinclude -Ilang -Isrc" + ;; + lang/cpp/*) + flags="$BK_FREESTANDING_CFLAGS $BK_LIB_VISIBILITY_CFLAGS -Iinclude -Ilang/cpp" + root=lang + dest=lang + ;; + lang/c/*) + flags="$BK_FREESTANDING_CFLAGS $BK_LIB_VISIBILITY_CFLAGS -Iinclude -Ilang/cpp -Ilang/c" + root=lang + dest=lang + ;; + lang/wasm/*) + flags="$BK_FREESTANDING_CFLAGS $BK_LIB_VISIBILITY_CFLAGS -Iinclude -Isrc -Ilang/wasm" + root=lang + dest=lang + ;; + lang/toy/*) + flags="$BK_FREESTANDING_CFLAGS $BK_LIB_VISIBILITY_CFLAGS -Iinclude -Ilang/toy" + root=lang + dest=lang + ;; + vendor/*) + root=vendor + dest=vendor + ;; + esac + printf '%s|%s|%s|%s\n' \ + "$(bk_obj_target "$src")" "$src" \ + "$(bk_flat_obj_rel "$src" "$root" "$dest")" "$flags" + done +} + +bk_driver_object_plan() { + version_defs=$(bk_version_defs) + for src in $(bk_driver_sources); do + flags=$BK_DRIVER_CFLAGS + case "$src" in + driver/env/*) + flags="$BK_DRIVER_ENV_CFLAGS $BK_DRIVER_ENV_OS_CFLAGS" + ;; + esac + case "$src" in + driver/version.c) + flags="$flags $version_defs" + ;; + esac + printf '%s|%s|%s|%s\n' \ + "$(bk_obj_target "$src")" "$src" "$(bk_driver_obj_rel "$src")" \ + "$flags" + done +} + +bk_object_plan() { + case "$1" in + driver) bk_driver_object_plan ;; + libkit) bk_libkit_object_plan ;; + libkit-*.objs) + set_id=${1#libkit-} + set_id=${set_id%.objs} + bk_libkit_object_plan | awk -F '|' -v set_id="$set_id" ' + BEGIN { limit = 60; first = set_id * limit + 1; last = first + limit - 1 } + NR >= first && NR <= last { print } + ' + ;; + *) + echo "unknown object plan: $1" >&2 + return 1 + ;; + esac +} + +bk_libkit_object_sets() { + bk_libkit_object_plan | awk ' + BEGIN { limit = 60 } + (NR - 1) % limit == 0 { printf "libkit-%u.objs\n", int((NR - 1) / limit) } + ' +} + +bk_object_plan_find() { + if bk_libkit_object_plan | awk -F '|' -v target="$1" ' + $1 == target { print; found = 1; exit } + END { if (!found) exit 1 } + '; then + return 0 + fi + bk_driver_object_plan | awk -F '|' -v target="$1" ' + $1 == target { print; found = 1; exit } + END { if (!found) exit 1 } + ' +} + +bk_copy_runtime_support() { + find rt -type f | sort | while IFS= read -r rt_file; do + src=$(bk_source "$rt_file") + dst="$KIT_BUILD_OUT/support/rt/$rt_file" + mkdir -p "$(dirname "$dst")" + cp "$src" "$dst" + done +} + +c_flags_init() { + bk_flags_init + C_CC=$BK_CC + C_AR=$BK_AR + C_CFLAGS="" + C_LDFLAGS=$BK_HOST_LDFLAGS + C_LDLIBS=$BK_HOST_LDLIBS +} + +c_object_plan() { + bk_object_plan "$1" +} + +c_object_plan_find() { + bk_object_plan_find "$1" +} + +c_archive_output() { + case "$1" in + libkit) printf '%s\n' libkit.a ;; + *) + echo "no static-library plan for target: $KIT_BUILD_TARGET" >&2 + return 1 + ;; + esac +} + +c_archive_object_sets() { + case "$1" in + libkit) bk_libkit_object_sets ;; + *) + echo "no static-library object sets for target: $KIT_BUILD_TARGET" >&2 + return 1 + ;; + esac +} + +c_executable_output() { + case "$1" in + kit) printf '%s\n' kit ;; + *) + echo "no executable plan for target: $KIT_BUILD_TARGET" >&2 + return 1 + ;; + esac +} + +c_executable_object_sets() { + case "$1" in + kit) printf '%s\n' //:driver ;; + esac +} + +c_executable_libraries() { + case "$1" in + kit) printf '%s\n' '//:libkit|libkit.a' ;; + esac +} + +c_executable_after_link() { + case "$1" in + kit) + lib_dir=$("$KIT" build need //:libkit) + cp "$lib_dir/libkit.a" "$KIT_BUILD_OUT/libkit.a" + bk_copy_runtime_support + ;; + esac +} diff --git a/recipes/buildkit/driver.sh b/recipes/buildkit/driver.sh @@ -1,30 +0,0 @@ -#!/bin/sh -set -eu - -: "${KIT:=./build/kit}" -common=$("$KIT" build source recipes/buildkit/common.sh) -. "$common" - -bk_flags_init -mkdir -p "$KIT_BUILD_OUT" - -objects="$KIT_BUILD_OUT/objects.list" -: > "$objects" -version_defs=$(bk_version_defs) - -for src in $(bk_driver_sources); do - flags=$BK_DRIVER_CFLAGS - case "$src" in - driver/env/*) - flags="$BK_DRIVER_ENV_CFLAGS $BK_DRIVER_ENV_OS_CFLAGS" - ;; - esac - case "$src" in - driver/version.c) - flags="$flags $version_defs" - ;; - esac - obj=$(bk_driver_obj "$src") - bk_compile "$src" "$obj" "$flags" - printf '%s\n' "${obj#"$KIT_BUILD_OUT"/}" >> "$objects" -done diff --git a/recipes/buildkit/kit.sh b/recipes/buildkit/kit.sh @@ -1,30 +0,0 @@ -#!/bin/sh -set -eu - -: "${KIT:=./build/kit}" -common=$("$KIT" build source recipes/buildkit/common.sh) -. "$common" - -bk_flags_init -mkdir -p "$KIT_BUILD_OUT" - -driver_dir=$("$KIT" build need //:driver) -lib_dir=$("$KIT" build need //:libkit) - -objs= -while IFS= read -r obj; do - [ -n "$obj" ] || continue - objs="$objs $driver_dir/$obj" -done < "$driver_dir/objects.list" - -# shellcheck disable=SC2086 -"$BK_CC" $BK_HOST_LDFLAGS -o "$KIT_BUILD_OUT/kit" $objs \ - "$lib_dir/libkit.a" $BK_HOST_LDLIBS -cp "$lib_dir/libkit.a" "$KIT_BUILD_OUT/libkit.a" - -find rt -type f | sort | while IFS= read -r rt_file; do - src=$(bk_source "$rt_file") - dst="$KIT_BUILD_OUT/support/rt/$rt_file" - mkdir -p "$(dirname "$dst")" - cp "$src" "$dst" -done diff --git a/recipes/buildkit/libkit.sh b/recipes/buildkit/libkit.sh @@ -1,56 +0,0 @@ -#!/bin/sh -set -eu - -: "${KIT:=./build/kit}" -common=$("$KIT" build source recipes/buildkit/common.sh) -. "$common" - -bk_flags_init -mkdir -p "$KIT_BUILD_OUT" - -objects="$KIT_BUILD_OUT/objects.list" -: > "$objects" - -for src in $(bk_lib_sources); do - flags=$BK_LIB_CFLAGS - root=src - dest=lib - case "$src" in - src/api/lang_registry.c) - flags="$BK_FREESTANDING_CFLAGS $BK_LIB_VISIBILITY_CFLAGS -Iinclude -Ilang -Isrc" - ;; - lang/cpp/*) - flags="$BK_FREESTANDING_CFLAGS $BK_LIB_VISIBILITY_CFLAGS -Iinclude -Ilang/cpp" - root=lang - dest=lang - ;; - lang/c/*) - flags="$BK_FREESTANDING_CFLAGS $BK_LIB_VISIBILITY_CFLAGS -Iinclude -Ilang/cpp -Ilang/c" - root=lang - dest=lang - ;; - lang/wasm/*) - flags="$BK_FREESTANDING_CFLAGS $BK_LIB_VISIBILITY_CFLAGS -Iinclude -Isrc -Ilang/wasm" - root=lang - dest=lang - ;; - lang/toy/*) - flags="$BK_FREESTANDING_CFLAGS $BK_LIB_VISIBILITY_CFLAGS -Iinclude -Ilang/toy" - root=lang - dest=lang - ;; - vendor/*) - root=vendor - dest=vendor - ;; - esac - obj=$(bk_flat_obj "$src" "$root" "$dest") - bk_compile "$src" "$obj" "$flags" - printf '%s\n' "$obj" >> "$objects" -done - -rm -f "$KIT_BUILD_OUT/libkit.a" -# shellcheck disable=SC2046 -"$BK_AR" rcs "$KIT_BUILD_OUT/libkit.a" $(cat "$objects") -find "$KIT_BUILD_OUT" -type f ! -name libkit.a -delete -find "$KIT_BUILD_OUT" -type d -empty -delete diff --git a/rules/c/common.sh b/rules/c/common.sh @@ -0,0 +1,212 @@ +#!/bin/sh + +set -eu + +: "${KIT:=./build/kit}" + +c_source() { + "$KIT" build source "$1" +} + +c_config() { + key=$1 + def=$2 + "$KIT" build config-get --default "$def" "$key" +} + +c_config_merge() { + key=$1 + def=$2 + profile=$(c_config profile "") + base=$(c_config "$key" "$def") + prof="" + extra=$(c_config "$key.extra" "") + if [ -n "$profile" ]; then + prof=$(c_config "profile.$profile.$key" "") + fi + printf '%s\n' "$base $prof $extra" | awk '{$1=$1; print}' +} + +c_toolchain_init() { + C_CC=$(c_config tool.c.cc "$(c_config cc "${CC:-cc}")") + C_AR=$(c_config tool.c.ar "$(c_config ar "${AR:-ar}")") + C_CFLAGS=$(c_config_merge tool.c.cflags "") + C_LDFLAGS=$(c_config_merge tool.c.ldflags "") + C_LDLIBS=$(c_config_merge tool.c.ldlibs "") +} + +c_glob() { + "$KIT" build glob "$1" +} + +c_depfile() { + if [ -s "$1" ]; then + dep=$1 + if command -v c_depfile_filter >/dev/null 2>&1; then + norm="$dep.norm" + c_depfile_filter "$dep" > "$norm" + dep=$norm + fi + "$KIT" build depfile "$dep" >/dev/null + rm -f "$1" "${1}.norm" + fi +} + +c_compile() { + src=$1 + obj=$2 + flags=$3 + mkdir -p "$(dirname "$obj")" + dep="$obj.d" + "$C_CC" $C_CFLAGS $flags -MMD -MP -MF "$dep" -c "$src" -o "$obj" + c_depfile "$dep" +} + +c_need() { + label=$1 + case "$label" in + :*|//*|@*) "$KIT" build need "$label" ;; + *) "$KIT" build need ":$label" ;; + esac +} + +c_target_local() { + if [ -n "${KIT_BUILD_LOCAL:-}" ]; then + printf '%s\n' "$KIT_BUILD_LOCAL" + else + printf '%s\n' "${KIT_BUILD_TARGET##*:}" + fi +} + +c_require_hook() { + if ! command -v "$1" >/dev/null 2>&1; then + echo "missing C rule hook: $1" >&2 + exit 1 + fi +} + +c_flags_init_default() { + if command -v c_flags_init >/dev/null 2>&1; then + c_flags_init + else + c_toolchain_init + fi +} + +c_default_object() { + c_flags_init_default + c_require_hook c_object_plan_find + local=$(c_target_local) + line=$(c_object_plan_find "$local") || { + echo "no C object plan for target: $KIT_BUILD_TARGET" >&2 + exit 1 + } + + target=${line%%|*} + rest=${line#*|} + src=${rest%%|*} + rest=${rest#*|} + obj_rel=${rest%%|*} + flags=${rest#*|} + + [ "$target" = "$local" ] || exit 1 + + mkdir -p "$KIT_BUILD_OUT/obj" + c_compile "$src" "$KIT_BUILD_OUT/obj/$local" "$flags" + printf '%s\n' "obj/$local" > "$KIT_BUILD_OUT/object.list" + printf '%s\n' "$obj_rel" > "$KIT_BUILD_OUT/object.rel" + printf '%s\n' "$src" > "$KIT_BUILD_OUT/source.txt" +} + +c_default_objects() { + c_flags_init_default + c_require_hook c_object_plan + local=$(c_target_local) + mkdir -p "$KIT_BUILD_OUT" + objects="$KIT_BUILD_OUT/objects.list" + : > "$objects" + + c_object_plan "$local" | while IFS='|' read -r _target src obj_rel flags; do + [ -n "$src" ] || continue + dst="$KIT_BUILD_OUT/$obj_rel" + mkdir -p "$(dirname "$dst")" + c_compile "$src" "$dst" "$flags" + printf '%s\n' "$obj_rel" >> "$objects" + done +} + +c_default_archive() { + c_flags_init_default + c_require_hook c_archive_output + c_require_hook c_archive_object_sets + local=$(c_target_local) + mkdir -p "$KIT_BUILD_OUT" + archive=$(c_archive_output "$local") + objects="$KIT_BUILD_OUT/archive-objects.list" + : > "$objects" + + c_archive_object_sets "$local" | while IFS= read -r set_target; do + [ -n "$set_target" ] || continue + dep=$(c_need "$set_target") + while IFS= read -r obj; do + [ -n "$obj" ] || continue + printf '%s/%s\n' "$dep" "$obj" >> "$objects" + done < "$dep/objects.list" + done + + rm -f "$KIT_BUILD_OUT/$archive" + # shellcheck disable=SC2046 + "$C_AR" rcs "$KIT_BUILD_OUT/$archive" $(cat "$objects") + rm -f "$objects" +} + +c_default_executable() { + c_flags_init_default + c_require_hook c_executable_output + local=$(c_target_local) + mkdir -p "$KIT_BUILD_OUT" + exe=$(c_executable_output "$local") + objs= + libs= + + if command -v c_executable_object_sets >/dev/null 2>&1; then + for set_target in $(c_executable_object_sets "$local"); do + dep=$(c_need "$set_target") + while IFS= read -r obj; do + [ -n "$obj" ] || continue + objs="$objs $dep/$obj" + done < "$dep/objects.list" + done + fi + + if command -v c_executable_libraries >/dev/null 2>&1; then + c_executable_libraries "$local" | while IFS='|' read -r label file; do + [ -n "$label" ] || continue + dep=$(c_need "$label") + printf '%s/%s\n' "$dep" "$file" >> "$KIT_BUILD_OUT/.link-libs" + done + if [ -f "$KIT_BUILD_OUT/.link-libs" ]; then + while IFS= read -r lib; do + libs="$libs $lib" + done < "$KIT_BUILD_OUT/.link-libs" + rm -f "$KIT_BUILD_OUT/.link-libs" + fi + fi + + target_ldflags="" + target_ldlibs="" + if command -v c_executable_ldflags >/dev/null 2>&1; then + target_ldflags=$(c_executable_ldflags "$local") + fi + if command -v c_executable_ldlibs >/dev/null 2>&1; then + target_ldlibs=$(c_executable_ldlibs "$local") + fi + + # shellcheck disable=SC2086 + "$C_CC" $C_LDFLAGS $target_ldflags -o "$KIT_BUILD_OUT/$exe" \ + $objs $libs $target_ldlibs $C_LDLIBS + + if command -v c_executable_after_link >/dev/null 2>&1; then + c_executable_after_link "$local" + fi +} diff --git a/rules/c/default.a.do b/rules/c/default.a.do @@ -0,0 +1,11 @@ +#!/bin/sh +set -eu + +: "${KIT:=./build/kit}" +rules=$("$KIT" build source rules/c/common.sh) +. "$rules" +project=$("$KIT" build config-get --default do/c.sh tool.c.project) +project_src=$("$KIT" build source "$project") +. "$project_src" + +c_default_archive diff --git a/rules/c/default.exe.do b/rules/c/default.exe.do @@ -0,0 +1,11 @@ +#!/bin/sh +set -eu + +: "${KIT:=./build/kit}" +rules=$("$KIT" build source rules/c/common.sh) +. "$rules" +project=$("$KIT" build config-get --default do/c.sh tool.c.project) +project_src=$("$KIT" build source "$project") +. "$project_src" + +c_default_executable diff --git a/rules/c/default.o.do b/rules/c/default.o.do @@ -0,0 +1,11 @@ +#!/bin/sh +set -eu + +: "${KIT:=./build/kit}" +rules=$("$KIT" build source rules/c/common.sh) +. "$rules" +project=$("$KIT" build config-get --default do/c.sh tool.c.project) +project_src=$("$KIT" build source "$project") +. "$project_src" + +c_default_object diff --git a/rules/c/default.objs.do b/rules/c/default.objs.do @@ -0,0 +1,11 @@ +#!/bin/sh +set -eu + +: "${KIT:=./build/kit}" +rules=$("$KIT" build source rules/c/common.sh) +. "$rules" +project=$("$KIT" build config-get --default do/c.sh tool.c.project) +project_src=$("$KIT" build source "$project") +. "$project_src" + +c_default_objects diff --git a/src/build/runner.c b/src/build/runner.c @@ -28,6 +28,51 @@ static int target_copy(KitSlice target, char out[BUILD_TARGET_MAX]) { return BUILD_OK; } +typedef struct BuildRunScratch { + BuildConfigLeaf configs[BUILD_RECIPE_CONFIG_CAP]; + BuildSourceLeaf sources[BUILD_RECIPE_SOURCE_CAP]; + BuildGlobLeaf globs[BUILD_RECIPE_GLOB_CAP]; + BuildBlobLeaf blobs[BUILD_RECIPE_BLOB_CAP]; + BuildDepEdge deps[BUILD_RECIPE_DEP_CAP]; + const BuildLeafSet* child_leafsets[BUILD_RECIPE_DEP_CAP]; + BuildPendingNeed pending[BUILD_RECIPE_DEP_CAP]; +} BuildRunScratch; + +static BuildRunScratch* build_run_scratch_new(KitBuildCoordinator* c) { + BuildRunScratch* s; + if (!c || !c->ctx || !c->ctx->heap) return NULL; + s = (BuildRunScratch*)c->ctx->heap->alloc(c->ctx->heap, sizeof *s, + _Alignof(BuildRunScratch)); + if (s) memset(s, 0, sizeof *s); + return s; +} + +static void build_run_scratch_free(KitBuildCoordinator* c, + BuildRunScratch* s) { + if (c && c->ctx && c->ctx->heap && s) + c->ctx->heap->free(c->ctx->heap, s, sizeof *s); +} + +static void build_dep_log_init(BuildDepLog* log, BuildRunScratch* scratch) { + memset(log, 0, sizeof *log); + log->configs = scratch->configs; + log->cap_configs = sizeof scratch->configs / sizeof scratch->configs[0]; + log->sources = scratch->sources; + log->cap_sources = sizeof scratch->sources / sizeof scratch->sources[0]; + log->globs = scratch->globs; + log->cap_globs = sizeof scratch->globs / sizeof scratch->globs[0]; + log->blobs = scratch->blobs; + log->cap_blobs = sizeof scratch->blobs / sizeof scratch->blobs[0]; + log->deps = scratch->deps; + log->cap_deps = sizeof scratch->deps / sizeof scratch->deps[0]; + log->child_leafsets = scratch->child_leafsets; + log->cap_children = + sizeof scratch->child_leafsets / sizeof scratch->child_leafsets[0]; + log->pending = scratch->pending; + log->cap_pending = sizeof scratch->pending / sizeof scratch->pending[0]; + log->next_token = 1; +} + static void hash_slice(KitSlice s, uint8_t out[BUILD_HASH_LEN]) { KitBlobInfo bi; static const uint8_t empty = 0; @@ -374,18 +419,12 @@ static int build_run_recipe_impl(KitBuildCoordinator* c, KitSlice target, char sandbox[BUILD_PATH_MAX]; char out_dir[BUILD_PATH_MAX]; KitSlice proc_argv[129]; - KitBuildKV env[132]; + KitBuildKV env[140]; char env_keys[128][BUILD_KEY_MAX]; - size_t argc = 0, nenv = 0, i; + size_t argc = 0, nenv = 0, i, base_nenv = 0; int exit_code = 1; int ok = BUILD_ERR; - BuildConfigLeaf configs[BUILD_RECIPE_CONFIG_CAP]; - BuildSourceLeaf sources[BUILD_RECIPE_SOURCE_CAP]; - BuildGlobLeaf globs[BUILD_RECIPE_GLOB_CAP]; - BuildBlobLeaf blobs[BUILD_RECIPE_BLOB_CAP]; - BuildDepEdge deps[BUILD_RECIPE_DEP_CAP]; - const BuildLeafSet* child_leafsets[BUILD_RECIPE_DEP_CAP]; - BuildPendingNeed pending[BUILD_RECIPE_DEP_CAP]; + BuildRunScratch* scratch = NULL; BuildDepLog log; if (!c || !cfg || !argv || !out || !c->host.exec || !c->host.transport) @@ -404,22 +443,9 @@ static int build_run_recipe_impl(KitBuildCoordinator* c, KitSlice target, sizeof out_dir) != BUILD_OK) goto out_cleanup; - memset(&log, 0, sizeof log); - log.configs = configs; - log.cap_configs = sizeof configs / sizeof configs[0]; - log.sources = sources; - log.cap_sources = sizeof sources / sizeof sources[0]; - log.globs = globs; - log.cap_globs = sizeof globs / sizeof globs[0]; - log.blobs = blobs; - log.cap_blobs = sizeof blobs / sizeof blobs[0]; - log.deps = deps; - log.cap_deps = sizeof deps / sizeof deps[0]; - log.child_leafsets = child_leafsets; - log.cap_children = sizeof child_leafsets / sizeof child_leafsets[0]; - log.pending = pending; - log.cap_pending = sizeof pending / sizeof pending[0]; - log.next_token = 1; + scratch = build_run_scratch_new(c); + if (!scratch) goto out_cleanup; + build_dep_log_init(&log, scratch); proc_argv[argc++] = kit_slice_cstr(recipe.recipe_abspath); for (i = 0; i < argv->n && argc < sizeof proc_argv / sizeof proc_argv[0]; @@ -433,18 +459,26 @@ static int build_run_recipe_impl(KitBuildCoordinator* c, KitSlice target, env[nenv++].value = kit_slice_cstr(out_dir); env[nenv].key = KIT_SLICE_LIT(KIT_BUILD_ENV_TARGET); env[nenv++].value = target; + env[nenv].key = KIT_SLICE_LIT(KIT_BUILD_ENV_REPO); + env[nenv++].value = kit_slice_cstr(recipe.repo); env[nenv].key = KIT_SLICE_LIT(KIT_BUILD_ENV_PACKAGE); env[nenv++].value = kit_slice_cstr(recipe.package); - for (i = 0; i < cfg->n && nenv < sizeof env / sizeof env[0]; ++i) { + env[nenv].key = KIT_SLICE_LIT(KIT_BUILD_ENV_LOCAL); + env[nenv++].value = kit_slice_cstr(recipe.local_name); + base_nenv = nenv; + for (i = 0; i < cfg->n && nenv < sizeof env / sizeof env[0] && + nenv - base_nenv < sizeof env_keys / sizeof env_keys[0]; + ++i) { const char* key = cfg->entries[i].key; size_t prefix_len = sizeof(KIT_BUILD_ENV_PREFIX) - 1u; if (strncmp(key, KIT_BUILD_ENV_PREFIX, prefix_len) != 0) continue; if (append_config_observation(&log, cfg, kit_slice_cstr(key), KIT_SLICE_NULL, 0) != BUILD_OK) goto out_cleanup; - snprintf(env_keys[nenv - 4u], sizeof env_keys[nenv - 4u], "%s", + snprintf(env_keys[nenv - base_nenv], + sizeof env_keys[nenv - base_nenv], "%s", key + prefix_len); - env[nenv].key = kit_slice_cstr(env_keys[nenv - 4u]); + env[nenv].key = kit_slice_cstr(env_keys[nenv - base_nenv]); env[nenv].value = kit_slice_cstr(cfg->entries[i].value); ++nenv; } @@ -481,6 +515,7 @@ out_cleanup: if (listener) c->host.transport->close_listener(c->host.transport->user, listener); if (sandbox[0]) build_store_sandbox_done(&c->store, sandbox); + build_run_scratch_free(c, scratch); return ok; } @@ -500,18 +535,12 @@ static int build_run_test_recipe_impl(KitBuildCoordinator* c, KitSlice target, char stdout_path[BUILD_PATH_MAX]; char stderr_path[BUILD_PATH_MAX]; KitSlice proc_argv[129]; - KitBuildKV env[132]; + KitBuildKV env[140]; char env_keys[128][BUILD_KEY_MAX]; - size_t argc = 0, nenv = 0, i; + size_t argc = 0, nenv = 0, i, base_nenv = 0; int exit_code = 1; int ok = BUILD_ERR; - BuildConfigLeaf configs[BUILD_RECIPE_CONFIG_CAP]; - BuildSourceLeaf sources[BUILD_RECIPE_SOURCE_CAP]; - BuildGlobLeaf globs[BUILD_RECIPE_GLOB_CAP]; - BuildBlobLeaf blobs[BUILD_RECIPE_BLOB_CAP]; - BuildDepEdge deps[BUILD_RECIPE_DEP_CAP]; - const BuildLeafSet* child_leafsets[BUILD_RECIPE_DEP_CAP]; - BuildPendingNeed pending[BUILD_RECIPE_DEP_CAP]; + BuildRunScratch* scratch = NULL; BuildDepLog log; if (!c || !cfg || !argv || !out || !c->host.exec || !c->host.transport || @@ -538,22 +567,9 @@ static int build_run_test_recipe_impl(KitBuildCoordinator* c, KitSlice target, BUILD_OK) goto out_cleanup; - memset(&log, 0, sizeof log); - log.configs = configs; - log.cap_configs = sizeof configs / sizeof configs[0]; - log.sources = sources; - log.cap_sources = sizeof sources / sizeof sources[0]; - log.globs = globs; - log.cap_globs = sizeof globs / sizeof globs[0]; - log.blobs = blobs; - log.cap_blobs = sizeof blobs / sizeof blobs[0]; - log.deps = deps; - log.cap_deps = sizeof deps / sizeof deps[0]; - log.child_leafsets = child_leafsets; - log.cap_children = sizeof child_leafsets / sizeof child_leafsets[0]; - log.pending = pending; - log.cap_pending = sizeof pending / sizeof pending[0]; - log.next_token = 1; + scratch = build_run_scratch_new(c); + if (!scratch) goto out_cleanup; + build_dep_log_init(&log, scratch); proc_argv[argc++] = kit_slice_cstr(recipe.recipe_abspath); for (i = 0; i < argv->n && argc < sizeof proc_argv / sizeof proc_argv[0]; @@ -567,18 +583,26 @@ static int build_run_test_recipe_impl(KitBuildCoordinator* c, KitSlice target, env[nenv++].value = kit_slice_cstr(out_dir); env[nenv].key = KIT_SLICE_LIT(KIT_BUILD_ENV_TARGET); env[nenv++].value = target; + env[nenv].key = KIT_SLICE_LIT(KIT_BUILD_ENV_REPO); + env[nenv++].value = kit_slice_cstr(recipe.repo); env[nenv].key = KIT_SLICE_LIT(KIT_BUILD_ENV_PACKAGE); env[nenv++].value = kit_slice_cstr(recipe.package); - for (i = 0; i < cfg->n && nenv < sizeof env / sizeof env[0]; ++i) { + env[nenv].key = KIT_SLICE_LIT(KIT_BUILD_ENV_LOCAL); + env[nenv++].value = kit_slice_cstr(recipe.local_name); + base_nenv = nenv; + for (i = 0; i < cfg->n && nenv < sizeof env / sizeof env[0] && + nenv - base_nenv < sizeof env_keys / sizeof env_keys[0]; + ++i) { const char* key = cfg->entries[i].key; size_t prefix_len = sizeof(KIT_BUILD_ENV_PREFIX) - 1u; if (strncmp(key, KIT_BUILD_ENV_PREFIX, prefix_len) != 0) continue; if (append_config_observation(&log, cfg, kit_slice_cstr(key), KIT_SLICE_NULL, 0) != BUILD_OK) goto out_cleanup; - snprintf(env_keys[nenv - 4u], sizeof env_keys[nenv - 4u], "%s", + snprintf(env_keys[nenv - base_nenv], + sizeof env_keys[nenv - base_nenv], "%s", key + prefix_len); - env[nenv].key = kit_slice_cstr(env_keys[nenv - 4u]); + env[nenv].key = kit_slice_cstr(env_keys[nenv - base_nenv]); env[nenv].value = kit_slice_cstr(cfg->entries[i].value); ++nenv; } @@ -626,6 +650,7 @@ out_cleanup: if (listener) c->host.transport->close_listener(c->host.transport->user, listener); if (sandbox[0]) build_store_sandbox_done(&c->store, sandbox); + build_run_scratch_free(c, scratch); return ok; } diff --git a/test/buildcoord/run.sh b/test/buildcoord/run.sh @@ -353,6 +353,9 @@ set -eu mkdir -p "$KIT_BUILD_OUT" printf 'ambient:%s\n' "${AMBIENT-unset}" > "$KIT_BUILD_OUT/env.txt" printf 'declared:%s\n' "${DECLARED-unset}" >> "$KIT_BUILD_OUT/env.txt" +printf 'repo:%s\n' "${KIT_BUILD_REPO-unset}" >> "$KIT_BUILD_OUT/env.txt" +printf 'package:%s\n' "${KIT_BUILD_PACKAGE-unset}" >> "$KIT_BUILD_OUT/env.txt" +printf 'local:%s\n' "${KIT_BUILD_LOCAL-unset}" >> "$KIT_BUILD_OUT/env.txt" EOF cat > "$ws/recipes/exports_provider.sh" <<'EOF' @@ -1821,6 +1824,10 @@ contains "buildcoord-env-clean-ambient" "$env_one_path/env.txt" \ "ambient:unset" contains "buildcoord-env-declared-visible" "$env_one_path/env.txt" \ "declared:one" +contains "buildcoord-env-target-repo" "$env_one_path/env.txt" "repo:" +contains "buildcoord-env-target-package" "$env_one_path/env.txt" \ + "package:env" +contains "buildcoord-env-target-local" "$env_one_path/env.txt" "local:probe" unset MISSING_BUILDCOORD_ENV run_fail "buildcoord-env-shorthand-unset-rejected" \