commit 8406232ec0dc65db7ff231a12bffff91975c3ab7
parent dffe56c37dd005738f5890335a4b76cb65d2b1f9
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Fri, 29 May 2026 12:38:02 -0700
Auto-link cfree runtime from ld
Diffstat:
6 files changed, 259 insertions(+), 91 deletions(-)
diff --git a/Makefile b/Makefile
@@ -375,7 +375,7 @@ endif
ifneq ($(filter 1,$(CFREE_TOOL_CC_ENABLED) $(CFREE_TOOL_CHECK_ENABLED) $(CFREE_TOOL_RUN_ENABLED)),)
DRIVER_SRCS += driver/hosted.c
endif
-ifneq ($(filter 1,$(CFREE_TOOL_CC_ENABLED) $(CFREE_TOOL_CHECK_ENABLED)),)
+ifneq ($(filter 1,$(CFREE_TOOL_CC_ENABLED) $(CFREE_TOOL_CHECK_ENABLED) $(CFREE_TOOL_LD_ENABLED)),)
DRIVER_SRCS += driver/runtime.c
endif
ifneq ($(filter 1,$(CFREE_TOOL_AR_ENABLED) $(CFREE_TOOL_RANLIB_ENABLED) $(CFREE_TOOL_STRIP_ENABLED) $(CFREE_TOOL_DBG_ENABLED) $(CFREE_TOOL_RUN_ENABLED)),)
diff --git a/driver/cc.c b/driver/cc.c
@@ -615,15 +615,17 @@ static int cc_append_hosted_input(CcOptions* o, const DriverHostedInput* in,
return 0;
}
-static void cc_insert_owned_archive(CcOptions* o, char* path, size_t path_size,
- uint32_t insert_pos) {
+static void cc_insert_runtime_archive(CcOptions* o, DriverRuntimeArchive* rt,
+ uint32_t insert_pos) {
CcArchiveInput* ar = &o->archives[o->narchives++];
- ar->path = path;
+ ar->path = rt->path;
ar->owned = 1;
- ar->owned_size = path_size;
- ar->whole_archive = 0;
- ar->link_mode = CFREE_LM_STATIC;
- ar->group_id = 0;
+ ar->owned_size = rt->path_size;
+ ar->whole_archive = rt->whole_archive;
+ ar->link_mode = rt->link_mode;
+ ar->group_id = rt->group_id;
+ rt->path = NULL;
+ rt->path_size = 0;
cc_insert_link_item(o, insert_pos, CC_LINK_ARCHIVE, o->narchives - 1u);
}
@@ -2806,8 +2808,7 @@ static int driver_cc_main(int argc, char** argv, int force_check) {
}
if (link_action && !co.no_stdlib && !co.no_defaultlibs) {
- char* rt_path = NULL;
- size_t rt_path_size = 0;
+ DriverRuntimeArchive rt_archive = {0};
uint32_t insert_pos;
if (!runtime_resolved) {
driver_errf(CC_TOOL, "support dir not found");
@@ -2815,8 +2816,9 @@ static int driver_cc_main(int argc, char** argv, int force_check) {
driver_env_fini(&env);
return 1;
}
- if (driver_runtime_ensure_archive(&env, &runtime, co.target, co.epoch,
- &rt_path, &rt_path_size) != 0) {
+ if (driver_runtime_prepare_archive(&env, CC_TOOL, &runtime, co.target,
+ co.epoch, &rt_archive) != 0) {
+ driver_runtime_archive_fini(&env, &rt_archive);
driver_runtime_support_fini(&env, &runtime);
cc_options_release(&co);
driver_env_fini(&env);
@@ -2824,7 +2826,8 @@ static int driver_cc_main(int argc, char** argv, int force_check) {
}
insert_pos = co.nlink_items;
if (co.hosted.nfinal <= insert_pos) insert_pos -= co.hosted.nfinal;
- cc_insert_owned_archive(&co, rt_path, rt_path_size, insert_pos);
+ cc_insert_runtime_archive(&co, &rt_archive, insert_pos);
+ driver_runtime_archive_fini(&env, &rt_archive);
}
driver_cflags_fill_pp(&co.cf, &pp);
diff --git a/driver/ld.c b/driver/ld.c
@@ -6,6 +6,7 @@
#include "driver.h"
#include "lib_resolve.h"
+#include "runtime.h"
/* `cfree ld` — link object/archive inputs into an executable, shared
* library, or relocatable object. The driver loads each input via
@@ -18,6 +19,7 @@
* -o out output path (required, exactly one)
* -e symbol entry symbol
* -T script.ld linker script (parsed, not raw)
+ * --support-dir DIR cfree support root for compiler rt
* -L dir library search path (-l targets)
* -l name resolves to lib<name>.a via -L
* -static / -pie / -no-pie target.pic
@@ -66,6 +68,7 @@ typedef struct LdDso {
typedef struct LdOptions {
DriverEnv* env;
+ const char* driver_path;
size_t argv_bound;
CfreeTarget target;
@@ -74,6 +77,7 @@ typedef struct LdOptions {
int output_seen;
const char* entry; /* -e */
const char* script_path; /* -T */
+ const char* support_dir; /* --support-dir */
uint16_t pe_subsystem; /* CfreePeSubsystem */
/* PT_INTERP path. NULL means "let libcfree pick the target default
* (e.g. /lib/ld-musl-aarch64.so.1)". Set by -dynamic-linker /
@@ -172,6 +176,8 @@ void driver_help_ld(void) {
" -static Non-PIC, non-PIE\n"
" -pie Position-independent executable\n"
" -no-pie Disable PIE\n"
+ " --support-dir DIR cfree support root for compiler "
+ "runtime\n"
" (target is otherwise auto-detected from the first object input)\n"
"\n"
"LIBRARY RESOLUTION\n"
@@ -227,7 +233,7 @@ void driver_help_ld(void) {
/* ---------- argv-sized scratch arrays ---------- */
static int ld_alloc_arrays(LdOptions* o, int argc) {
- size_t bound = (size_t)argc;
+ size_t bound = (size_t)argc + 16u;
o->argv_bound = bound;
o->object_files =
driver_alloc_zeroed(o->env, bound * sizeof(*o->object_files));
@@ -267,6 +273,19 @@ static void ld_push_archive(LdOptions* o, const char* path, int owned,
ld_push_order(o, CFREE_LINK_INPUT_ARCHIVE, o->narchives - 1u);
}
+static void ld_push_runtime_archive(LdOptions* o, DriverRuntimeArchive* rt) {
+ LdArchive* a = &o->archives[o->narchives++];
+ a->path = rt->path;
+ a->owned = 1;
+ a->owned_size = rt->path_size;
+ a->whole_archive = rt->whole_archive;
+ a->link_mode = rt->link_mode;
+ a->group_id = rt->group_id;
+ rt->path = NULL;
+ rt->path_size = 0;
+ ld_push_order(o, CFREE_LINK_INPUT_ARCHIVE, o->narchives - 1u);
+}
+
static void ld_push_dso(LdOptions* o, const char* path, int owned,
size_t owned_size) {
LdDso* d = &o->dsos[o->ndsos++];
@@ -639,6 +658,18 @@ static int ld_parse(int argc, char** argv, LdOptions* o) {
o->script_path = argv[i];
continue;
}
+ if (driver_streq(a, "--support-dir")) {
+ if (++i >= argc) {
+ driver_errf(LD_TOOL, "--support-dir requires an argument");
+ return 1;
+ }
+ o->support_dir = argv[i];
+ continue;
+ }
+ if (driver_strneq(a, "--support-dir=", 14)) {
+ o->support_dir = a + 14;
+ continue;
+ }
if (driver_strneq(a, "-L", 2)) {
const char* dir = a[2] ? a + 2 : (++i < argc ? argv[i] : NULL);
@@ -1062,7 +1093,10 @@ static int ld_run_link(LdOptions* o) {
CfreeSlice* dso_in = NULL;
CfreeLinkScript* script = NULL;
CfreeLinkSession* link = NULL;
+ DriverRuntimeSupport runtime = {0};
+ DriverRuntimeArchive rt_archive = {0};
uint32_t i;
+ int runtime_resolved = 0;
int rc = 1;
if (!io || !io->read_all || !io->open_writer) {
@@ -1070,7 +1104,8 @@ static int ld_run_link(LdOptions* o) {
return 1;
}
- /* Allocate scratch parallel arrays sized to the actual input counts. */
+ /* Load object files first so the final target is known before deciding
+ * which compiler-runtime archive to auto-link. */
if (o->nobject_files) {
obj_lf = driver_alloc_zeroed(o->env, o->nobject_files * sizeof(*obj_lf));
obj_in = driver_alloc_zeroed(o->env, o->nobject_files * sizeof(*obj_in));
@@ -1079,6 +1114,42 @@ static int ld_run_link(LdOptions* o) {
goto out;
}
}
+ for (i = 0; i < o->nobject_files; ++i) {
+ const char* path = o->object_files[i];
+ if (load_file(io, path, &obj_lf[i]) != 0) {
+ driver_errf(LD_TOOL, "failed to read: %.*s",
+ CFREE_SLICE_ARG(cfree_slice_cstr(path)));
+ goto out;
+ }
+ obj_in[i].data = obj_lf[i].data.data;
+ obj_in[i].len = obj_lf[i].data.size;
+ }
+
+ /* Auto-detect target from the first object input, falling back to
+ * the host target. PIC overrides parsed from flags are preserved. */
+ if (o->nobject_files > 0) {
+ CfreeTarget detected;
+ if (cfree_detect_target(obj_lf[0].data.data, obj_lf[0].data.size,
+ &detected) == CFREE_OK) {
+ uint8_t pic = o->target.pic;
+ o->target = detected;
+ if (pic != CFREE_PIC_NONE) o->target.pic = pic;
+ }
+ }
+
+ if (!o->relocatable) {
+ if (driver_runtime_resolve(o->env, o->support_dir, o->driver_path,
+ &runtime) != 0) {
+ driver_errf(LD_TOOL, "support dir not found");
+ goto out;
+ }
+ runtime_resolved = 1;
+ if (driver_runtime_prepare_archive(o->env, LD_TOOL, &runtime, o->target, 0,
+ &rt_archive) != 0)
+ goto out;
+ ld_push_runtime_archive(o, &rt_archive);
+ }
+
if (o->narchives) {
arch_lf = driver_alloc_zeroed(o->env, o->narchives * sizeof(*arch_lf));
arch_in = driver_alloc_zeroed(o->env, o->narchives * sizeof(*arch_in));
@@ -1096,17 +1167,6 @@ static int ld_run_link(LdOptions* o) {
}
}
- /* Load object files. */
- for (i = 0; i < o->nobject_files; ++i) {
- const char* path = o->object_files[i];
- if (load_file(io, path, &obj_lf[i]) != 0) {
- driver_errf(LD_TOOL, "failed to read: %.*s",
- CFREE_SLICE_ARG(cfree_slice_cstr(path)));
- goto out;
- }
- obj_in[i].data = obj_lf[i].data.data;
- obj_in[i].len = obj_lf[i].data.size;
- }
/* Load archives. */
for (i = 0; i < o->narchives; ++i) {
const LdArchive* a = &o->archives[i];
@@ -1145,18 +1205,6 @@ static int ld_run_link(LdOptions* o) {
}
}
- /* Auto-detect target from the first object input, falling back to
- * the host target. PIC overrides parsed from flags are preserved. */
- if (o->nobject_files > 0) {
- CfreeTarget detected;
- if (cfree_detect_target(obj_lf[0].data.data, obj_lf[0].data.size,
- &detected) == CFREE_OK) {
- uint8_t pic = o->target.pic;
- o->target = detected;
- if (pic != CFREE_PIC_NONE) o->target.pic = pic;
- }
- }
-
if (driver_compiler_new(o->target, &ctx, &compiler) != CFREE_OK) {
driver_errf(LD_TOOL, "failed to initialize compiler");
goto out;
@@ -1210,8 +1258,7 @@ static int ld_run_link(LdOptions* o) {
lopts.build_id_len = o->build_id_len;
lopts.gc_sections = o->gc_sections;
lopts.strip_debug = o->strip_debug;
- lopts.pie =
- driver_link_pie(o->target, o->pie, o->shared, o->relocatable);
+ lopts.pie = driver_link_pie(o->target, o->pie, o->shared, o->relocatable);
lopts.pe_subsystem = o->pe_subsystem;
lopts.interp_path = cfree_slice_cstr(o->interp_path);
lopts.soname = cfree_slice_cstr(o->soname);
@@ -1285,6 +1332,8 @@ out:
}
if (script) cfree_link_script_free(&ctx, script);
if (compiler) driver_compiler_free(compiler);
+ driver_runtime_archive_fini(o->env, &rt_archive);
+ if (runtime_resolved) driver_runtime_support_fini(o->env, &runtime);
release_file(&script_lf);
release_all(arch_lf, o->narchives);
release_all(obj_lf, o->nobject_files);
@@ -1310,6 +1359,7 @@ int driver_ld(int argc, char** argv) {
driver_env_init(&env);
lo.env = &env;
+ lo.driver_path = argv[0];
if (ld_parse(argc, argv, &lo) != 0) {
ld_options_release(&lo);
diff --git a/driver/runtime.c b/driver/runtime.c
@@ -7,8 +7,6 @@
#include <stdint.h>
#include <string.h>
-#define RT_TOOL "cc"
-
typedef struct RuntimeVariant {
const char* key;
CfreeArchKind arch;
@@ -163,7 +161,6 @@ static void rt_store_const_ptr(const char** slot, const char* value) {
*slot = value;
}
-
static void rt_free_str(DriverEnv* env, char** p, size_t* n) {
if (*p) driver_free(env, *p, *n);
*p = NULL;
@@ -204,8 +201,7 @@ static int rt_try_support_root(DriverEnv* env, const char* root,
rt_root = rt_join(env, root, "rt", &rt_root_size);
if (!rt_root) return 1;
- ok = rt_has_layout(rt_root) &&
- rt_set_layout(env, out, root, rt_root) == 0;
+ ok = rt_has_layout(rt_root) && rt_set_layout(env, out, root, rt_root) == 0;
driver_free(env, rt_root, rt_root_size);
return ok ? 0 : 1;
}
@@ -461,7 +457,7 @@ static void rt_free_pp(DriverEnv* env, CfreePreprocessOptions* pp,
static int rt_compile_source(DriverEnv* env,
const DriverRuntimeSupport* support,
- const RuntimeVariant* variant,
+ const RuntimeVariant* variant, const char* tool,
CfreeCompiler* compiler, const char* rel,
CfreeArInput* member, CfreeWriter** obj_writer) {
CfreeContext ctx = driver_env_to_context(env);
@@ -485,7 +481,7 @@ static int rt_compile_source(DriverEnv* env,
if (!lib_path) goto out;
src_path = rt_join(env, lib_path, rel, &src_path_size);
if (!src_path) goto out;
- if (driver_load_bytes(ctx.file_io, RT_TOOL, src_path, &src_load, &input) != 0)
+ if (driver_load_bytes(ctx.file_io, tool, src_path, &src_load, &input) != 0)
goto out;
if (cfree_writer_mem(ctx.heap, &writer) != CFREE_OK) goto out;
@@ -563,7 +559,7 @@ static int rt_compile_source(DriverEnv* env,
rt_free_pp(env, &copts.preprocess, owned_dirs, owned_sizes, owned_count);
}
if (st != CFREE_OK || cfree_writer_status(writer) != CFREE_OK) {
- driver_errf(RT_TOOL, "failed to build runtime source: %.*s",
+ driver_errf(tool, "failed to build runtime source: %.*s",
CFREE_SLICE_ARG(cfree_slice_cstr(src_path)));
goto out;
}
@@ -586,8 +582,8 @@ out:
}
static int rt_build_archive(DriverEnv* env, const DriverRuntimeSupport* support,
- const RuntimeVariant* variant, uint64_t epoch,
- const char* archive_path) {
+ const RuntimeVariant* variant, const char* tool,
+ uint64_t epoch, const char* archive_path) {
CfreeContext ctx = driver_env_to_context(env);
CfreeCompiler* compiler = NULL;
CfreeWriter* archive_writer = NULL;
@@ -603,7 +599,7 @@ static int rt_build_archive(DriverEnv* env, const DriverRuntimeSupport* support,
obj_writers = (CfreeWriter**)driver_alloc_zeroed(
env, (size_t)variant->nsources * sizeof(*obj_writers));
if (!members || !obj_writers) {
- driver_errf(RT_TOOL, "out of memory");
+ driver_errf(tool, "out of memory");
goto out;
}
@@ -617,19 +613,20 @@ static int rt_build_archive(DriverEnv* env, const DriverRuntimeSupport* support,
target.code_model = CFREE_CM_DEFAULT;
if (driver_compiler_new(target, &ctx, &compiler) != CFREE_OK) {
- driver_errf(RT_TOOL, "failed to initialize compiler for runtime");
+ driver_errf(tool, "failed to initialize compiler for runtime");
goto out;
}
for (i = 0; i < variant->nsources; ++i) {
- if (rt_compile_source(env, support, variant, compiler, variant->sources[i],
- &members[i], &obj_writers[i]) != 0)
+ if (rt_compile_source(env, support, variant, tool, compiler,
+ variant->sources[i], &members[i],
+ &obj_writers[i]) != 0)
goto out;
}
if (ctx.file_io->open_writer(ctx.file_io->user, archive_path,
&archive_writer) != CFREE_OK) {
- driver_errf(RT_TOOL, "failed to open runtime archive: %.*s",
+ driver_errf(tool, "failed to open runtime archive: %.*s",
CFREE_SLICE_ARG(cfree_slice_cstr(archive_path)));
goto out;
}
@@ -638,7 +635,7 @@ static int rt_build_archive(DriverEnv* env, const DriverRuntimeSupport* support,
ar_opts.long_names = 1;
if (cfree_ar_write(archive_writer, members, variant->nsources, &ar_opts) !=
CFREE_OK) {
- driver_errf(RT_TOOL, "failed to write runtime archive: %.*s",
+ driver_errf(tool, "failed to write runtime archive: %.*s",
CFREE_SLICE_ARG(cfree_slice_cstr(archive_path)));
goto out;
}
@@ -691,61 +688,144 @@ static int rt_is_archive_stale(DriverEnv* env,
return 0;
}
-int driver_runtime_ensure_archive(DriverEnv* env,
+static char* rt_archive_dir_for_root(DriverEnv* env, const char* root,
+ const RuntimeVariant* variant,
+ size_t* out_size) {
+ char* build_rt;
+ char* dir = NULL;
+ size_t build_rt_size = 0;
+ size_t dir_size = 0;
+ build_rt = rt_join(env, root, "build/rt", &build_rt_size);
+ if (!build_rt) return NULL;
+ dir = rt_join(env, build_rt, variant->key, &dir_size);
+ driver_free(env, build_rt, build_rt_size);
+ if (out_size) *out_size = dir ? dir_size : 0;
+ return dir;
+}
+
+static int rt_archive_try_dir(DriverEnv* env, const char* tool,
+ const DriverRuntimeSupport* support,
+ const RuntimeVariant* variant, uint64_t epoch,
+ const char* cache_dir, char** out_path,
+ size_t* out_path_size) {
+ char* archive_path;
+ size_t archive_path_size = 0;
+
+ archive_path = rt_join(env, cache_dir, "libcfree_rt.a", &archive_path_size);
+ if (!archive_path) {
+ driver_errf(tool, "out of memory");
+ return 1;
+ }
+
+ if (!driver_path_exists(archive_path) ||
+ rt_is_archive_stale(env, support, variant, archive_path)) {
+ if (driver_mkdir_p(env, cache_dir) != 0) {
+ driver_free(env, archive_path, archive_path_size);
+ return 2;
+ }
+ if (rt_build_archive(env, support, variant, tool, epoch, archive_path) !=
+ 0) {
+ driver_errf(tool, "compiler runtime for %.*s could not be built",
+ CFREE_SLICE_ARG(cfree_slice_cstr(variant->key)));
+ driver_errf(tool, "support dir: %.*s",
+ CFREE_SLICE_ARG(cfree_slice_cstr(support->support_root)));
+ driver_free(env, archive_path, archive_path_size);
+ return 1;
+ }
+ }
+
+ *out_path = archive_path;
+ *out_path_size = archive_path_size;
+ return 0;
+}
+
+int driver_runtime_ensure_archive(DriverEnv* env, const char* tool,
const DriverRuntimeSupport* support,
CfreeTarget target, uint64_t epoch,
char** out_path, size_t* out_path_size) {
const RuntimeVariant* variant = rt_variant_for_target(target);
- char* cache_dir = NULL;
- char* archive_path = NULL;
- size_t cache_dir_size = 0;
- size_t archive_path_size = 0;
+ const char* diag_tool = tool ? tool : "rt";
+ char* primary_dir = NULL;
+ char* fallback_dir = NULL;
+ size_t primary_dir_size = 0;
+ size_t fallback_dir_size = 0;
+ int primary_rc;
+ int fallback_rc = 1;
*out_path = NULL;
*out_path_size = 0;
if (!variant) {
- driver_errf(RT_TOOL, "compiler runtime is not available for this target");
+ driver_errf(diag_tool, "compiler runtime is not available for this target");
return 1;
}
- if (!env->cache_dir) {
- driver_errf(RT_TOOL, "no cache directory configured");
+
+ primary_dir = rt_archive_dir_for_root(env, support->support_root, variant,
+ &primary_dir_size);
+ if (!primary_dir) {
+ driver_errf(diag_tool, "out of memory");
return 1;
}
- cache_dir = rt_join(env, env->cache_dir, variant->key, &cache_dir_size);
- if (!cache_dir) {
- driver_errf(RT_TOOL, "out of memory");
- return 1;
+
+ primary_rc = rt_archive_try_dir(env, diag_tool, support, variant, epoch,
+ primary_dir, out_path, out_path_size);
+ if (primary_rc == 0) {
+ driver_free(env, primary_dir, primary_dir_size);
+ return 0;
}
- archive_path = rt_join(env, cache_dir, "libcfree_rt.a", &archive_path_size);
- if (!archive_path) {
- driver_free(env, cache_dir, cache_dir_size);
- driver_errf(RT_TOOL, "out of memory");
+
+ if (primary_rc != 2) {
+ driver_free(env, primary_dir, primary_dir_size);
return 1;
}
- if (!driver_path_exists(archive_path) ||
- rt_is_archive_stale(env, support, variant, archive_path)) {
- if (driver_mkdir_p(env, cache_dir) != 0) {
- driver_errf(RT_TOOL, "failed to create runtime cache: %.*s",
- CFREE_SLICE_ARG(cfree_slice_cstr(cache_dir)));
- driver_free(env, archive_path, archive_path_size);
- driver_free(env, cache_dir, cache_dir_size);
+ if (env->cache_dir) {
+ fallback_dir =
+ rt_join(env, env->cache_dir, variant->key, &fallback_dir_size);
+ if (!fallback_dir) {
+ driver_free(env, primary_dir, primary_dir_size);
+ driver_errf(diag_tool, "out of memory");
return 1;
}
- if (rt_build_archive(env, support, variant, epoch, archive_path) != 0) {
- driver_errf(RT_TOOL, "compiler runtime for %.*s could not be built",
- CFREE_SLICE_ARG(cfree_slice_cstr(variant->key)));
- driver_errf(RT_TOOL, "support dir: %.*s",
- CFREE_SLICE_ARG(cfree_slice_cstr(support->support_root)));
- driver_free(env, archive_path, archive_path_size);
- driver_free(env, cache_dir, cache_dir_size);
- return 1;
+ fallback_rc = rt_archive_try_dir(env, diag_tool, support, variant, epoch,
+ fallback_dir, out_path, out_path_size);
+ }
+
+ if (fallback_rc == 2 || !env->cache_dir) {
+ driver_errf(diag_tool, "failed to create runtime cache: %.*s",
+ CFREE_SLICE_ARG(cfree_slice_cstr(primary_dir)));
+ if (fallback_dir) {
+ driver_errf(diag_tool, "failed to create runtime cache: %.*s",
+ CFREE_SLICE_ARG(cfree_slice_cstr(fallback_dir)));
}
}
+ if (fallback_dir) driver_free(env, fallback_dir, fallback_dir_size);
+ driver_free(env, primary_dir, primary_dir_size);
+ return fallback_rc == 0 ? 0 : 1;
+}
- driver_free(env, cache_dir, cache_dir_size);
- *out_path = archive_path;
- *out_path_size = archive_path_size;
+int driver_runtime_prepare_archive(DriverEnv* env, const char* tool,
+ const DriverRuntimeSupport* support,
+ CfreeTarget target, uint64_t epoch,
+ DriverRuntimeArchive* out) {
+ DriverRuntimeArchive z = {0};
+ if (!out) return 1;
+ *out = z;
+ if (driver_runtime_ensure_archive(env, tool, support, target, epoch,
+ &out->path, &out->path_size) != 0)
+ return 1;
+ out->whole_archive = 0;
+ out->link_mode = CFREE_LM_STATIC;
+ out->group_id = 0;
return 0;
}
+
+void driver_runtime_archive_fini(DriverEnv* env, DriverRuntimeArchive* a) {
+ if (!a) return;
+ if (a->path) driver_free(env, a->path, a->path_size);
+ a->path = NULL;
+ a->path_size = 0;
+ a->whole_archive = 0;
+ a->link_mode = 0;
+ a->group_id = 0;
+}
diff --git a/driver/runtime.h b/driver/runtime.h
@@ -1,6 +1,8 @@
#ifndef CFREE_DRIVER_RUNTIME_H
#define CFREE_DRIVER_RUNTIME_H
+#include <cfree/link.h>
+
#include "cflags.h"
#include "driver.h"
@@ -14,6 +16,14 @@ typedef struct DriverRuntimeSupport {
const char* tool_path;
} DriverRuntimeSupport;
+typedef struct DriverRuntimeArchive {
+ char* path;
+ size_t path_size;
+ uint8_t whole_archive;
+ uint8_t link_mode;
+ uint8_t group_id;
+} DriverRuntimeArchive;
+
int driver_runtime_resolve(DriverEnv* env, const char* explicit_support_dir,
const char* argv0, DriverRuntimeSupport* out);
void driver_runtime_support_fini(DriverEnv* env, DriverRuntimeSupport* s);
@@ -23,9 +33,14 @@ int driver_runtime_add_freestanding_headers(const DriverRuntimeSupport* s,
int driver_runtime_append_freestanding_headers(const DriverRuntimeSupport* s,
DriverCflags* cf);
-int driver_runtime_ensure_archive(DriverEnv* env,
+int driver_runtime_ensure_archive(DriverEnv* env, const char* tool,
const DriverRuntimeSupport* support,
CfreeTarget target, uint64_t epoch,
char** out_path, size_t* out_path_size);
+int driver_runtime_prepare_archive(DriverEnv* env, const char* tool,
+ const DriverRuntimeSupport* support,
+ CfreeTarget target, uint64_t epoch,
+ DriverRuntimeArchive* out);
+void driver_runtime_archive_fini(DriverEnv* env, DriverRuntimeArchive* a);
#endif
diff --git a/test/driver/run.sh b/test/driver/run.sh
@@ -352,6 +352,26 @@ else
fail=$((fail + 1))
fi
+mkdir -p "$work/ld-rt-support/rt"
+cp -R "$repo_root/rt/include" "$work/ld-rt-support/rt/include"
+cp -R "$repo_root/rt/lib" "$work/ld-rt-support/rt/lib"
+if "$CFREE" cc --support-dir "$work/ld-rt-support" -target aarch64-linux \
+ -c "$work/rt-div.c" -o "$work/ld-rt-div.o" \
+ > "$work/ld-rt-div-cc.out" 2> "$work/ld-rt-div-cc.err" &&
+ "$CFREE" ld --support-dir "$work/ld-rt-support" \
+ -e _start "$work/ld-rt-div.o" -o "$work/ld-rt-div" \
+ > "$work/ld-rt-div.out" 2> "$work/ld-rt-div.err" &&
+ [ -f "$work/ld-rt-support/build/rt/aarch64-linux/libcfree_rt.a" ]; then
+ printf 'PASS %s\n' "ld-auto-builds-and-links-libcfree-rt"
+ pass=$((pass + 1))
+else
+ printf 'FAIL %s (cfree ld failed)\n' \
+ "ld-auto-builds-and-links-libcfree-rt"
+ sed 's/^/ | /' "$work/ld-rt-div-cc.err"
+ sed 's/^/ | /' "$work/ld-rt-div.err" 2>/dev/null || true
+ fail=$((fail + 1))
+fi
+
if "$CFREE" ld "$work/main.o" --output="$work/ld-long-output" \
> "$work/ld-long-output.out" 2> "$work/ld-long-output.err" &&
[ -f "$work/ld-long-output" ]; then