kit

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

commit 556472c785d8cf94ad8f9f5c376ad127b39975d4
parent d79afab6903f07ccae1fe5b750fbaa371ea62599
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Mon, 25 May 2026 13:21:08 -0700

Add release build toggle

Diffstat:
MMakefile | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
Mdriver/nm.c | 62+++++++++++++++++++++++++++++++++++++++++++++++---------------
Mtest/test.mk | 7++++---
3 files changed, 108 insertions(+), 32 deletions(-)

diff --git a/Makefile b/Makefile @@ -3,18 +3,55 @@ AR = ar LD = ld BUILD_DIR ?= build SYSROOT = $(shell xcrun --show-sdk-path) -HOST_OPTFLAGS ?= -O1 +RELEASE ?= 0 +.DEFAULT_GOAL := all + +ifeq ($(RELEASE),1) +HOST_OPTFLAGS ?= -O2 +HOST_MODE_CPPFLAGS = -DNDEBUG +HOST_MODE_CFLAGS = +HOST_MODE_LDFLAGS = +else +HOST_OPTFLAGS ?= -O0 +HOST_MODE_CPPFLAGS = +HOST_MODE_CFLAGS = -g3 -fno-omit-frame-pointer -fno-optimize-sibling-calls \ + -fsanitize=address,undefined \ + -fno-sanitize-recover=address,undefined \ + -fsanitize-address-use-after-scope +HOST_MODE_LDFLAGS = -fsanitize=address,undefined +ASAN_OPTIONS ?= halt_on_error=1:abort_on_error=1 +UBSAN_OPTIONS ?= halt_on_error=1:print_stacktrace=1 +export ASAN_OPTIONS UBSAN_OPTIONS +endif # -isysroot lives in its own var so stage/bootstrap recipes can override # host SDK handling when cfree is used as the compiler. HOST_SYSROOT_CFLAGS = -isysroot $(SYSROOT) HOST_SYSROOT_LDFLAGS = -isysroot $(SYSROOT) -CFLAGS_COMMON = $(HOST_OPTFLAGS) -std=c11 -Wpedantic -Wall -Wextra -Werror +CFLAGS_COMMON = $(HOST_OPTFLAGS) $(HOST_MODE_CPPFLAGS) $(HOST_MODE_CFLAGS) \ + -std=c11 -Wpedantic -Wall -Wextra -Werror HOST_CFLAGS = $(CFLAGS_COMMON) $(HOST_SYSROOT_CFLAGS) +HOST_LDFLAGS = $(HOST_SYSROOT_LDFLAGS) $(HOST_MODE_LDFLAGS) DEPFLAGS = -MMD -MP +BUILD_CONFIG = $(BUILD_DIR)/.build-config + +.PHONY: FORCE +FORCE: + +$(BUILD_CONFIG): FORCE + @mkdir -p $(dir $@) + @{ \ + printf '%s\n' 'RELEASE=$(RELEASE)'; \ + printf '%s\n' 'HOST_OPTFLAGS=$(HOST_OPTFLAGS)'; \ + printf '%s\n' 'HOST_MODE_CPPFLAGS=$(HOST_MODE_CPPFLAGS)'; \ + printf '%s\n' 'HOST_MODE_CFLAGS=$(HOST_MODE_CFLAGS)'; \ + printf '%s\n' 'HOST_MODE_LDFLAGS=$(HOST_MODE_LDFLAGS)'; \ + } > $@.tmp + @if ! cmp -s $@.tmp $@; then mv $@.tmp $@; else rm -f $@.tmp; fi + # Freestanding objects must not see host SDK/libc headers. Homebrew clang can # also inject a configured sysroot before command-line flags; use # --no-default-config when the selected compiler supports it, but omit it for @@ -177,7 +214,7 @@ bin: $(BIN) # Replace the archive (`ar rcs` only adds/updates), so removing a .c file # also removes its .o from the archive on the next build. -$(LIB_RELOC_OBJ): $(LIB_OBJS) +$(LIB_RELOC_OBJ): $(LIB_OBJS) $(BUILD_CONFIG) @mkdir -p $(dir $@) @rm -f $@ $(LD) -r -o $@ $(LIB_OBJS) @@ -187,47 +224,47 @@ $(LIB_AR): $(LIB_RELOC_OBJ) @rm -f $@ $(AR) rcs $@ $(LIB_RELOC_OBJ) -$(BIN): $(DRIVER_OBJS) $(LIB_AR) - $(CC) $(HOST_SYSROOT_LDFLAGS) -o $@ $(DRIVER_OBJS) $(LIB_AR) +$(BIN): $(DRIVER_OBJS) $(LIB_AR) $(BUILD_CONFIG) + $(CC) $(HOST_LDFLAGS) -o $@ $(DRIVER_OBJS) $(LIB_AR) -$(BUILD_DIR)/lib/%.o: src/%.c Makefile +$(BUILD_DIR)/lib/%.o: src/%.c Makefile $(BUILD_CONFIG) @mkdir -p $(dir $@) $(CC) $(LIB_CFLAGS) $(DEPFLAGS) -c $< -o $@ # lang_registry.c is the one libcfree source that crosses into lang/*; it # uses -Ilang so the frontend headers can be reached as "c/c.h" etc. -$(BUILD_DIR)/lib/api/lang_registry.o: src/api/lang_registry.c Makefile +$(BUILD_DIR)/lib/api/lang_registry.o: src/api/lang_registry.c Makefile $(BUILD_CONFIG) @mkdir -p $(dir $@) $(CC) $(LIB_CFLAGS) -Ilang $(DEPFLAGS) -c $< -o $@ -$(BUILD_DIR)/lang/cpp/%.o: lang/cpp/%.c Makefile +$(BUILD_DIR)/lang/cpp/%.o: lang/cpp/%.c Makefile $(BUILD_CONFIG) @mkdir -p $(dir $@) $(CC) $(FREESTANDING_CFLAGS) -Iinclude -Ilang/cpp $(DEPFLAGS) -c $< -o $@ # The C frontend includes the lexer and preprocessor headers (pp/pp.h, # lex/lex.h) which now live under lang/cpp/, and cpp_support.h is the # shared substrate. So lang/c objects build with -Ilang/cpp -Ilang/c. -$(BUILD_DIR)/lang/c/%.o: lang/c/%.c Makefile +$(BUILD_DIR)/lang/c/%.o: lang/c/%.c Makefile $(BUILD_CONFIG) @mkdir -p $(dir $@) $(CC) $(FREESTANDING_CFLAGS) -Iinclude -Ilang/cpp -Ilang/c $(DEPFLAGS) -c $< -o $@ -$(BUILD_DIR)/lang/wasm/%.o: lang/wasm/%.c Makefile +$(BUILD_DIR)/lang/wasm/%.o: lang/wasm/%.c Makefile $(BUILD_CONFIG) @mkdir -p $(dir $@) $(CC) $(FREESTANDING_CFLAGS) -Iinclude -Ilang/wasm $(DEPFLAGS) -c $< -o $@ -$(BUILD_DIR)/lib/%.o: src/%.S Makefile +$(BUILD_DIR)/lib/%.o: src/%.S Makefile $(BUILD_CONFIG) @mkdir -p $(dir $@) $(CC) $(LIB_CFLAGS) $(DEPFLAGS) -c $< -o $@ -$(BUILD_DIR)/driver/%.o: driver/%.c Makefile +$(BUILD_DIR)/driver/%.o: driver/%.c Makefile $(BUILD_CONFIG) @mkdir -p $(dir $@) $(CC) $(DRIVER_CFLAGS) $(DEPFLAGS) -c $< -o $@ -$(BUILD_DIR)/driver/env.o: driver/env.c Makefile +$(BUILD_DIR)/driver/env.o: driver/env.c Makefile $(BUILD_CONFIG) @mkdir -p $(dir $@) $(CC) $(DRIVER_ENV_CFLAGS) $(DEPFLAGS) -c $< -o $@ -$(BUILD_DIR)/lang/toy/%.o: lang/toy/%.c Makefile +$(BUILD_DIR)/lang/toy/%.o: lang/toy/%.c Makefile $(BUILD_CONFIG) @mkdir -p $(dir $@) $(CC) $(FREESTANDING_CFLAGS) -Iinclude -Ilang/toy $(DEPFLAGS) -c $< -o $@ @@ -252,14 +289,20 @@ bootstrap: $(BIN) rt @for tool in $(BOOTSTRAP_TOOLS); do ln -sf cfree "$(BOOTSTRAP_STAGE1_DIR)/$$tool"; done $(MAKE) lib bin \ BUILD_DIR='$(abspath $(BOOTSTRAP_STAGE2_DIR))' \ + RELEASE='$(RELEASE)' \ HOST_OPTFLAGS='$(HOST_OPTFLAGS)' \ + HOST_MODE_CFLAGS= \ + HOST_MODE_LDFLAGS= \ CC='$(abspath $(BOOTSTRAP_STAGE1_DIR))/cc' \ AR='$(abspath $(BOOTSTRAP_STAGE1_DIR))/ar' \ LD='$(abspath $(BOOTSTRAP_STAGE1_DIR))/ld' @for tool in $(BOOTSTRAP_TOOLS); do ln -sf cfree "$(BOOTSTRAP_STAGE2_DIR)/$$tool"; done $(MAKE) lib bin \ BUILD_DIR='$(abspath $(BOOTSTRAP_STAGE3_DIR))' \ + RELEASE='$(RELEASE)' \ HOST_OPTFLAGS='$(HOST_OPTFLAGS)' \ + HOST_MODE_CFLAGS= \ + HOST_MODE_LDFLAGS= \ CC='$(abspath $(BOOTSTRAP_STAGE2_DIR))/cc' \ AR='$(abspath $(BOOTSTRAP_STAGE2_DIR))/ar' \ LD='$(abspath $(BOOTSTRAP_STAGE2_DIR))/ld' diff --git a/driver/nm.c b/driver/nm.c @@ -96,16 +96,17 @@ static int nm_value_cmp(const void *a, const void *b) { return nm_name_cmp(a, b); } -static void nm_append_sym(DriverEnv *env, NmSym **syms, uint32_t *n, - uint32_t *cap, const CfreeObjSymInfo *si, - const char *file_prefix, int *ptr_digits, - CfreeTarget t) { +static int nm_append_sym(DriverEnv *env, NmSym **syms, uint32_t *n, + uint32_t *cap, const CfreeObjSymInfo *si, + const char *file_prefix, int *ptr_digits, + CfreeTarget t) { int d = (t.ptr_size == 4) ? 8 : 16; + char *name; if (d > *ptr_digits) *ptr_digits = d; if (*n >= *cap) { uint32_t nc = *cap ? *cap * 2u : 64u; NmSym *ns = (NmSym *)driver_alloc_zeroed(env, (size_t)nc * sizeof(NmSym)); - if (!ns) return; + if (!ns) return 1; if (*syms) { memcpy(ns, *syms, (size_t)(*n) * sizeof(NmSym)); driver_free(env, *syms, (size_t)(*cap) * sizeof(NmSym)); @@ -113,30 +114,40 @@ static void nm_append_sym(DriverEnv *env, NmSym **syms, uint32_t *n, *syms = ns; *cap = nc; } + name = (char *)driver_alloc(env, si->name.len); + if (!name) return 1; + driver_memcpy(name, si->name.s, si->name.len); NmSym *ds = &(*syms)[*n]; - ds->name = si->name; + ds->name.s = name; + ds->name.len = si->name.len; ds->value = si->value; ds->bind = si->bind; ds->kind = si->kind; ds->defined = (si->section != CFREE_SECTION_NONE); ds->file_prefix = file_prefix; (*n)++; + return 0; } -static void nm_collect_obj(CfreeObjFile *of, const NmOpts *opts, - const char *file_prefix, NmSym **syms, - uint32_t *n, uint32_t *cap, int *ptr_digits, - DriverEnv *env) { +static int nm_collect_obj(CfreeObjFile *of, const NmOpts *opts, + const char *file_prefix, NmSym **syms, uint32_t *n, + uint32_t *cap, int *ptr_digits, DriverEnv *env) { CfreeTarget t = cfree_obj_target(of); CfreeObjSymIter *it = NULL; - if (cfree_obj_symiter_new(of, &it) != CFREE_OK) return; + int rc = 0; + if (cfree_obj_symiter_new(of, &it) != CFREE_OK) return 1; for (;;) { CfreeObjSymInfo si; if (cfree_obj_symiter_next(it, &si) != CFREE_ITER_ITEM) break; if (!nm_symbol_visible(&si, opts)) continue; - nm_append_sym(env, syms, n, cap, &si, file_prefix, ptr_digits, t); + if (nm_append_sym(env, syms, n, cap, &si, file_prefix, ptr_digits, t) != + 0) { + rc = 1; + break; + } } cfree_obj_symiter_free(it); + return rc; } static int nm_process_file(const CfreeContext *ctx, const CfreeSlice *input, @@ -158,8 +169,14 @@ static int nm_process_file(const CfreeContext *ctx, const CfreeSlice *input, mb.data = m.data; mb.len = m.size; if (cfree_obj_open(ctx, m.name, &mb, &of) == CFREE_OK) { - nm_collect_obj(of, opts, NULL, syms, n, cap, ptr_digits, env); + int collect_rc = + nm_collect_obj(of, opts, NULL, syms, n, cap, ptr_digits, env); cfree_obj_free(of); + if (collect_rc != 0) { + cfree_ar_iter_free(it); + driver_errf(NM_TOOL, "%s: out of memory while reading symbols", path); + return 1; + } } } cfree_ar_iter_free(it); @@ -170,12 +187,27 @@ static int nm_process_file(const CfreeContext *ctx, const CfreeSlice *input, driver_errf(NM_TOOL, "%s: not a recognized object file", path); return 1; } - nm_collect_obj(of, opts, NULL, syms, n, cap, ptr_digits, env); + if (nm_collect_obj(of, opts, NULL, syms, n, cap, ptr_digits, env) != 0) { + cfree_obj_free(of); + driver_errf(NM_TOOL, "%s: out of memory while reading symbols", path); + return 1; + } cfree_obj_free(of); } return 0; } +static void nm_free_syms(DriverEnv *env, NmSym *syms, uint32_t nsyms, + uint32_t cap) { + uint32_t i; + if (!syms) return; + for (i = 0; i < nsyms; ++i) { + if (syms[i].name.s) + driver_free(env, (void *)syms[i].name.s, syms[i].name.len); + } + driver_free(env, syms, (size_t)cap * sizeof(NmSym)); +} + static void nm_sort_syms(NmSym *syms, uint32_t nsyms, const NmOpts *opts) { uint32_t i, j; if (opts->no_sort) return; @@ -313,7 +345,7 @@ int driver_nm(int argc, char **argv) { rc = 0; done: - if (syms) driver_free(&env, syms, (size_t)cap * sizeof(NmSym)); + nm_free_syms(&env, syms, nsyms, cap); driver_env_fini(&env); return rc; } diff --git a/test/test.mk b/test/test.mk @@ -252,9 +252,10 @@ test-rt-runtime: bin rt $(LINK_EXE_RUNNER) # Declared as Make targets (not built by the run.sh scripts) so they pick # up libcfree.a changes deterministically. # -# HARNESS_CFLAGS drops -Wpedantic; the runners cast cfree_jit_lookup's -# void* to a function pointer, which pedantic rejects under C11. -HARNESS_CFLAGS = -std=c11 -Wall -Wextra -Werror -isysroot $(SYSROOT) -Iinclude -Itest +# HARNESS_CFLAGS drops -Wpedantic from the normal host flags; the runners cast +# cfree_jit_lookup's void* to a function pointer, which pedantic rejects under +# C11. +HARNESS_CFLAGS = $(filter-out -Wpedantic,$(HOST_CFLAGS)) -Iinclude -Itest ROUNDTRIP_BIN = build/test/cfree-roundtrip ROUNDTRIP_BIN_MACHO = build/test/cfree-roundtrip-macho