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); }