kit

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

commit 5381da7830175a7bdc007561160c0828f32095a9
parent f4598076bcaf8b69666403a8667f338f25870bc6
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Sun, 10 May 2026 14:04:35 -0700

build/driver: make self target + filename in diagnostics

- Makefile: `make self` builds cfree with clang (stage 1), copies it
  to build/cfree-stage1, wipes the stage-1 outputs, and recurses with
  stage-1 cfree as CC. Stage 2 swaps host -isysroot for -isystem
  rt/include + -isystem $(SYSROOT)/usr/include since cfree's cc
  doesn't accept -isysroot/-std=c11/-W*/-ffreestanding. The bin link's
  hardcoded -isysroot moves to a HOST_SYSROOT_LDFLAGS variable.

- include/cfree.h, src/api/lifecycle.c: new public lookup
  cfree_compiler_file_name(c, file_id) returning the spelling
  registered by SourceManager (path or memory-input label).

- driver/{env.c,driver.h}: stderr diag sink consults a module-local
  active compiler and prints `path:line:col` instead of `<file:%u>`.
  driver_{compiler,pipeline}_{new,free} wrap the libcfree lifecycle
  entries to register/clear that pointer; all driver call sites are
  renamed to use them.

Stage 2 currently fails at rt/include/stddef.h:5:26 (typedef
__PTRDIFF_TYPE__ ptrdiff_t) — cfree's pp doesn't define
__PTRDIFF_TYPE__. The diag wiring above is what made that location
visible instead of <file:14>.

