kit

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

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 }