kit

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

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 }