inputs.c (13943B)
1 #include "inputs.h" 2 3 #include <kit/frontend.h> 4 #include <stddef.h> 5 #include <stdint.h> 6 #include <string.h> 7 8 int driver_inputs_init(DriverInputs* in, DriverEnv* env, const char* tool, 9 int argc) { 10 size_t bound = (size_t)argc; 11 in->env = env; 12 in->tool = tool; 13 in->bound = bound; 14 in->sources = driver_alloc_zeroed(env, bound * sizeof(*in->sources)); 15 in->source_memory = 16 driver_alloc_zeroed(env, bound * sizeof(*in->source_memory)); 17 in->object_files = 18 driver_alloc_zeroed(env, bound * sizeof(*in->object_files)); 19 in->archives = driver_alloc_zeroed(env, bound * sizeof(*in->archives)); 20 if (!in->sources || !in->source_memory || !in->object_files || 21 !in->archives) { 22 driver_errf(tool, "out of memory"); 23 return 1; 24 } 25 return 0; 26 } 27 28 void driver_inputs_release(DriverInputs* in) { 29 size_t bound = in->bound; 30 if (in->stdin_buf) driver_free(in->env, in->stdin_buf, in->stdin_size); 31 if (in->sources) 32 driver_free(in->env, in->sources, bound * sizeof(*in->sources)); 33 if (in->source_memory) 34 driver_free(in->env, in->source_memory, bound * sizeof(*in->source_memory)); 35 if (in->object_files) 36 driver_free(in->env, in->object_files, bound * sizeof(*in->object_files)); 37 if (in->archives) 38 driver_free(in->env, in->archives, bound * sizeof(*in->archives)); 39 } 40 41 /* Slurp stdin into the single source_memory entry. Guarded against 42 * duplicates so a user typo (`kit run - -`) is surfaced rather than 43 * silently leaking the first slurp. */ 44 static int inputs_record_stdin(DriverInputs* in) { 45 KitSourceInput* slot; 46 if (in->stdin_buf) { 47 driver_errf(in->tool, "'-' (stdin) may appear at most once"); 48 return -1; 49 } 50 if (!driver_read_stdin(in->env, &in->stdin_buf, &in->stdin_size)) { 51 driver_errf(in->tool, "failed to read stdin"); 52 return -1; 53 } 54 slot = &in->source_memory[in->nsource_memory++]; 55 slot->name = KIT_SLICE_LIT("<stdin>"); 56 slot->bytes.data = in->stdin_buf; 57 slot->bytes.len = in->stdin_size; 58 slot->lang = KIT_LANG_C; 59 return 1; 60 } 61 62 /* A compilable source file: a path some registered frontend claims (via the 63 * canonical extension registry, case-insensitively), excluding C headers — the 64 * C frontend registers ".h" so language-for-path can identify headers, but a 65 * header is not a translation unit to compile. No compiler exists at arg-parse 66 * time, so this resolves against the compile-time default frontend set 67 * (kit_language_for_path(NULL, ...)). The single source of truth shared by 68 * cc/build/run/dbg source classification. */ 69 int driver_path_is_source(const char* path) { 70 if (!path) return 0; 71 if (kit_language_for_path(NULL, path) == KIT_LANG_UNKNOWN) return 0; 72 if (driver_has_suffix(path, ".h") || driver_has_suffix(path, ".H")) return 0; 73 return 1; 74 } 75 76 int driver_inputs_classify(DriverInputs* in, const char* arg) { 77 if (driver_streq(arg, "-")) return inputs_record_stdin(in); 78 /* Source classification flows through the shared driver_path_is_source helper 79 * (canonical extension registry, headers excluded). This also fixes a latent 80 * bug: the former explicit list checked only ".s" case-sensitively, so ".S" 81 * assembly was misclassified; the registry matches case-insensitively. */ 82 if (driver_path_is_source(arg)) { 83 in->sources[in->nsources++] = arg; 84 return 1; 85 } 86 if (driver_has_suffix(arg, ".o") || driver_has_suffix(arg, ".obj")) { 87 in->object_files[in->nobject_files++] = arg; 88 return 1; 89 } 90 if (driver_has_suffix(arg, ".a")) { 91 in->archives[in->narchives++] = arg; 92 return 1; 93 } 94 return 0; 95 } 96 97 uint32_t driver_inputs_count(const DriverInputs* in) { 98 return in->nsources + in->nsource_memory + in->nobject_files + in->narchives; 99 } 100 101 const char* driver_inputs_first_name(const DriverInputs* in) { 102 if (in->nsources) return in->sources[0]; 103 if (in->nsource_memory) return in->source_memory[0].name.s; 104 if (in->nobject_files) return in->object_files[0]; 105 if (in->narchives) return in->archives[0]; 106 return NULL; 107 } 108 109 /* Load every input through env.file_io, compile sources via `compiler` with 110 * `copts`, and JIT-link. The compiler must outlive the JIT — it backs 111 * jit->c, which kit_jit_lookup dereferences. */ 112 int driver_inputs_compile_and_jit(DriverInputs* in, KitCompiler* compiler, 113 const KitJitHost* host, 114 const KitCCompileOptions* copts, 115 const KitPreprocessOptions* pp, 116 const char* entry, 117 void* (*extern_resolver)(void*, KitSlice), 118 void* extern_resolver_user, 119 KitJit** out_jit) { 120 DriverEnv* env = in->env; 121 const char* tool = in->tool; 122 KitContext ctx = driver_env_to_context(env); 123 const KitFileIO* io = ctx.file_io; 124 DriverLoad* src_lf = NULL; 125 DriverLoad* obj_lf = NULL; 126 DriverLoad* arch_lf = NULL; 127 KitSlice* src_bytes = NULL; /* per-path source bytes for loads */ 128 KitSlice* obj_in = NULL; 129 KitLinkArchiveInput* arch_in = NULL; 130 KitObjBuilder** objs = NULL; 131 KitLinkSession* link = NULL; 132 uint32_t nsrc = in->nsources + in->nsource_memory; 133 uint32_t i; 134 int rc = 1; 135 136 if (!io || !io->read_all) { 137 driver_errf(tool, "host file I/O unavailable"); 138 return 1; 139 } 140 141 if (in->nsources) { 142 src_bytes = driver_alloc_zeroed(env, in->nsources * sizeof(*src_bytes)); 143 src_lf = driver_alloc_zeroed(env, in->nsources * sizeof(*src_lf)); 144 if (!src_bytes || !src_lf) { 145 driver_errf(tool, "out of memory"); 146 goto out; 147 } 148 } 149 if (nsrc) { 150 objs = driver_alloc_zeroed(env, nsrc * sizeof(*objs)); 151 if (!objs) { 152 driver_errf(tool, "out of memory"); 153 goto out; 154 } 155 } 156 if (in->nobject_files) { 157 obj_lf = driver_alloc_zeroed(env, in->nobject_files * sizeof(*obj_lf)); 158 obj_in = driver_alloc_zeroed(env, in->nobject_files * sizeof(*obj_in)); 159 if (!obj_lf || !obj_in) { 160 driver_errf(tool, "out of memory"); 161 goto out; 162 } 163 } 164 if (in->narchives) { 165 arch_lf = driver_alloc_zeroed(env, in->narchives * sizeof(*arch_lf)); 166 arch_in = driver_alloc_zeroed(env, in->narchives * sizeof(*arch_in)); 167 if (!arch_lf || !arch_in) { 168 driver_errf(tool, "out of memory"); 169 goto out; 170 } 171 } 172 173 /* Load source files into KitSlice and compile them into object builders. */ 174 kit_frontend_metrics_scope_begin(compiler, "driver.load_sources"); 175 for (i = 0; i < in->nsources; ++i) { 176 if (driver_load_bytes(io, tool, in->sources[i], &src_lf[i], 177 &src_bytes[i]) != 0) { 178 kit_frontend_metrics_scope_end(compiler, "driver.load_sources"); 179 goto out; 180 } 181 } 182 kit_frontend_metrics_scope_end(compiler, "driver.load_sources"); 183 184 for (i = 0; i < in->nsources; ++i) { 185 KitLanguage lang = kit_language_for_path(compiler, in->sources[i]); 186 KitCompileSessionOptions sopts; 187 KitCompileSession* session = NULL; 188 KitSourceInput sin; 189 KitStatus st; 190 memset(&sopts, 0, sizeof(sopts)); 191 sopts.lang = lang; 192 sopts.compile.code = copts->code; 193 sopts.compile.diagnostics = copts->diagnostics; 194 if (pp) sopts.compile.preprocess = *pp; 195 memset(&sin, 0, sizeof(sin)); 196 sin.name = kit_slice_cstr(in->sources[i]); 197 sin.bytes = src_bytes[i]; 198 sin.lang = lang; 199 st = kit_compile_session_new(compiler, &sopts, &session); 200 if (st == KIT_OK) st = kit_compile_session_compile(session, &sin, &objs[i]); 201 kit_compile_session_free(session); 202 if (st != KIT_OK) goto out; 203 } 204 for (i = 0; i < in->nsource_memory; ++i) { 205 KitCompileSessionOptions sopts; 206 KitCompileSession* session = NULL; 207 KitStatus st; 208 memset(&sopts, 0, sizeof(sopts)); 209 sopts.lang = in->source_memory[i].lang; 210 sopts.compile.code = copts->code; 211 sopts.compile.diagnostics = copts->diagnostics; 212 if (pp) sopts.compile.preprocess = *pp; 213 st = kit_compile_session_new(compiler, &sopts, &session); 214 if (st == KIT_OK) 215 st = kit_compile_session_compile(session, &in->source_memory[i], 216 &objs[in->nsources + i]); 217 kit_compile_session_free(session); 218 if (st != KIT_OK) goto out; 219 } 220 221 kit_frontend_metrics_scope_begin(compiler, "driver.load_objects"); 222 for (i = 0; i < in->nobject_files; ++i) { 223 if (driver_load_bytes(io, tool, in->object_files[i], &obj_lf[i], 224 &obj_in[i]) != 0) { 225 kit_frontend_metrics_scope_end(compiler, "driver.load_objects"); 226 goto out; 227 } 228 } 229 kit_frontend_metrics_scope_end(compiler, "driver.load_objects"); 230 kit_frontend_metrics_scope_begin(compiler, "driver.load_archives"); 231 for (i = 0; i < in->narchives; ++i) { 232 if (driver_load_bytes(io, tool, in->archives[i], &arch_lf[i], 233 &arch_in[i].bytes) != 0) { 234 kit_frontend_metrics_scope_end(compiler, "driver.load_archives"); 235 goto out; 236 } 237 arch_in[i].link_mode = KIT_LM_DEFAULT; 238 arch_in[i].whole_archive = 0; 239 arch_in[i].group_id = 0; 240 } 241 kit_frontend_metrics_scope_end(compiler, "driver.load_archives"); 242 243 { 244 KitLinkSessionOptions lopts; 245 KitStatus st; 246 memset(&lopts, 0, sizeof(lopts)); 247 lopts.output_kind = KIT_LINK_OUTPUT_JIT; 248 lopts.entry = kit_slice_cstr(entry); 249 lopts.jit_host = host; 250 lopts.extern_resolver = extern_resolver; 251 lopts.extern_resolver_user = extern_resolver_user; 252 kit_frontend_metrics_scope_begin(compiler, "driver.link_setup"); 253 st = kit_link_session_new(compiler, &lopts, &link); 254 for (i = 0; st == KIT_OK && i < nsrc; ++i) 255 st = kit_link_session_add_obj(link, objs[i]); 256 for (i = 0; st == KIT_OK && i < in->nobject_files; ++i) 257 st = kit_link_session_add_obj_bytes( 258 link, kit_slice_cstr(in->object_files[i]), &obj_in[i]); 259 for (i = 0; st == KIT_OK && i < in->narchives; ++i) 260 st = kit_link_session_add_archive_bytes(link, &arch_in[i]); 261 kit_frontend_metrics_scope_end(compiler, "driver.link_setup"); 262 if (st == KIT_OK) st = kit_link_session_jit(link, out_jit); 263 rc = st == KIT_OK ? 0 : 1; 264 } 265 266 out: 267 kit_link_session_free(link); 268 if (arch_lf) { 269 for (i = 0; i < in->narchives; ++i) driver_release_bytes(io, &arch_lf[i]); 270 } 271 if (obj_lf) { 272 for (i = 0; i < in->nobject_files; ++i) 273 driver_release_bytes(io, &obj_lf[i]); 274 } 275 if (src_lf) { 276 for (i = 0; i < in->nsources; ++i) driver_release_bytes(io, &src_lf[i]); 277 } 278 if (arch_in) driver_free(env, arch_in, in->narchives * sizeof(*arch_in)); 279 if (arch_lf) driver_free(env, arch_lf, in->narchives * sizeof(*arch_lf)); 280 if (obj_in) driver_free(env, obj_in, in->nobject_files * sizeof(*obj_in)); 281 if (obj_lf) driver_free(env, obj_lf, in->nobject_files * sizeof(*obj_lf)); 282 if (src_lf) driver_free(env, src_lf, in->nsources * sizeof(*src_lf)); 283 if (src_bytes) driver_free(env, src_bytes, in->nsources * sizeof(*src_bytes)); 284 if (objs) driver_free(env, objs, nsrc * sizeof(*objs)); 285 return rc; 286 } 287 288 /* ---------------------------------------------------------------------- 289 * Per-object global-symbol collection (shared by ar / ranlib / strip). 290 * ---------------------------------------------------------------------- */ 291 292 int driver_collect_obj_global_syms(DriverEnv* env, const KitContext* ctx, 293 const char* tool, const KitSlice* member, 294 void** blob_out, size_t* blob_size_out, 295 const KitSlice** names_out, 296 uint32_t* count_out) { 297 KitObjFile* of = NULL; 298 KitObjSymIter* it = NULL; 299 KitObjSymInfo si; 300 uint32_t count = 0; 301 size_t name_bytes = 0; 302 size_t alloc_sz; 303 char* blob; 304 KitSlice* name_arr; 305 char* name_storage; 306 size_t cursor = 0; 307 308 *blob_out = NULL; 309 *blob_size_out = 0; 310 *names_out = NULL; 311 *count_out = 0; 312 313 if (kit_obj_open(ctx, KIT_SLICE_NULL, member, &of) != KIT_OK) { 314 /* Not a recognized object — caller treats as "no symbols". */ 315 return 0; 316 } 317 318 /* Pass A: count + measure name bytes. */ 319 if (kit_obj_symiter_new(of, &it) != KIT_OK) { 320 kit_obj_free(of); 321 driver_errf(tool, "out of memory"); 322 return 1; 323 } 324 for (;;) { 325 KitIterResult r = kit_obj_symiter_next(it, &si); 326 if (r != KIT_ITER_ITEM) break; 327 if (si.bind != KIT_SB_GLOBAL) continue; 328 if (si.section == KIT_SECTION_NONE) continue; 329 if (!si.name.len) continue; 330 count += 1; 331 name_bytes += si.name.len + 1; /* +NUL */ 332 } 333 kit_obj_symiter_free(it); 334 335 if (count == 0) { 336 kit_obj_free(of); 337 return 0; 338 } 339 340 alloc_sz = (size_t)count * sizeof(KitSlice) + name_bytes; 341 blob = (char*)driver_alloc_zeroed(env, alloc_sz); 342 if (!blob) { 343 kit_obj_free(of); 344 driver_errf(tool, "out of memory"); 345 return 1; 346 } 347 name_arr = (KitSlice*)blob; 348 name_storage = blob + (size_t)count * sizeof(KitSlice); 349 350 /* Pass B: copy names. */ 351 if (kit_obj_symiter_new(of, &it) != KIT_OK) { 352 driver_free(env, blob, alloc_sz); 353 kit_obj_free(of); 354 driver_errf(tool, "out of memory"); 355 return 1; 356 } 357 { 358 uint32_t k = 0; 359 for (;;) { 360 KitIterResult r; 361 char* dst; 362 size_t j; 363 if (k >= count) break; 364 r = kit_obj_symiter_next(it, &si); 365 if (r != KIT_ITER_ITEM) break; 366 if (si.bind != KIT_SB_GLOBAL) continue; 367 if (si.section == KIT_SECTION_NONE) continue; 368 if (!si.name.len) continue; 369 dst = name_storage + cursor; 370 name_arr[k].s = dst; 371 name_arr[k].len = si.name.len; 372 for (j = 0; j < si.name.len; ++j) *dst++ = si.name.s[j]; 373 *dst++ = '\0'; 374 cursor = (size_t)(dst - name_storage); 375 k++; 376 } 377 count = k; 378 } 379 kit_obj_symiter_free(it); 380 kit_obj_free(of); 381 382 *blob_out = blob; 383 *blob_size_out = alloc_sz; 384 *names_out = name_arr; 385 *count_out = count; 386 return 0; 387 } 388 389 void driver_collect_obj_global_syms_free(DriverEnv* env, void* blob, 390 size_t blob_size) { 391 if (blob) driver_free(env, blob, blob_size); 392 }