kit

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

main.c (10949B)


      1 #include <kit/config.h>
      2 
      3 #include "driver.h"
      4 
      5 /* Multi-call dispatch. Looks at argv[0]'s basename for a tool name; if argv[0]
      6  * is the bare "kit" binary, falls back to argv[1].
      7  *
      8  * Tool availability is centralized here. The Makefile uses the same
      9  * KIT_TOOL_*_ENABLED flags to drop driver/<tool>.c objects, so disabled
     10  * tools do not need #if checks scattered through each tool implementation.
     11  */
     12 
     13 typedef int (*DriverToolMain)(int argc, char** argv);
     14 typedef void (*DriverToolHelp)(void);
     15 
     16 typedef struct DriverToolDesc {
     17   const char* name;
     18   DriverToolMain main;
     19   DriverToolHelp help;
     20   const char* summary;
     21   /* DriverToolGroup bits; 0 => not in the default install set */
     22   unsigned groups;
     23 } DriverToolDesc;
     24 
     25 static const DriverToolDesc driver_tools[] = {
     26 #if KIT_TOOL_CC_ENABLED
     27     {"cc", driver_cc, driver_help_cc,
     28      "Compile (and link) C sources, with cpp / dep-emit / -shared modes",
     29      DRIVER_GROUP_TOOLCHAIN},
     30 #endif
     31 #if KIT_TOOL_CHECK_ENABLED
     32     {"check", driver_check, driver_help_check,
     33      "Run C frontend checks without emitting code", DRIVER_GROUP_OTHER},
     34 #endif
     35 #if KIT_TOOL_BUILD_EXE_ENABLED
     36     {"build-exe", driver_build_exe, driver_help_build_exe,
     37      "Compile a polyglot source set and link an executable (in memory)",
     38      DRIVER_GROUP_TOOLCHAIN},
     39 #endif
     40 #if KIT_TOOL_BUILD_LIB_ENABLED
     41     {"build-lib", driver_build_lib, driver_help_build_lib,
     42      "Compile sources into a static .a or shared library (in memory)",
     43      DRIVER_GROUP_TOOLCHAIN},
     44 #endif
     45 #if KIT_TOOL_BUILD_OBJ_ENABLED
     46     {"build-obj", driver_build_obj, driver_help_build_obj,
     47      "Compile sources to an object / asm / C / IR, or check (replaces compile)",
     48      DRIVER_GROUP_TOOLCHAIN},
     49 #endif
     50 #if KIT_TOOL_INSTALL_ENABLED
     51     {"install", driver_install, driver_help_install,
     52      "Symlink the kit tools into a dir for drop-in toolchain use",
     53      DRIVER_GROUP_OTHER},
     54 #endif
     55 #if KIT_TOOL_CPP_ENABLED
     56     {"cpp", driver_cpp, driver_help_cpp,
     57      "Standalone C preprocessor (alias for `cc -E` minus link scaffold)",
     58      DRIVER_GROUP_TOOLCHAIN},
     59 #endif
     60 #if KIT_TOOL_AS_ENABLED
     61     {"as", driver_as, driver_help_as,
     62      "Assemble a GAS-subset text source into a relocatable object",
     63      DRIVER_GROUP_TOOLCHAIN},
     64 #endif
     65 #if KIT_TOOL_LD_ENABLED
     66     {"ld", driver_ld, driver_help_ld,
     67      "Link objects/archives into an executable or shared library",
     68      DRIVER_GROUP_TOOLCHAIN},
     69 #endif
     70 #if KIT_TOOL_AR_ENABLED
     71     {"ar", driver_ar, driver_help_ar,
     72      "Create / modify / list / extract POSIX `ar` archives",
     73      DRIVER_GROUP_TOOLCHAIN},
     74 #endif
     75 #if KIT_TOOL_RANLIB_ENABLED
     76     {"ranlib", driver_ranlib, driver_help_ranlib,
     77      "Refresh the symbol index of an `ar` archive", DRIVER_GROUP_TOOLCHAIN},
     78 #endif
     79 #if KIT_TOOL_STRIP_ENABLED
     80     {"strip", driver_strip, driver_help_strip,
     81      "Drop debug sections and/or symbols from a .o or .a",
     82      DRIVER_GROUP_TOOLCHAIN},
     83 #endif
     84 #if KIT_TOOL_OBJCOPY_ENABLED
     85     {"objcopy", driver_objcopy, driver_help_objcopy,
     86      "Copy and transform an object file (rename / remove / format)",
     87      DRIVER_GROUP_TOOLCHAIN},
     88 #endif
     89 #if KIT_TOOL_OBJDUMP_ENABLED
     90     {"objdump", driver_objdump, driver_help_objdump,
     91      "Dump sections, symbols, disassembly, hex, and relocations",
     92      DRIVER_GROUP_TOOLCHAIN},
     93 #endif
     94 #if KIT_TOOL_RUN_ENABLED
     95     {"run", driver_run, driver_help_run,
     96      "JIT-compile inputs and invoke the entry symbol in-process",
     97      DRIVER_GROUP_OTHER},
     98 #endif
     99 #if KIT_TOOL_DBG_ENABLED
    100     {"dbg", driver_dbg, driver_help_dbg,
    101      "Interactive JIT debugger (REPL on top of the JIT image)",
    102      DRIVER_GROUP_OTHER},
    103 #endif
    104 #if KIT_TOOL_EMU_ENABLED
    105     {"emu", driver_emu, driver_help_emu,
    106      "Run a guest user-mode ELF (aarch64/riscv64) on the host",
    107      DRIVER_GROUP_OTHER},
    108 #endif
    109 #if KIT_TOOL_NM_ENABLED
    110     {"nm", driver_nm, driver_help_nm, "List symbols from object files",
    111      DRIVER_GROUP_TOOLCHAIN},
    112 #endif
    113 #if KIT_TOOL_SIZE_ENABLED
    114     {"size", driver_size, driver_help_size,
    115      "Display section sizes of object files", DRIVER_GROUP_TOOLCHAIN},
    116 #endif
    117 #if KIT_TOOL_ADDR2LINE_ENABLED
    118     {"addr2line", driver_addr2line, driver_help_addr2line,
    119      "Translate addresses to file:line using debug info",
    120      DRIVER_GROUP_TOOLCHAIN},
    121 #endif
    122 #if KIT_TOOL_SYMBOLIZE_ENABLED
    123     {"symbolize", driver_symbolize, driver_help_symbolize,
    124      "Annotate a kit backtrace stream with func at file:line",
    125      DRIVER_GROUP_OTHER},
    126 #endif
    127 #if KIT_TOOL_STRINGS_ENABLED
    128     {"strings", driver_strings, driver_help_strings,
    129      "Print printable character sequences found in a file",
    130      DRIVER_GROUP_TOOLCHAIN},
    131 #endif
    132 #if KIT_TOOL_CAS_ENABLED
    133     {"cas", driver_cas, driver_help_cas,
    134      "Store, inspect, verify, and materialize kit CAS blobs and trees",
    135      DRIVER_GROUP_OTHER},
    136 #endif
    137 #if KIT_TOOL_PKG_ENABLED
    138     {"pkg", driver_pkg, driver_help_pkg,
    139      "Bundle, sign, verify, and unpack distributable .kpkg packages",
    140      DRIVER_GROUP_OTHER},
    141 #endif
    142 #if KIT_TOOL_XXD_ENABLED
    143     {"xxd", driver_xxd, driver_help_xxd,
    144      "Hex dump any file (and reverse a dump back to binary)",
    145      DRIVER_GROUP_BYTEUTIL},
    146 #endif
    147 #if KIT_TOOL_CMP_ENABLED
    148     {"cmp", driver_cmp, driver_help_cmp, "Compare two files byte by byte",
    149      DRIVER_GROUP_BYTEUTIL},
    150 #endif
    151 #if KIT_TOOL_HASH_ENABLED
    152     {"hash", driver_hash, driver_help_hash,
    153      "Hash files with SHA-256, BLAKE2b, or CRC-32", DRIVER_GROUP_OTHER},
    154     {"sha256sum", driver_sha256sum, driver_help_hash,
    155      "SHA-256 of files or stdin (sha256sum-compatible)", DRIVER_GROUP_BYTEUTIL},
    156     {"b2sum", driver_b2sum, driver_help_hash,
    157      "BLAKE2b-256 of files or stdin (b2sum-style)", DRIVER_GROUP_BYTEUTIL},
    158     {"crc32", driver_crc32, driver_help_hash, "CRC-32 of files or stdin",
    159      DRIVER_GROUP_BYTEUTIL},
    160 #endif
    161 #if KIT_TOOL_COMPRESS_ENABLED
    162     {"compress", driver_compress, driver_help_compress,
    163      "Compress or decompress data (gzip, lz4 frame)", DRIVER_GROUP_OTHER},
    164     {"gzip", driver_gzip, driver_help_compress,
    165      "Compress to gzip (.gz); -d to decompress", DRIVER_GROUP_BYTEUTIL},
    166     {"gunzip", driver_gunzip, driver_help_compress,
    167      "Decompress gzip (.gz) streams", DRIVER_GROUP_BYTEUTIL},
    168     {"lz4", driver_lz4, driver_help_compress,
    169      "Compress to LZ4 frame (.lz4); -d to decompress", DRIVER_GROUP_BYTEUTIL},
    170     {"lz4c", driver_lz4c, driver_help_compress,
    171      "Compress to LZ4 frame (.lz4) (lz4 alias)", DRIVER_GROUP_BYTEUTIL},
    172 #endif
    173 #if KIT_TOOL_DISAS_ENABLED
    174     {"disas", driver_disas, driver_help_disas,
    175      "Disassemble raw machine-code bytes for a target arch",
    176      DRIVER_GROUP_OTHER},
    177 #endif
    178 #if KIT_TOOL_MC_ENABLED
    179     {"mc", driver_mc, driver_help_mc,
    180      "Assemble one instruction and show its machine-code encoding",
    181      DRIVER_GROUP_OTHER},
    182 #endif
    183     {NULL, NULL, NULL, NULL, DRIVER_GROUP_OTHER},
    184 };
    185 
    186 unsigned driver_tool_count(void) {
    187   return (unsigned)(sizeof driver_tools / sizeof driver_tools[0]) - 1u;
    188 }
    189 
    190 const char* driver_tool_name(unsigned index) {
    191   if (index >= driver_tool_count()) return NULL;
    192   return driver_tools[index].name;
    193 }
    194 
    195 unsigned driver_tool_groups(unsigned index) {
    196   if (index >= driver_tool_count()) return 0u;
    197   return driver_tools[index].groups;
    198 }
    199 
    200 int driver_tool_find(const char* name) {
    201   unsigned i;
    202   if (!name) return -1;
    203   for (i = 0; i < driver_tool_count(); ++i) {
    204     if (driver_streq(name, driver_tools[i].name)) return (int)i;
    205   }
    206   return -1;
    207 }
    208 
    209 static const DriverToolDesc* find_tool(const char* name) {
    210   unsigned i;
    211   for (i = 0; i < driver_tool_count(); ++i) {
    212     if (driver_streq(name, driver_tools[i].name)) return &driver_tools[i];
    213   }
    214   return NULL;
    215 }
    216 
    217 static int dispatch(const char* name, int argc, char** argv) {
    218   const DriverToolDesc* tool = find_tool(name);
    219   if (tool) return tool->main(argc, argv);
    220   return -1;
    221 }
    222 
    223 /* If `name` matches a tool, print its help and return 0. Otherwise return
    224  * non-zero (caller reports the error). */
    225 static int print_tool_help(const char* name) {
    226   const DriverToolDesc* tool = find_tool(name);
    227   if (tool) {
    228     tool->help();
    229     return 0;
    230   }
    231   return -1;
    232 }
    233 
    234 int driver_is_help_flag(const char* arg) {
    235   if (!arg) return 0;
    236   return driver_streq(arg, "--help") || driver_streq(arg, "-help");
    237 }
    238 
    239 int driver_argv_wants_help(int argc, char** argv, int accept_short_h) {
    240   int i;
    241   for (i = 1; i < argc; ++i) {
    242     /* `--` ends the driver's own option scan: anything after it is
    243      * forwarded to the JITed program (run/dbg) or the guest (emu),
    244      * so a user's own `--help` to their program must not be hijacked. */
    245     if (driver_streq(argv[i], "--")) break;
    246     if (driver_is_help_flag(argv[i])) return 1;
    247     if (accept_short_h && driver_streq(argv[i], "-h")) return 1;
    248   }
    249   return 0;
    250 }
    251 
    252 void driver_help_top(void) {
    253   unsigned i;
    254   driver_printf(
    255       "kit — freestanding C compiler toolchain\n"
    256       "\n"
    257       "USAGE\n"
    258       "  kit <tool> [args...]            multi-call dispatch by name\n"
    259       "  <tool> [args...]                  when invoked via the tool's "
    260       "symlink\n"
    261       "  kit help [<tool>]               this help, or per-tool help\n"
    262       "\n"
    263       "TOOLS\n");
    264   for (i = 0; i < driver_tool_count(); ++i) {
    265     driver_printf("  %-9s %s\n", driver_tools[i].name, driver_tools[i].summary);
    266   }
    267   driver_printf(
    268       "\n"
    269       "GETTING HELP\n"
    270       "  kit <tool> --help               full per-tool help (also -h, except "
    271       "objdump)\n"
    272       "  kit <tool>                      same as --help (no args ⇒ show "
    273       "help)\n"
    274       "  kit help <tool>                 same as `kit <tool> --help`\n"
    275       "\n"
    276       "EXIT CODES\n"
    277       "  0   success\n"
    278       "  1   tool-reported error (compile, link, I/O, ...)\n"
    279       "  2   bad command-line usage\n");
    280 }
    281 
    282 int driver_main(int argc, char** argv) {
    283   const char* name;
    284   int rc;
    285 
    286   if (argc < 1) return 2;
    287   name = driver_basename(argv[0]);
    288 
    289   /* Multi-call form first: argv[0] is the tool name (e.g. installed as
    290    * a `cc` symlink). Help inside the tool is gated by the tool itself. */
    291   rc = dispatch(name, argc, argv);
    292   if (rc != -1) return rc;
    293 
    294   /* From here on argv[0] was the bare "kit" binary. Apply the
    295    * top-level help / `help <tool>` routing before delegating. */
    296   if (argc < 2) {
    297     driver_help_top();
    298     return 0;
    299   }
    300 
    301   if (driver_is_help_flag(argv[1]) || driver_streq(argv[1], "-h")) {
    302     driver_help_top();
    303     return 0;
    304   }
    305 
    306   if (driver_streq(argv[1], "help")) {
    307     if (argc < 3) {
    308       driver_help_top();
    309       return 0;
    310     }
    311     if (print_tool_help(argv[2]) == 0) return 0;
    312     driver_errf("kit", "no such tool: %.*s",
    313                 KIT_SLICE_ARG(kit_slice_cstr(argv[2])));
    314     return 2;
    315   }
    316 
    317   {
    318     char* tool_name = argv[1];
    319     argv[1] = argv[0];
    320     rc = dispatch(tool_name, argc - 1, argv + 1);
    321     argv[1] = tool_name;
    322     if (rc != -1) return rc;
    323   }
    324 
    325   driver_errf("kit", "no such tool: %.*s",
    326               KIT_SLICE_ARG(kit_slice_cstr(argv[1])));
    327   driver_help_top();
    328   return 2;
    329 }
    330 
    331 int main(int argc, char** argv) { return driver_main(argc, argv); }