inputs.c (13096B)
1 #include "inputs.h" 2 3 #include <kit/archive.h> 4 #include <kit/frontend.h> 5 #include <stddef.h> 6 #include <stdint.h> 7 #include <string.h> 8 9 int driver_inputs_init(DriverInputs* in, DriverEnv* env, const char* tool, 10 int argc) { 11 size_t bound = (size_t)argc; 12 in->env = env; 13 in->tool = tool; 14 in->bound = bound; 15 in->sources = driver_alloc_zeroed(env, bound * sizeof(*in->sources)); 16 in->source_memory = 17 driver_alloc_zeroed(env, bound * sizeof(*in->source_memory)); 18 in->object_files = 19 driver_alloc_zeroed(env, bound * sizeof(*in->object_files)); 20 in->archives = driver_alloc_zeroed(env, bound * sizeof(*in->archives)); 21 if (!in->sources || !in->source_memory || !in->object_files || 22 !in->archives) { 23 driver_errf(tool, "out of memory"); 24 return 1; 25 } 26 return 0; 27 } 28 29 void driver_inputs_release(DriverInputs* in) { 30 size_t bound = in->bound; 31 if (in->stdin_buf) driver_free(in->env, in->stdin_buf, in->stdin_size); 32 if (in->sources) 33 driver_free(in->env, in->sources, bound * sizeof(*in->sources)); 34 if (in->source_memory) 35 driver_free(in->env, in->source_memory, bound * sizeof(*in->source_memory)); 36 if (in->object_files) 37 driver_free(in->env, in->object_files, bound * sizeof(*in->object_files)); 38 if (in->archives) 39 driver_free(in->env, in->archives, bound * sizeof(*in->archives)); 40 } 41 42 /* Slurp stdin into the single source_memory entry. Guarded against 43 * duplicates so a user typo (`kit run - -`) is surfaced rather than 44 * silently leaking the first slurp. */ 45 static int inputs_record_stdin(DriverInputs* in) { 46 KitSourceInput* slot; 47 if (in->stdin_buf) { 48 driver_errf(in->tool, "'-' (stdin) may appear at most once"); 49 return -1; 50 } 51 if (!driver_read_stdin(in->env, &in->stdin_buf, &in->stdin_size)) { 52 driver_errf(in->tool, "failed to read stdin"); 53 return -1; 54 } 55 slot = &in->source_memory[in->nsource_memory++]; 56 slot->name = KIT_SLICE_LIT("<stdin>"); 57 slot->bytes.data = in->stdin_buf; 58 slot->bytes.len = in->stdin_size; 59 slot->lang = KIT_LANG_C; 60 return 1; 61 } 62 63 /* A compilable source file: a path some registered frontend claims (via the 64 * canonical extension registry, case-insensitively), excluding C headers — the 65 * C frontend registers ".h" so language-for-path can identify headers, but a 66 * header is not a translation unit to compile. No compiler exists at arg-parse 67 * time, so this resolves against the compile-time default frontend set 68 * (kit_language_for_path(NULL, ...)). The single source of truth shared by 69 * cc/build/run/dbg source classification. */ 70 int driver_path_is_source(const char* path) { 71 if (!path) return 0; 72 return kit_language_path_kind(NULL, path, NULL) == KIT_FRONTEND_PATH_SOURCE; 73 } 74 75 int driver_inputs_classify(DriverInputs* in, const char* arg) { 76 if (driver_streq(arg, "-")) return inputs_record_stdin(in); 77 /* Classification flows through the public kit_input_kind_for_path: source 78 * via the canonical case-insensitive extension registry (headers excluded), 79 * then the object/archive suffix tests. A .so/.dylib is KIT_INPUT_DSO, which 80 * run/dbg do not accept, so it falls through to "unrecognized" like before. */ 81 if (in->frontends && 82 kit_frontend_registry_path_kind(in->frontends, arg, NULL) == 83 KIT_FRONTEND_PATH_SOURCE) { 84 in->sources[in->nsources++] = arg; 85 return 1; 86 } 87 switch (kit_input_kind_for_path(NULL, arg)) { 88 case KIT_INPUT_SOURCE: 89 in->sources[in->nsources++] = arg; 90 return 1; 91 case KIT_INPUT_OBJECT: 92 in->object_files[in->nobject_files++] = arg; 93 return 1; 94 case KIT_INPUT_ARCHIVE: 95 in->archives[in->narchives++] = arg; 96 return 1; 97 case KIT_INPUT_DSO: 98 case KIT_INPUT_UNKNOWN: 99 break; 100 } 101 return 0; 102 } 103 104 uint32_t driver_inputs_count(const DriverInputs* in) { 105 return in->nsources + in->nsource_memory + in->nobject_files + in->narchives; 106 } 107 108 const char* driver_inputs_first_name(const DriverInputs* in) { 109 if (in->nsources) return in->sources[0]; 110 if (in->nsource_memory) return in->source_memory[0].name.s; 111 if (in->nobject_files) return in->object_files[0]; 112 if (in->narchives) return in->archives[0]; 113 return NULL; 114 } 115 116 /* Load every input through env.file_io, compile sources via `compiler` with 117 * `copts`, and JIT-link. The compiler must outlive the JIT — it backs 118 * jit->c, which kit_jit_lookup dereferences. */ 119 int driver_inputs_compile_and_jit( 120 DriverInputs* in, KitCompiler* compiler, const KitJitHost* host, 121 const KitCCompileOptions* copts, const KitPreprocessOptions* pp, 122 const char* entry, void* (*extern_resolver)(void*, KitSlice), 123 void* extern_resolver_user, KitJit** out_jit) { 124 DriverEnv* env = in->env; 125 const char* tool = in->tool; 126 KitContext ctx = driver_env_to_context(env); 127 const KitFileIO* io = ctx.file_io; 128 DriverLoad* src_lf = NULL; 129 DriverLoad* obj_lf = NULL; 130 DriverLoad* arch_lf = NULL; 131 KitSlice* src_bytes = NULL; /* per-path source bytes for loads */ 132 KitSlice* obj_in = NULL; 133 KitLinkArchiveInput* arch_in = NULL; 134 KitObjBuilder** objs = NULL; 135 KitLinkSession* link = NULL; 136 uint32_t nsrc = in->nsources + in->nsource_memory; 137 uint32_t i; 138 int rc = 1; 139 140 if (!io || !io->read_all) { 141 driver_errf(tool, "host file I/O unavailable"); 142 return 1; 143 } 144 145 if (in->nsources) { 146 src_bytes = driver_alloc_zeroed(env, in->nsources * sizeof(*src_bytes)); 147 src_lf = driver_alloc_zeroed(env, in->nsources * sizeof(*src_lf)); 148 if (!src_bytes || !src_lf) { 149 driver_errf(tool, "out of memory"); 150 goto out; 151 } 152 } 153 if (nsrc) { 154 objs = driver_alloc_zeroed(env, nsrc * sizeof(*objs)); 155 if (!objs) { 156 driver_errf(tool, "out of memory"); 157 goto out; 158 } 159 } 160 if (in->nobject_files) { 161 obj_lf = driver_alloc_zeroed(env, in->nobject_files * sizeof(*obj_lf)); 162 obj_in = driver_alloc_zeroed(env, in->nobject_files * sizeof(*obj_in)); 163 if (!obj_lf || !obj_in) { 164 driver_errf(tool, "out of memory"); 165 goto out; 166 } 167 } 168 if (in->narchives) { 169 arch_lf = driver_alloc_zeroed(env, in->narchives * sizeof(*arch_lf)); 170 arch_in = driver_alloc_zeroed(env, in->narchives * sizeof(*arch_in)); 171 if (!arch_lf || !arch_in) { 172 driver_errf(tool, "out of memory"); 173 goto out; 174 } 175 } 176 177 /* Load source files into KitSlice and compile them into object builders. */ 178 kit_frontend_profile_scope_begin(compiler, 179 KIT_PROFILE_SCOPE_DRIVER_LOAD_SOURCES); 180 for (i = 0; i < in->nsources; ++i) { 181 if (driver_load_bytes(io, tool, in->sources[i], &src_lf[i], 182 &src_bytes[i]) != 0) { 183 kit_frontend_profile_scope_end(compiler, 184 KIT_PROFILE_SCOPE_DRIVER_LOAD_SOURCES); 185 goto out; 186 } 187 } 188 kit_frontend_profile_scope_end(compiler, 189 KIT_PROFILE_SCOPE_DRIVER_LOAD_SOURCES); 190 191 for (i = 0; i < in->nsources; ++i) { 192 KitLanguage lang = kit_language_for_path(compiler, in->sources[i]); 193 KitCompileSessionOptions sopts; 194 KitCompileSession* session = NULL; 195 KitSourceInput sin; 196 KitStatus st; 197 memset(&sopts, 0, sizeof(sopts)); 198 sopts.lang = lang; 199 sopts.compile.code = copts->code; 200 sopts.compile.diagnostics = copts->diagnostics; 201 if (pp) sopts.compile.preprocess = *pp; 202 memset(&sin, 0, sizeof(sin)); 203 sin.name = kit_slice_cstr(in->sources[i]); 204 sin.bytes = src_bytes[i]; 205 sin.lang = lang; 206 st = kit_compile_session_new(compiler, &sopts, &session); 207 if (st == KIT_OK) st = kit_compile_session_compile(session, &sin, &objs[i]); 208 kit_compile_session_free(session); 209 if (st != KIT_OK) goto out; 210 } 211 for (i = 0; i < in->nsource_memory; ++i) { 212 KitCompileSessionOptions sopts; 213 KitCompileSession* session = NULL; 214 KitStatus st; 215 memset(&sopts, 0, sizeof(sopts)); 216 sopts.lang = in->source_memory[i].lang; 217 sopts.compile.code = copts->code; 218 sopts.compile.diagnostics = copts->diagnostics; 219 if (pp) sopts.compile.preprocess = *pp; 220 st = kit_compile_session_new(compiler, &sopts, &session); 221 if (st == KIT_OK) 222 st = kit_compile_session_compile(session, &in->source_memory[i], 223 &objs[in->nsources + i]); 224 kit_compile_session_free(session); 225 if (st != KIT_OK) goto out; 226 } 227 228 kit_frontend_profile_scope_begin(compiler, 229 KIT_PROFILE_SCOPE_DRIVER_LOAD_OBJECTS); 230 for (i = 0; i < in->nobject_files; ++i) { 231 if (driver_load_bytes(io, tool, in->object_files[i], &obj_lf[i], 232 &obj_in[i]) != 0) { 233 kit_frontend_profile_scope_end(compiler, 234 KIT_PROFILE_SCOPE_DRIVER_LOAD_OBJECTS); 235 goto out; 236 } 237 } 238 kit_frontend_profile_scope_end(compiler, 239 KIT_PROFILE_SCOPE_DRIVER_LOAD_OBJECTS); 240 kit_frontend_profile_scope_begin(compiler, 241 KIT_PROFILE_SCOPE_DRIVER_LOAD_ARCHIVES); 242 for (i = 0; i < in->narchives; ++i) { 243 if (driver_load_bytes(io, tool, in->archives[i], &arch_lf[i], 244 &arch_in[i].bytes) != 0) { 245 kit_frontend_profile_scope_end(compiler, 246 KIT_PROFILE_SCOPE_DRIVER_LOAD_ARCHIVES); 247 goto out; 248 } 249 arch_in[i].link_mode = KIT_LM_DEFAULT; 250 arch_in[i].whole_archive = 0; 251 arch_in[i].group_id = 0; 252 } 253 kit_frontend_profile_scope_end(compiler, 254 KIT_PROFILE_SCOPE_DRIVER_LOAD_ARCHIVES); 255 256 { 257 KitLinkSessionOptions lopts; 258 KitStatus st; 259 memset(&lopts, 0, sizeof(lopts)); 260 lopts.output_kind = KIT_LINK_OUTPUT_JIT; 261 lopts.entry = kit_slice_cstr(entry); 262 lopts.jit_host = host; 263 lopts.extern_resolver = extern_resolver; 264 lopts.extern_resolver_user = extern_resolver_user; 265 kit_frontend_profile_scope_begin(compiler, 266 KIT_PROFILE_SCOPE_DRIVER_LINK_SETUP); 267 st = kit_link_session_new(compiler, &lopts, &link); 268 for (i = 0; st == KIT_OK && i < nsrc; ++i) 269 st = kit_link_session_add_obj(link, objs[i]); 270 for (i = 0; st == KIT_OK && i < in->nobject_files; ++i) 271 st = kit_link_session_add_obj_bytes( 272 link, kit_slice_cstr(in->object_files[i]), &obj_in[i]); 273 for (i = 0; st == KIT_OK && i < in->narchives; ++i) 274 st = kit_link_session_add_archive_bytes(link, &arch_in[i]); 275 kit_frontend_profile_scope_end(compiler, 276 KIT_PROFILE_SCOPE_DRIVER_LINK_SETUP); 277 if (st == KIT_OK) st = kit_link_session_jit(link, out_jit); 278 rc = st == KIT_OK ? 0 : 1; 279 } 280 281 out: 282 kit_link_session_free(link); 283 if (arch_lf) { 284 for (i = 0; i < in->narchives; ++i) driver_release_bytes(io, &arch_lf[i]); 285 } 286 if (obj_lf) { 287 for (i = 0; i < in->nobject_files; ++i) 288 driver_release_bytes(io, &obj_lf[i]); 289 } 290 if (src_lf) { 291 for (i = 0; i < in->nsources; ++i) driver_release_bytes(io, &src_lf[i]); 292 } 293 if (arch_in) driver_free(env, arch_in, in->narchives * sizeof(*arch_in)); 294 if (arch_lf) driver_free(env, arch_lf, in->narchives * sizeof(*arch_lf)); 295 if (obj_in) driver_free(env, obj_in, in->nobject_files * sizeof(*obj_in)); 296 if (obj_lf) driver_free(env, obj_lf, in->nobject_files * sizeof(*obj_lf)); 297 if (src_lf) driver_free(env, src_lf, in->nsources * sizeof(*src_lf)); 298 if (src_bytes) driver_free(env, src_bytes, in->nsources * sizeof(*src_bytes)); 299 if (objs) driver_free(env, objs, nsrc * sizeof(*objs)); 300 return rc; 301 } 302 303 /* ---------------------------------------------------------------------- 304 * Per-object global-symbol collection (shared by ar / ranlib / strip). 305 * 306 * The "which symbols a linker indexes" policy and the collect-and-pack work 307 * now live in libkit (kit_obj_global_syms); this is a thin driver-side wrapper 308 * that adapts the old (blob, blob_size, names, count) shape and emits a 309 * driver_errf on allocation failure. The libkit block carries its own free 310 * size, so blob_size is no longer load-bearing — it is reported as 0 and the 311 * matching _free routes through kit_obj_global_syms_free. 312 * ---------------------------------------------------------------------- */ 313 314 int driver_collect_obj_global_syms(DriverEnv* env, const KitContext* ctx, 315 const char* tool, const KitSlice* member, 316 void** blob_out, size_t* blob_size_out, 317 const KitSlice** names_out, 318 uint32_t* count_out) { 319 KitArMemberSymbols syms = {NULL, 0}; 320 void* owned = NULL; 321 (void)env; 322 323 *blob_out = NULL; 324 *blob_size_out = 0; 325 *names_out = NULL; 326 *count_out = 0; 327 328 if (kit_obj_global_syms(ctx, member, &syms, &owned) != KIT_OK) { 329 driver_errf(tool, "out of memory"); 330 return 1; 331 } 332 *blob_out = owned; 333 *names_out = syms.names; 334 *count_out = syms.count; 335 return 0; 336 } 337 338 void driver_collect_obj_global_syms_free(DriverEnv* env, void* blob, 339 size_t blob_size) { 340 KitContext ctx = driver_env_to_context(env); 341 (void)blob_size; 342 if (blob) kit_obj_global_syms_free(&ctx, blob); 343 }