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:
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);
+}