kit

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

target.c (16113B)


      1 #include <stddef.h>
      2 #include <stdint.h>
      3 #include <stdio.h>
      4 #include <string.h>
      5 
      6 #include <kit/target.h>
      7 
      8 #include "driver.h"
      9 
     10 /* Target-triple parsing and the spec-derived target defaults now live in the
     11  * public libkit API (<kit/target.h>, src/api/target.c). The functions below are
     12  * thin driver-side wrappers that preserve the historical driver_* signatures
     13  * (and the driver's int-status / diagnostic conventions) so every CLI caller is
     14  * unaffected. The CLI feature-parsing policy (-march / -mattr / -mcpu / -m<feat>
     15  * → DriverTargetFeatures) stays here, since it consumes argv and emits
     16  * diagnostics. */
     17 
     18 int driver_arch_from_name(const char* name, KitArchKind* arch_out,
     19                           uint8_t* ptr_size_out) {
     20   return kit_arch_from_name(name, arch_out, ptr_size_out) ? 0 : 1;
     21 }
     22 
     23 void driver_err_unknown_target(const char* tool, const char* value) {
     24   const KitTargetProfile* profiles;
     25   const char* candidates[64];
     26   DriverSuggestion suggestions[3];
     27   size_t count = 0, candidate_count = 0, i, nsuggestions;
     28   profiles = kit_target_profiles(&count);
     29   for (i = 0; i < count && candidate_count < 64; ++i)
     30     candidates[candidate_count++] = profiles[i].triple;
     31   for (i = 0; i < count && candidate_count < 64; ++i)
     32     candidates[candidate_count++] = profiles[i].selector;
     33   nsuggestions = driver_suggest_values(value, candidates, candidate_count,
     34                                        suggestions, 3);
     35   if (nsuggestions)
     36     driver_errf(tool, "unrecognized target: %s; did you mean '%s'?", value,
     37                 suggestions[0].value);
     38   else
     39     driver_errf(tool, "unrecognized target: %s; run `kit targets` to list "
     40                       "supported profiles",
     41                 value);
     42 }
     43 
     44 KitPic driver_default_pic(KitObjFmt obj, KitOSKind os) {
     45   return kit_target_default_pic(obj, os);
     46 }
     47 
     48 int driver_link_pie(KitTargetSpec target, int explicit_pie, int shared,
     49                     int relocatable) {
     50   return kit_target_link_pie(target, explicit_pie, shared, relocatable);
     51 }
     52 
     53 const char* driver_default_exe_name(KitTargetSpec target) {
     54   return kit_target_default_exe_name(target);
     55 }
     56 
     57 void driver_default_obj_ext(KitTargetSpec target, const char** ext_out,
     58                             size_t* ext_len_out) {
     59   kit_target_default_obj_ext(target, ext_out, ext_len_out);
     60 }
     61 
     62 int driver_target_needs_sysroot_libdir(KitTargetSpec target) {
     63   return kit_target_needs_sysroot_libdir(target);
     64 }
     65 
     66 int driver_target_default_hosted_profile(KitTargetSpec target) {
     67   return kit_target_default_hosted_profile(target);
     68 }
     69 
     70 int driver_target_shared_uses_hosted(KitTargetSpec target) {
     71   /* Whether a `-shared` link still needs the hosted CRT/libc is an OS policy
     72    * (Android bionic does; ELF/Mach-O/COFF hosts otherwise do not). Read it from
     73    * the OS hosted-ops vtable rather than hardcoding the identity here. The obj
     74    * gate guards against a triple that names an OS but a mismatched object
     75    * format. Note: no arch coupling -- Android shared libs need the hosted CRT on
     76    * every arch (only aarch64 is built today, so behavior is preserved). */
     77   const KitOsImpl* o = kit_os_lookup(target.os);
     78   return o && o->hosted && o->hosted->obj == target.obj &&
     79          o->hosted->shared_uses_hosted;
     80 }
     81 
     82 static int target_features_grow(DriverTargetFeatures* tf) {
     83   DriverEnv* env = tf->env;
     84   uint32_t old_cap = tf->cap_features;
     85   uint32_t new_cap = old_cap ? old_cap * 2u : 8u;
     86   size_t old_sz = (size_t)old_cap * sizeof(*tf->features);
     87   size_t new_sz = (size_t)new_cap * sizeof(*tf->features);
     88   void* p = env->heap->realloc(env->heap, tf->features, old_sz, new_sz,
     89                                _Alignof(KitTargetFeature));
     90   if (!p) return 1;
     91   tf->features = (KitTargetFeature*)p;
     92   memset(tf->features + old_cap, 0, new_sz - old_sz);
     93   tf->cap_features = new_cap;
     94   return 0;
     95 }
     96 
     97 int driver_target_features_init(DriverTargetFeatures* tf, DriverEnv* env,
     98                                 int argc_bound) {
     99   size_t bound = argc_bound > 0 ? (size_t)argc_bound + 8u : 8u;
    100   if (!tf || !env || !env->heap) return 1;
    101   memset(tf, 0, sizeof(*tf));
    102   tf->env = env;
    103   tf->cap_features = (uint32_t)bound;
    104   tf->features = driver_alloc_zeroed(env, bound * sizeof(*tf->features));
    105   if (!tf->features) return 1;
    106   return 0;
    107 }
    108 
    109 void driver_target_features_fini(DriverTargetFeatures* tf, DriverEnv* env) {
    110   if (!tf || !env) return;
    111   driver_free(env, tf->features,
    112               (size_t)tf->cap_features * sizeof(*tf->features));
    113   memset(tf, 0, sizeof(*tf));
    114 }
    115 
    116 static int target_features_record_feature(DriverTargetFeatures* tf,
    117                                           DriverEnv* env, KitSlice name,
    118                                           int enabled) {
    119   KitTargetFeature* f;
    120   (void)env;
    121   if (!name.s || name.len == 0) return 1;
    122   if (tf->nfeatures >= tf->cap_features && target_features_grow(tf) != 0)
    123     return 1;
    124   f = &tf->features[tf->nfeatures++];
    125   f->name = name;
    126   f->enabled = enabled ? true : false;
    127   return 0;
    128 }
    129 
    130 static const char* target_features_pull_value(const char* tool, int argc,
    131                                               char** argv, int* i,
    132                                               size_t prefix_len,
    133                                               const char* flag_label) {
    134   const char* a = argv[*i];
    135   if (a[prefix_len]) return a + prefix_len;
    136   if (++(*i) >= argc) {
    137     driver_errf(tool, "%.*s requires an argument",
    138                 KIT_SLICE_ARG(kit_slice_cstr(flag_label)));
    139     return NULL;
    140   }
    141   return argv[*i];
    142 }
    143 
    144 static int target_features_parse_mattr(DriverTargetFeatures* tf, DriverEnv* env,
    145                                        const char* tool, const char* list) {
    146   const char* p = list;
    147   if (!p || !*p) {
    148     driver_errf(tool, "-mattr= requires a comma-separated feature list");
    149     return 1;
    150   }
    151   while (*p) {
    152     int enabled;
    153     const char* start;
    154     if (*p == '+') {
    155       enabled = 1;
    156     } else if (*p == '-') {
    157       enabled = 0;
    158     } else {
    159       driver_errf(tool, "-mattr entries must start with '+' or '-': %.*s",
    160                   KIT_SLICE_ARG(kit_slice_cstr(p)));
    161       return 1;
    162     }
    163     ++p;
    164     start = p;
    165     while (*p && *p != ',') ++p;
    166     if (p == start) {
    167       driver_errf(tool, "empty -mattr feature");
    168       return 1;
    169     }
    170     if (target_features_record_feature(
    171             tf, env, (KitSlice){.s = start, .len = (size_t)(p - start)},
    172             enabled) != 0) {
    173       driver_errf(tool, "out of memory");
    174       return 1;
    175     }
    176     if (*p == ',') ++p;
    177   }
    178   return 0;
    179 }
    180 
    181 /* Map an ARM -mfpu= name onto the backend's VFP target features. `none` records
    182  * nothing (soft-float). `fpv4-sp-d16` (Cortex-M4F) records `vfp`; `fpv5-d16` /
    183  * `fpv5-sp-d16` (Cortex-M7) record `vfp`+`fpv5`. An unknown name is an error.
    184  * The recorded features flow through opts->features[] into kit_target_new, where
    185  * resolve_float_abi requires them for -mfloat-abi=hard/softfp and the
    186  * feature_predefines hook keys __ARM_FP/__ARM_FPV5__ on them. */
    187 static int target_features_record_mfpu(DriverTargetFeatures* tf, DriverEnv* env,
    188                                        const char* tool, const char* fpu) {
    189   if (driver_streq(fpu, "none")) return 0;
    190   if (driver_streq(fpu, "fpv4-sp-d16")) {
    191     return target_features_record_feature(tf, env, KIT_SLICE_LIT("vfp"), 1) == 0
    192                ? 0
    193                : 1;
    194   }
    195   if (driver_streq(fpu, "fpv5-d16") || driver_streq(fpu, "fpv5-sp-d16")) {
    196     if (target_features_record_feature(tf, env, KIT_SLICE_LIT("vfp"), 1) != 0)
    197       return 1;
    198     return target_features_record_feature(tf, env, KIT_SLICE_LIT("fpv5"), 1) == 0
    199                ? 0
    200                : 1;
    201   }
    202   driver_errf(tool, "-mfpu=%s is unsupported (none, fpv4-sp-d16, fpv5-d16, "
    203                     "fpv5-sp-d16)",
    204               fpu);
    205   return 1;
    206 }
    207 
    208 int driver_target_features_try_consume(DriverTargetFeatures* tf, DriverEnv* env,
    209                                        const char* tool, int argc, char** argv,
    210                                        int* i) {
    211   const char* a = argv[*i];
    212   const char* v;
    213   if (!tf || !a) return 0;
    214 
    215   if (driver_strneq(a, "-mattr=", 7)) {
    216     return target_features_parse_mattr(tf, env, tool, a + 7) == 0 ? 1 : -1;
    217   }
    218   if (driver_streq(a, "-mattr")) {
    219     if (++(*i) >= argc) {
    220       driver_errf(tool, "-mattr requires an argument");
    221       return -1;
    222     }
    223     return target_features_parse_mattr(tf, env, tool, argv[*i]) == 0 ? 1 : -1;
    224   }
    225   if (driver_strneq(a, "-mfeature=", 10) ||
    226       driver_strneq(a, "-mno-feature=", 13)) {
    227     return 0;
    228   }
    229   if (driver_strneq(a, "-march=", 7)) {
    230     tf->isa = kit_slice_cstr(a + 7);
    231     return 1;
    232   }
    233   if (driver_streq(a, "-march")) {
    234     if (++(*i) >= argc) {
    235       driver_errf(tool, "-march requires an argument");
    236       return -1;
    237     }
    238     tf->isa = kit_slice_cstr(argv[*i]);
    239     return 1;
    240   }
    241   if (driver_strneq(a, "-mabi=", 6)) {
    242     tf->abi = kit_slice_cstr(a + 6);
    243     return 1;
    244   }
    245   if (driver_streq(a, "-mabi")) {
    246     if (++(*i) >= argc) {
    247       driver_errf(tool, "-mabi requires an argument");
    248       return -1;
    249     }
    250     tf->abi = kit_slice_cstr(argv[*i]);
    251     return 1;
    252   }
    253   if (driver_strneq(a, "-mcpu=", 6)) {
    254     tf->cpu = kit_slice_cstr(a + 6);
    255     return 1;
    256   }
    257   if (driver_streq(a, "-mcpu")) {
    258     v = target_features_pull_value(tool, argc, argv, i, 5, "-mcpu");
    259     if (!v) return -1;
    260     tf->cpu = kit_slice_cstr(v);
    261     return 1;
    262   }
    263   if (driver_strneq(a, "-mtune=", 7)) {
    264     tf->tune = kit_slice_cstr(a + 7);
    265     return 1;
    266   }
    267   if (driver_streq(a, "-mtune")) {
    268     v = target_features_pull_value(tool, argc, argv, i, 6, "-mtune");
    269     if (!v) return -1;
    270     tf->tune = kit_slice_cstr(v);
    271     return 1;
    272   }
    273   /* -mfloat-abi / -mfpu: ARM float-ABI selection. v1 supports soft-float only
    274    * (FP via the AEABI helpers); the arch's resolve_float_abi pins float_abi to
    275    * SOFT. Consume the flag here so it does not fall through to the generic
    276    * -m<feature> recorder (which would reject "float-abi=soft" as an unknown
    277    * feature). hard/softfp are a follow-on. -mfpu records the VFP target
    278    * features so the FP-feature machinery (resolve_float_abi requiring vfp/fpv5,
    279    * the __ARM_FP/__ARM_FPV5__ macros) is exercisable at the kit_target_new
    280    * level, even though -mfloat-abi=hard/softfp is still rejected below. */
    281   if (driver_strneq(a, "-mfloat-abi=", 12)) {
    282     if (!driver_streq(a + 12, "soft")) {
    283       driver_errf(tool,
    284                   "-mfloat-abi=%s is unsupported (soft-float only; hard/softfp "
    285                   "are a follow-on)",
    286                   a + 12);
    287       return -1;
    288     }
    289     return 1;
    290   }
    291   if (driver_streq(a, "-mfloat-abi")) {
    292     v = target_features_pull_value(tool, argc, argv, i, 11, "-mfloat-abi");
    293     if (!v) return -1;
    294     if (!driver_streq(v, "soft")) {
    295       driver_errf(tool,
    296                   "-mfloat-abi %s is unsupported (soft-float only; hard/softfp "
    297                   "are a follow-on)",
    298                   v);
    299       return -1;
    300     }
    301     return 1;
    302   }
    303   if (driver_strneq(a, "-mfpu=", 6))
    304     return target_features_record_mfpu(tf, env, tool, a + 6) == 0 ? 1 : -1;
    305   if (driver_streq(a, "-mfpu")) {
    306     v = target_features_pull_value(tool, argc, argv, i, 5, "-mfpu");
    307     if (!v) return -1;
    308     return target_features_record_mfpu(tf, env, tool, v) == 0 ? 1 : -1;
    309   }
    310   if (driver_strneq(a, "-mno-", 5) && a[5] != '\0') {
    311     if (target_features_record_feature(tf, env, kit_slice_cstr(a + 5), 0) !=
    312         0) {
    313       driver_errf(tool, "out of memory");
    314       return -1;
    315     }
    316     return 1;
    317   }
    318   if (driver_strneq(a, "-m", 2) && a[2] != '\0') {
    319     if (target_features_record_feature(tf, env, kit_slice_cstr(a + 2), 1) !=
    320         0) {
    321       driver_errf(tool, "out of memory");
    322       return -1;
    323     }
    324     return 1;
    325   }
    326   return 0;
    327 }
    328 
    329 static int darwin_platform_set_arch(const char* tool, KitTargetSpec* target,
    330                                     const char* arch) {
    331   KitArchKind k;
    332   uint8_t ptr_size;
    333   if (!arch) {
    334     driver_errf(tool, "-arch requires an argument");
    335     return 1;
    336   }
    337   if (driver_streq(arch, "arm64e")) arch = "arm64";
    338   if (driver_arch_from_name(arch, &k, &ptr_size) != 0) {
    339     driver_errf(tool, "unsupported -arch value: %.*s",
    340                 KIT_SLICE_ARG(kit_slice_cstr(arch)));
    341     return 1;
    342   }
    343   target->arch = k;
    344   target->ptr_size = ptr_size;
    345   target->ptr_align = ptr_size;
    346   return 0;
    347 }
    348 
    349 static void darwin_platform_set_os(KitTargetSpec* target, const char* platform,
    350                                    int pic_explicit) {
    351   if (!platform) return;
    352   if (driver_streq(platform, "macos")) {
    353     target->os = KIT_OS_MACOS;
    354     target->obj = KIT_OBJ_MACHO;
    355   } else if (driver_streq(platform, "ios")) {
    356     target->os = KIT_OS_IOS;
    357     target->obj = KIT_OBJ_MACHO;
    358   } else if (driver_streq(platform, "ios-simulator") ||
    359              driver_streq(platform, "iossimulator")) {
    360     target->os = KIT_OS_IOS_SIMULATOR;
    361     target->obj = KIT_OBJ_MACHO;
    362   } else if (driver_streq(platform, "linux")) {
    363     target->os = KIT_OS_LINUX;
    364     target->obj = KIT_OBJ_ELF;
    365   } else {
    366     return;
    367   }
    368   if (!pic_explicit) target->pic = driver_default_pic(target->obj, target->os);
    369 }
    370 
    371 int driver_darwin_platform_try_consume(const char* tool, int argc, char** argv,
    372                                        int* i, KitTargetSpec* target,
    373                                        int pic_explicit) {
    374   const char* a;
    375   if (!argv || !i || !target || *i < 0 || *i >= argc) return 0;
    376   a = argv[*i];
    377   if (driver_streq(a, "-arch")) {
    378     if (++(*i) >= argc) {
    379       driver_errf(tool, "-arch requires an argument");
    380       return -1;
    381     }
    382     return darwin_platform_set_arch(tool, target, argv[*i]) == 0 ? 1 : -1;
    383   }
    384   if (driver_streq(a, "-platform_version")) {
    385     if (*i + 3 >= argc) {
    386       driver_errf(tool, "-platform_version requires three arguments");
    387       return -1;
    388     }
    389     darwin_platform_set_os(target, argv[*i + 1], pic_explicit);
    390     *i += 3;
    391     return 1;
    392   }
    393   if (driver_streq(a, "-macosx_version_min")) {
    394     if (++(*i) >= argc) {
    395       driver_errf(tool, "-macosx_version_min requires an argument");
    396       return -1;
    397     }
    398     darwin_platform_set_os(target, "macos", pic_explicit);
    399     return 1;
    400   }
    401   if (driver_streq(a, "-ios_version_min") ||
    402       driver_streq(a, "-iphoneos_version_min")) {
    403     if (++(*i) >= argc) {
    404       driver_errf(tool, "%s requires an argument", a);
    405       return -1;
    406     }
    407     darwin_platform_set_os(target, "ios", pic_explicit);
    408     return 1;
    409   }
    410   if (driver_streq(a, "-ios_simulator_version_min") ||
    411       driver_streq(a, "-iphonesimulator_version_min")) {
    412     if (++(*i) >= argc) {
    413       driver_errf(tool, "%s requires an argument", a);
    414       return -1;
    415     }
    416     darwin_platform_set_os(target, "ios-simulator", pic_explicit);
    417     return 1;
    418   }
    419   return 0;
    420 }
    421 
    422 int driver_target_options(const DriverTargetFeatures* tf, const char* tool,
    423                           KitTargetSpec target, KitTargetOptions* out) {
    424   (void)tool;
    425   if (!out) return 1;
    426   memset(out, 0, sizeof(*out));
    427   out->spec = target;
    428   if (!tf) return 0;
    429   out->isa = tf->isa;
    430   out->cpu = tf->cpu;
    431   out->tune = tf->tune;
    432   out->abi = tf->abi;
    433   out->features = tf->features;
    434   out->nfeatures = tf->nfeatures;
    435   return 0;
    436 }
    437 
    438 KitStatus driver_target_new(const KitContext* ctx, KitTargetSpec target,
    439                             const DriverTargetFeatures* tf, const char* tool,
    440                             KitTarget** out) {
    441   KitTargetOptions opts;
    442   if (driver_target_options(tf, tool, target, &opts) != 0) {
    443     if (out) *out = NULL;
    444     return KIT_INVALID;
    445   }
    446   return kit_target_new(ctx, &opts, out);
    447 }
    448 
    449 int driver_target_from_triple(const char* triple, KitTargetSpec* out) {
    450   return kit_target_from_triple(triple, out) ? 0 : 1;
    451 }
    452 
    453 int driver_target_to_triple(KitTargetSpec target, char* buf, size_t cap) {
    454   return kit_target_to_triple(target, buf, cap) ? 0 : 1;
    455 }
    456 
    457 int driver_record_mcmodel(KitTargetSpec* target, const char* tool,
    458                           const char* val) {
    459   KitCodeModel cm;
    460   if (!kit_target_code_model_from_name(val, &cm)) {
    461     driver_errf(tool, "unknown -mcmodel value: %.*s",
    462                 KIT_SLICE_ARG(kit_slice_cstr(val)));
    463     return 1;
    464   }
    465   if (target) target->code_model = cm;
    466   return 0;
    467 }