Diffstat:
MMakefile | 42+++++++++++++++++++++++++++++++++++++++---
Mdriver/as.c | 4++--
Mdriver/cc.c | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
Mdriver/dbg.c | 8++++----
Mdriver/driver.h | 16++++++++++++++++
Mdriver/emu.c | 4++--
Mdriver/env.c | 49+++++++++++++++++++++++++++++++++++++++++++++++--
Mdriver/ld.c | 4++--
Mdriver/objdump.c | 4++--
Mdriver/run.c | 4++--
Minclude/cfree.h | 8++++++++
Msrc/api/lifecycle.c | 9+++++++++
12 files changed, 202 insertions(+), 42 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,7 +1,12 @@ CC = clang SYSROOT = $(shell xcrun --show-sdk-path) -CFLAGS_COMMON = -std=c11 -Wpedantic -Wall -Wextra -Werror -isysroot $(SYSROOT) +# -isysroot lives in its own var so the `self` target (cfree-as-CC) can +# swap it for cfree's -isystem-only flag set. +HOST_SYSROOT_CFLAGS = -isysroot $(SYSROOT) +HOST_SYSROOT_LDFLAGS = -isysroot $(SYSROOT) + +CFLAGS_COMMON = -std=c11 -Wpedantic -Wall -Wextra -Werror $(HOST_SYSROOT_CFLAGS) # libcfree: written in C11 freestanding; sees both src/ (internal) and # include/ (its own public surface). @@ -22,7 +27,7 @@ DRIVER_DEPS = $(DRIVER_OBJS:.o=.d) LIB_AR = build/libcfree.a BIN = build/cfree -.PHONY: all lib driver bin rt rt-aarch64-linux format clean +.PHONY: all lib driver bin rt rt-aarch64-linux format clean self self-stage2 # Default: compile libcfree.a, the driver objects, and link the cfree # binary. The link step currently fails because most libcfree functions @@ -56,7 +61,7 @@ $(LIB_AR): $(LIB_OBJS) ar rcs $@ $(LIB_OBJS) $(BIN): $(DRIVER_OBJS) $(LIB_AR) - $(CC) -isysroot $(SYSROOT) -o $@ $(DRIVER_OBJS) $(LIB_AR) + $(CC) $(HOST_SYSROOT_LDFLAGS) -o $@ $(DRIVER_OBJS) $(LIB_AR) build/lib/%.o: src/%.c @mkdir -p $(dir $@) @@ -66,6 +71,37 @@ build/driver/%.o: driver/%.c @mkdir -p $(dir $@) $(CC) $(DRIVER_CFLAGS) -MMD -MP -c $< -o $@ +# Self-host: build cfree with clang (stage 1), then rebuild libcfree.a + +# driver + bin from clean using stage-1 cfree as CC (stage 2). Stage 1 is +# preserved at build/cfree-stage1; build/cfree is replaced with stage 2. +# +# cfree's cc accepts -I, -isystem, -D, -U, -c, -o, -O, -g, -MMD, -MP, +# -MF, -fPIC/-fPIE, -static, -shared, -Wl,, -target, -ffile-prefix-map=, +# --build-id=. It rejects -isysroot, -std=c11, -Wpedantic/-Wall/-Wextra, +# -Werror, -ffreestanding — those are dropped from the stage-2 flag set. +STAGE1_BIN = build/cfree-stage1 + +self: $(BIN) + cp $(BIN) $(STAGE1_BIN) + rm -rf build/lib build/driver $(LIB_AR) $(BIN) + $(MAKE) self-stage2 + +# Stage 2 sysroot: cfree finds system headers via -isystem, not -isysroot. +# rt/include ships cfree's freestanding headers (stddef.h, stdarg.h, ...) +# and must precede the SDK so its versions win over Xcode's. +SELF_SYSROOT_CFLAGS = -isystem rt/include -isystem $(SYSROOT)/usr/include +SELF_SYSROOT_LDFLAGS = +SELF_LIB_CFLAGS = $(SELF_SYSROOT_CFLAGS) -Iinclude -Isrc +SELF_DRIVER_CFLAGS = $(SELF_SYSROOT_CFLAGS) -Iinclude + +self-stage2: + $(MAKE) all \ + CC='$(abspath $(STAGE1_BIN)) cc' \ + CFLAGS_COMMON='$(SELF_SYSROOT_CFLAGS)' \ + LIB_CFLAGS='$(SELF_LIB_CFLAGS)' \ + DRIVER_CFLAGS='$(SELF_DRIVER_CFLAGS)' \ + HOST_SYSROOT_LDFLAGS='$(SELF_SYSROOT_LDFLAGS)' + format: find src include driver test rt \( -path test/lex -o -path test/pp \) -prune -o \( -name '*.c' -o -name '*.h' \) -print | xargs clang-format -i --style=google diff --git a/driver/as.c b/driver/as.c @@ -147,7 +147,7 @@ int driver_as(int argc, char** argv) { goto out; } - compiler = cfree_compiler_new(o.target, &cenv); + compiler = driver_compiler_new(o.target, &cenv); if (!compiler) { driver_errf(AS_TOOL, "failed to initialize compiler"); goto out; @@ -164,7 +164,7 @@ int driver_as(int argc, char** argv) { rc = cfree_compile_obj_emit(compiler, &copts, &input, writer); out: - if (compiler) cfree_compiler_free(compiler); + if (compiler) driver_compiler_free(compiler); if (writer) cfree_writer_close(writer); if (loaded) cenv.file_io->release(cenv.file_io->user, &src); driver_env_fini(&env); diff --git a/driver/cc.c b/driver/cc.c @@ -96,6 +96,10 @@ typedef struct CcOptions { char** owned_archives; size_t* owned_archive_sizes; uint32_t nowned_archives; + /* DSO inputs (.so / .dylib / .tbd). Always heap-owned by cc. */ + char** dsos; + size_t* dso_sizes; + uint32_t ndsos; /* -L search paths (argv-borrowed). */ const char** lib_search_paths; uint32_t nlib_search_paths; @@ -241,6 +245,8 @@ static int cc_alloc_arrays(CcOptions* o, int argc) { driver_alloc_zeroed(o->env, bound * sizeof(*o->owned_archives)); o->owned_archive_sizes = driver_alloc_zeroed(o->env, bound * sizeof(*o->owned_archive_sizes)); + o->dsos = driver_alloc_zeroed(o->env, bound * sizeof(*o->dsos)); + o->dso_sizes = driver_alloc_zeroed(o->env, bound * sizeof(*o->dso_sizes)); o->lib_search_paths = driver_alloc_zeroed(o->env, bound * sizeof(*o->lib_search_paths)); o->pending_libs = @@ -254,6 +260,7 @@ static int cc_alloc_arrays(CcOptions* o, int argc) { o->rpaths = driver_alloc_zeroed(o->env, bound * sizeof(*o->rpaths)); if (!o->source_files || !o->source_memory || !o->object_files || !o->archives || !o->owned_archives || !o->owned_archive_sizes || + !o->dsos || !o->dso_sizes || !o->lib_search_paths || !o->pending_libs || !o->dep_targets || !o->path_map || !o->owned_path_map_olds || !o->owned_path_map_old_sizes || !o->rpaths) { @@ -274,6 +281,9 @@ static void cc_options_release(CcOptions* o) { for (i = 0; i < o->nowned_archives; ++i) { driver_free(o->env, o->owned_archives[i], o->owned_archive_sizes[i]); } + for (i = 0; i < o->ndsos; ++i) { + driver_free(o->env, o->dsos[i], o->dso_sizes[i]); + } for (i = 0; i < o->npath_map; ++i) { if (o->owned_path_map_olds[i]) { driver_free(o->env, o->owned_path_map_olds[i], @@ -291,6 +301,8 @@ static void cc_options_release(CcOptions* o) { driver_free(o->env, o->owned_archives, bound * sizeof(*o->owned_archives)); driver_free(o->env, o->owned_archive_sizes, bound * sizeof(*o->owned_archive_sizes)); + driver_free(o->env, o->dsos, bound * sizeof(*o->dsos)); + driver_free(o->env, o->dso_sizes, bound * sizeof(*o->dso_sizes)); driver_free(o->env, o->lib_search_paths, bound * sizeof(*o->lib_search_paths)); driver_free(o->env, o->pending_libs, bound * sizeof(*o->pending_libs)); @@ -548,23 +560,35 @@ static int cc_classify_positional(CcOptions* o, const char* a) { return 1; } -/* Resolve every accumulated -lname against -L paths; pushes resolved paths - * into archives[]. Reports first lookup failure. */ +/* Resolve every accumulated -lname against -L paths; routes results to + * archives[] (.a) or dsos[] (.so/.dylib/.tbd). Reports first lookup + * failure. Mach-O targets prefer dynamic resolution (.tbd > .dylib > .a); + * other targets fall back to the historical static-only path. */ static int cc_resolve_pending_libs(CcOptions* o) { uint32_t i; + LibResolveMode mode = + (o->target.obj == CFREE_OBJ_MACHO) ? LIB_RESOLVE_DYNAMIC_PREFER + : LIB_RESOLVE_STATIC_ONLY; for (i = 0; i < o->npending_libs; ++i) { char* p; size_t sz; - if (driver_lib_resolve(o->env, o->pending_libs[i], LIB_RESOLVE_STATIC_ONLY, + LibResolveKind kind; + if (driver_lib_resolve(o->env, o->pending_libs[i], mode, o->lib_search_paths, o->nlib_search_paths, &p, &sz, - NULL) != 0) { + &kind) != 0) { driver_errf(CC_TOOL, "library not found: -l%s", o->pending_libs[i]); return 1; } - o->owned_archives[o->nowned_archives] = p; - o->owned_archive_sizes[o->nowned_archives] = sz; - o->nowned_archives++; - o->archives[o->narchives++] = p; + if (kind == LIB_RESOLVE_KIND_SHARED || kind == LIB_RESOLVE_KIND_TBD) { + o->dsos[o->ndsos] = p; + o->dso_sizes[o->ndsos] = sz; + o->ndsos++; + } else { + o->owned_archives[o->nowned_archives] = p; + o->owned_archive_sizes[o->nowned_archives] = sz; + o->nowned_archives++; + o->archives[o->narchives++] = p; + } } return 0; } @@ -943,7 +967,7 @@ static int cc_preprocess(DriverEnv* env, const CcOptions* o, goto out; } - compiler = cfree_compiler_new(o->target, &cenv); + compiler = driver_compiler_new(o->target, &cenv); if (!compiler) { driver_errf(CC_TOOL, "failed to initialize compiler"); goto out; @@ -952,7 +976,7 @@ static int cc_preprocess(DriverEnv* env, const CcOptions* o, rc = cfree_preprocess(compiler, pp_opts, &input, writer); out: - if (compiler) cfree_compiler_free(compiler); + if (compiler) driver_compiler_free(compiler); if (writer) cfree_writer_close(writer); if (loaded) cenv.file_io->release(cenv.file_io->user, &fd); return rc; @@ -975,7 +999,7 @@ static int cc_dump_tokens(DriverEnv* env, const CcOptions* o) { goto out; } - compiler = cfree_compiler_new(o->target, &cenv); + compiler = driver_compiler_new(o->target, &cenv); if (!compiler) { driver_errf(CC_TOOL, "failed to initialize compiler"); goto out; @@ -984,7 +1008,7 @@ static int cc_dump_tokens(DriverEnv* env, const CcOptions* o) { rc = cfree_dump_tokens(compiler, &input, writer); out: - if (compiler) cfree_compiler_free(compiler); + if (compiler) driver_compiler_free(compiler); if (writer) cfree_writer_close(writer); if (loaded) cenv.file_io->release(cenv.file_io->user, &fd); return rc; @@ -1308,7 +1332,7 @@ static int cc_run_deps_only(DriverEnv* env, const CcOptions* o, goto out; } - compiler = cfree_compiler_new(o->target, &cenv); + compiler = driver_compiler_new(o->target, &cenv); if (!compiler) { driver_errf(CC_TOOL, "failed to initialize compiler"); goto out; @@ -1319,7 +1343,7 @@ static int cc_run_deps_only(DriverEnv* env, const CcOptions* o, rc = cc_dep_finish(env, &cenv, compiler, o); out: - if (compiler) cfree_compiler_free(compiler); + if (compiler) driver_compiler_free(compiler); if (discard) cfree_writer_close(discard); if (loaded) cenv.file_io->release(cenv.file_io->user, &fd); return rc; @@ -1347,7 +1371,7 @@ static int cc_run_compile_obj(DriverEnv* env, const CcOptions* o, goto out; } - compiler = cfree_compiler_new(o->target, &cenv); + compiler = driver_compiler_new(o->target, &cenv); if (!compiler) { driver_errf(CC_TOOL, "failed to initialize compiler"); goto out; @@ -1361,7 +1385,7 @@ static int cc_run_compile_obj(DriverEnv* env, const CcOptions* o, : 0; out: - if (compiler) cfree_compiler_free(compiler); + if (compiler) driver_compiler_free(compiler); if (obj_w) cfree_writer_close(obj_w); if (loaded) cenv.file_io->release(cenv.file_io->user, &fd); return rc; @@ -1380,9 +1404,11 @@ static int cc_run_link_exe(DriverEnv* env, const CcOptions* o, DriverLoad* obj_lf = NULL; DriverLoad* arch_lf = NULL; DriverLoad script_lf = {0}; + DriverLoad* dso_lf = NULL; CfreeBytesInput* src_in = NULL; CfreeBytesInput* obj_in = NULL; CfreeBytesInputArchive* arch_in = NULL; + CfreeBytesInput* dso_in = NULL; CfreeObjBuilder** objs = NULL; const CfreeLinkScript* script = NULL; CfreeCompileOptions copts; @@ -1397,11 +1423,13 @@ static int cc_run_link_exe(DriverEnv* env, const CcOptions* o, } /* Allocate scratch for parallel arrays. */ - src_in = driver_alloc_zeroed(env, nsrc * sizeof(*src_in)); - objs = driver_alloc_zeroed(env, nsrc * sizeof(*objs)); - if (!src_in || !objs) { - driver_errf(CC_TOOL, "out of memory"); - goto out; + if (nsrc) { + src_in = driver_alloc_zeroed(env, nsrc * sizeof(*src_in)); + objs = driver_alloc_zeroed(env, nsrc * sizeof(*objs)); + if (!src_in || !objs) { + driver_errf(CC_TOOL, "out of memory"); + goto out; + } } if (o->nsource_files) { src_lf = driver_alloc_zeroed(env, o->nsource_files * sizeof(*src_lf)); @@ -1426,6 +1454,14 @@ static int cc_run_link_exe(DriverEnv* env, const CcOptions* o, goto out; } } + if (o->ndsos) { + dso_lf = driver_alloc_zeroed(env, o->ndsos * sizeof(*dso_lf)); + dso_in = driver_alloc_zeroed(env, o->ndsos * sizeof(*dso_in)); + if (!dso_lf || !dso_in) { + driver_errf(CC_TOOL, "out of memory"); + goto out; + } + } /* Stage source inputs: paths first (paths-then-memory matches the old * cfree_run order so reproducibility is unchanged), then memory. */ @@ -1452,6 +1488,11 @@ static int cc_run_link_exe(DriverEnv* env, const CcOptions* o, arch_in[i].whole_archive = 0; arch_in[i].group_id = 0; } + for (i = 0; i < o->ndsos; ++i) { + if (driver_load_bytes(io, CC_TOOL, o->dsos[i], &dso_lf[i], + &dso_in[i]) != 0) + goto out; + } /* Linker script. */ if (o->linker_script) { @@ -1461,7 +1502,7 @@ static int cc_run_link_exe(DriverEnv* env, const CcOptions* o, goto out; } - pipe = cfree_pipeline_new(o->target, &cenv); + pipe = driver_pipeline_new(o->target, &cenv); if (!pipe) { driver_errf(CC_TOOL, "failed to initialize compiler"); goto out; @@ -1497,6 +1538,8 @@ static int cc_run_link_exe(DriverEnv* env, const CcOptions* o, inputs.nobj_bytes = o->nobject_files; inputs.archives = arch_in; inputs.narchives = o->narchives; + inputs.dso_bytes = dso_in; + inputs.ndso_bytes = o->ndsos; inputs.linker_script = script; inputs.entry = o->entry; inputs.build_id_mode = o->build_id_mode; @@ -1530,10 +1573,11 @@ out: if (out_w) cfree_writer_close(out_w); if (script && pipe) cfree_link_script_free(cfree_pipeline_compiler(pipe), script); - if (pipe) cfree_pipeline_free(pipe); + if (pipe) driver_pipeline_free(pipe); driver_release_bytes(io, &script_lf); if (arch_lf) { for (i = 0; i < o->narchives; ++i) driver_release_bytes(io, &arch_lf[i]); + for (i = 0; i < o->ndsos; ++i) driver_release_bytes(io, &dso_lf[i]); } if (obj_lf) { for (i = 0; i < o->nobject_files; ++i) driver_release_bytes(io, &obj_lf[i]); @@ -1543,6 +1587,8 @@ out: } if (arch_in) driver_free(env, arch_in, o->narchives * sizeof(*arch_in)); if (arch_lf) driver_free(env, arch_lf, o->narchives * sizeof(*arch_lf)); + if (dso_in) driver_free(env, dso_in, o->ndsos * sizeof(*dso_in)); + if (dso_lf) driver_free(env, dso_lf, o->ndsos * sizeof(*dso_lf)); if (obj_in) driver_free(env, obj_in, o->nobject_files * sizeof(*obj_in)); if (obj_lf) driver_free(env, obj_lf, o->nobject_files * sizeof(*obj_lf)); if (src_lf) driver_free(env, src_lf, o->nsource_files * sizeof(*src_lf)); diff --git a/driver/dbg.c b/driver/dbg.c @@ -1828,7 +1828,7 @@ int driver_dbg(int argc, char** argv) { cenv = driver_env_to_cfree(&env); target = driver_host_target(); - pipe = cfree_pipeline_new(target, &cenv); + pipe = driver_pipeline_new(target, &cenv); if (!pipe) { driver_errf(DBG_TOOL, "failed to initialize compiler"); dbg_options_release(&o); @@ -1838,7 +1838,7 @@ int driver_dbg(int argc, char** argv) { rc = dbg_compile_and_jit(&env, &o, pipe, &jit); if (rc != 0) { - cfree_pipeline_free(pipe); + driver_pipeline_free(pipe); dbg_options_release(&o); driver_env_fini(&env); return rc; @@ -1853,7 +1853,7 @@ int driver_dbg(int argc, char** argv) { if (!st.entry_addr) { driver_errf(DBG_TOOL, "entry symbol not found: %s", o.entry); cfree_jit_free(jit); - cfree_pipeline_free(pipe); + driver_pipeline_free(pipe); dbg_options_release(&o); driver_env_fini(&env); return 1; @@ -1879,7 +1879,7 @@ int driver_dbg(int argc, char** argv) { if (st.dwarf) cfree_dwarf_close(st.dwarf); if (st.session) cfree_jit_session_free(st.session); cfree_jit_free(jit); - cfree_pipeline_free(pipe); + driver_pipeline_free(pipe); dbg_options_release(&o); driver_env_fini(&env); return 0; diff --git a/driver/driver.h b/driver/driver.h @@ -80,6 +80,22 @@ void driver_env_init(DriverEnv*); void driver_env_fini(DriverEnv*); CfreeEnv driver_env_to_cfree(const DriverEnv*); +/* Tells the stderr diag sink which compiler to use when resolving + * SrcLoc.file_id to a path. The driver_{compiler,pipeline}_{new,free} + * helpers below already manage this; call this directly only when you + * hand a CfreeCompiler from outside those helpers (none today). */ +void driver_diag_set_compiler(CfreeCompiler*); + +/* Lifecycle helpers around cfree_{compiler,pipeline}_{new,free}. + * Identical to the raw entries except they register/clear the active + * compiler with the stderr diag sink, so diagnostics can resolve + * loc.file_id to its registered path. Tools should always go through + * these inside the driver. */ +CfreeCompiler* driver_compiler_new(CfreeTarget, const CfreeEnv*); +void driver_compiler_free(CfreeCompiler*); +CfreePipeline* driver_pipeline_new(CfreeTarget, const CfreeEnv*); +void driver_pipeline_free(CfreePipeline*); + /* Default target used by tools that don't expose a target-selection flag * yet. v1: native-looking host target (chosen at compile time). */ CfreeTarget driver_host_target(void); diff --git a/driver/emu.c b/driver/emu.c @@ -290,7 +290,7 @@ int driver_emu(int argc, char** argv) { /* The emu's host-side compiler runs at the host's native target — * the JIT image holds host code, the *guest* arch is configured * through CfreeEmuOptions.guest_arch. */ - compiler = cfree_compiler_new(driver_host_target(), &cenv); + compiler = driver_compiler_new(driver_host_target(), &cenv); if (!compiler) { driver_errf(EMU_TOOL, "failed to initialize compiler"); goto out; @@ -319,7 +319,7 @@ int driver_emu(int argc, char** argv) { rc = exit_code; out: - if (compiler) cfree_compiler_free(compiler); + if (compiler) driver_compiler_free(compiler); if (elf_lf.loaded && cenv.file_io) driver_release_bytes(cenv.file_io, &elf_lf); emu_options_release(&eo); diff --git a/driver/env.c b/driver/env.c @@ -101,12 +101,57 @@ static const char* diag_label(CfreeDiagKind k) { return "diag"; } +/* Tracks the compiler currently driving libcfree calls so the stderr + * diag sink can resolve loc.file_id to the source's spelling (path or + * memory-input label). NULL falls back to the numeric `<file:%u>` form, + * which is what callers see before they've registered a compiler. */ +static CfreeCompiler* g_diag_active_compiler; + +void driver_diag_set_compiler(CfreeCompiler* c) { g_diag_active_compiler = c; } + +/* driver_{compiler,pipeline}_{new,free}: thin wrappers around the libcfree + * lifecycle entries that register the active compiler with the diag sink + * and clear it on free. Driver tools call these instead of the raw + * cfree_* calls so a fatal diagnostic from libcfree prints the source + * file name rather than a bare numeric file_id. */ +CfreeCompiler* driver_compiler_new(CfreeTarget t, const CfreeEnv* env) { + CfreeCompiler* c = cfree_compiler_new(t, env); + if (c) driver_diag_set_compiler(c); + return c; +} + +void driver_compiler_free(CfreeCompiler* c) { + if (!c) return; + if (g_diag_active_compiler == c) driver_diag_set_compiler(NULL); + cfree_compiler_free(c); +} + +CfreePipeline* driver_pipeline_new(CfreeTarget t, const CfreeEnv* env) { + CfreePipeline* p = cfree_pipeline_new(t, env); + if (p) driver_diag_set_compiler(cfree_pipeline_compiler(p)); + return p; +} + +void driver_pipeline_free(CfreePipeline* p) { + if (!p) return; + if (g_diag_active_compiler == cfree_pipeline_compiler(p)) + driver_diag_set_compiler(NULL); + cfree_pipeline_free(p); +} + static void diag_stderr_emit(CfreeDiagSink* s, CfreeDiagKind k, CfreeSrcLoc loc, const char* fmt, va_list ap) { (void)s; if (loc.file_id || loc.line) { - fprintf(stderr, "<file:%u>:%u:%u: %s: ", loc.file_id, loc.line, loc.col, - diag_label(k)); + const char* name = cfree_compiler_file_name(g_diag_active_compiler, + loc.file_id); + if (name && *name) { + fprintf(stderr, "%s:%u:%u: %s: ", name, loc.line, loc.col, + diag_label(k)); + } else { + fprintf(stderr, "<file:%u>:%u:%u: %s: ", loc.file_id, loc.line, loc.col, + diag_label(k)); + } } else { fprintf(stderr, "%s: ", diag_label(k)); } diff --git a/driver/ld.c b/driver/ld.c @@ -770,7 +770,7 @@ static int ld_run_link(LdOptions* o) { } } - compiler = cfree_compiler_new(o->target, &cenv); + compiler = driver_compiler_new(o->target, &cenv); if (!compiler) { driver_errf(LD_TOOL, "failed to initialize compiler"); goto out; @@ -864,7 +864,7 @@ out: (void)chmod(o->output_path, 0755); } if (script && compiler) cfree_link_script_free(compiler, script); - if (compiler) cfree_compiler_free(compiler); + if (compiler) driver_compiler_free(compiler); release_file(&script_lf); release_all(arch_lf, o->narchives); release_all(obj_lf, o->nobject_files); diff --git a/driver/objdump.c b/driver/objdump.c @@ -494,7 +494,7 @@ int driver_objdump(int argc, char** argv) { * session at the host target — disasm consults the per-file builder * for annotation but does not require a target match. */ if (opts.d || opts.D) { - dc = cfree_compiler_new(driver_host_target(), &cenv); + dc = driver_compiler_new(driver_host_target(), &cenv); if (!dc) { driver_errf(OBJDUMP_TOOL, "%s", "failed to init disassembler"); rc = 1; @@ -559,7 +559,7 @@ int driver_objdump(int argc, char** argv) { } done: - if (dc) cfree_compiler_free(dc); + if (dc) driver_compiler_free(dc); driver_env_fini(&env); return rc; } diff --git a/driver/run.c b/driver/run.c @@ -432,7 +432,7 @@ static int run_compile_and_jit(DriverEnv* env, const RunOptions* o, arch_in[i].group_id = 0; } - pipe = cfree_pipeline_new(o->target, &cenv); + pipe = driver_pipeline_new(o->target, &cenv); if (!pipe) { driver_errf(RUN_TOOL, "failed to initialize compiler"); goto out; @@ -461,7 +461,7 @@ static int run_compile_and_jit(DriverEnv* env, const RunOptions* o, rc = cfree_pipeline_link_jit(pipe, &link_opts, out_jit); out: - if (pipe) cfree_pipeline_free(pipe); + if (pipe) driver_pipeline_free(pipe); if (arch_lf) { for (i = 0; i < o->narchives; ++i) driver_release_bytes(io, &arch_lf[i]); } diff --git a/include/cfree.h b/include/cfree.h @@ -297,6 +297,14 @@ typedef struct CfreeEnv { CfreeCompiler* cfree_compiler_new(CfreeTarget, const CfreeEnv*); void cfree_compiler_free(CfreeCompiler*); +/* Resolve a CfreeSrcLoc.file_id to the spelling used when the source was + * registered (typically the path passed to FileIO.read_all, or a memory- + * input label). Returns NULL when `c` is NULL or `file_id` doesn't name a + * registered file. The returned pointer is owned by the compiler and is + * valid until cfree_compiler_free. Diagnostic sinks use this to print + * `path:line:col` instead of the bare numeric `file_id`. */ +const char* cfree_compiler_file_name(CfreeCompiler*, uint32_t file_id); + /* ============================================================ * Writer dispatch (inline) * ============================================================ diff --git a/src/api/lifecycle.c b/src/api/lifecycle.c @@ -6,6 +6,7 @@ #include "core/core.h" #include "core/heap.h" +#include "core/pool.h" CfreeCompiler* cfree_compiler_new(CfreeTarget target, const CfreeEnv* env) { Heap* h; @@ -26,3 +27,11 @@ void cfree_compiler_free(CfreeCompiler* c) { compiler_fini(c); h->free(h, c, sizeof(*c)); } + +const char* cfree_compiler_file_name(CfreeCompiler* c, uint32_t file_id) { + const SourceFile* f; + if (!c) return NULL; + f = source_file(c->sources, file_id); + if (!f) return NULL; + return pool_str(c->global, f->name, NULL); +}