kit

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

commit 6a316b3761492fae0efe911dc7473b16abcc10b6
parent 33c0793b31d1645ebd37017a6b3a22533c01b431
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Thu, 16 Jul 2026 11:07:37 -0700

Group tools in top-level help

Diffstat:
Mdriver/driver.h | 4++--
Mdriver/main.c | 158++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Mtest/audit/release/modules/help.sh | 2+-
Mtest/driver/help_uniform.sh | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 183 insertions(+), 53 deletions(-)

diff --git a/driver/driver.h b/driver/driver.h @@ -116,8 +116,8 @@ void driver_help_gram(void); void driver_help_targets(void); /* Multi-call top-level help (`kit`, `kit -h`, `kit --help`, - * `kit help`). Lists each tool with a one-line summary and explains - * the multi-call dispatch. Writes to stdout. */ + * `kit help`). Lists public tools in task-oriented groups with a one-line + * summary and explains the multi-call dispatch. Writes to stdout. */ void driver_help_top(void); /* ---------------------------------------------------------------------- diff --git a/driver/main.c b/driver/main.c @@ -15,12 +15,24 @@ typedef int (*DriverToolMainEx)(int argc, char** argv, const KitDriverExtension*); typedef void (*DriverToolHelp)(void); +typedef enum DriverHelpGroup { + DRIVER_HELP_BUILD, + DRIVER_HELP_BINARY, + DRIVER_HELP_EXECUTION, + DRIVER_HELP_DISTRIBUTION, + DRIVER_HELP_DATA, + DRIVER_HELP_KIT, + DRIVER_HELP_GROUP_COUNT, +} DriverHelpGroup; + typedef struct DriverToolDesc { const char* name; DriverToolMain main; DriverToolMainEx main_ex; DriverToolHelp help; const char* summary; + /* Task-oriented presentation category for the top-level help inventory. */ + DriverHelpGroup help_group; /* DriverToolGroup bits; 0 => not in the default install set */ unsigned groups; } DriverToolDesc; @@ -32,188 +44,202 @@ static const DriverToolDesc driver_tools[] = { #if KIT_TOOL_CC_ENABLED {"cc", driver_cc, NULL, driver_help_cc, "Compile (and link) C sources, with cpp / dep-emit / ELF -shared modes", - DRIVER_GROUP_TOOLCHAIN}, + DRIVER_HELP_BUILD, DRIVER_GROUP_TOOLCHAIN}, #endif #if KIT_TOOL_CHECK_ENABLED {"check", driver_check, NULL, driver_help_check, - "Run C frontend checks without emitting code", DRIVER_GROUP_OTHER}, + "Run C frontend checks without emitting code", DRIVER_HELP_BUILD, + DRIVER_GROUP_OTHER}, #endif #if KIT_TOOL_BUILD_EXE_ENABLED {"build-exe", driver_build_exe, driver_build_exe_ex, driver_help_build_exe, "Compile a polyglot source set and link an executable (in memory)", - DRIVER_GROUP_TOOLCHAIN}, + DRIVER_HELP_BUILD, DRIVER_GROUP_TOOLCHAIN}, #endif #if KIT_TOOL_BUILD_LIB_ENABLED {"build-lib", driver_build_lib, driver_build_lib_ex, driver_help_build_lib, "Compile sources into a static .a or ELF shared library (in memory)", - DRIVER_GROUP_TOOLCHAIN}, + DRIVER_HELP_BUILD, DRIVER_GROUP_TOOLCHAIN}, #endif #if KIT_TOOL_BUILD_OBJ_ENABLED {"build-obj", driver_build_obj, driver_build_obj_ex, driver_help_build_obj, "Compile sources to an object / asm / C / IR, or check (replaces compile)", - DRIVER_GROUP_TOOLCHAIN}, + DRIVER_HELP_BUILD, DRIVER_GROUP_TOOLCHAIN}, #endif #if KIT_TOOL_BUILD_ENABLED {"build", driver_build, NULL, driver_help_build, "Resolve a target with the content-addressed build coordinator", - DRIVER_GROUP_OTHER}, + DRIVER_HELP_BUILD, DRIVER_GROUP_OTHER}, #endif #if KIT_TOOL_INSTALL_ENABLED {"install", driver_install, NULL, driver_help_install, "Symlink the kit tools into a dir for drop-in toolchain use", - DRIVER_GROUP_OTHER}, + DRIVER_HELP_KIT, DRIVER_GROUP_OTHER}, #endif #if KIT_TOOL_CPP_ENABLED {"cpp", driver_cpp, NULL, driver_help_cpp, "Standalone C preprocessor (alias for `cc -E` minus link scaffold)", - DRIVER_GROUP_TOOLCHAIN}, + DRIVER_HELP_BUILD, DRIVER_GROUP_TOOLCHAIN}, #endif #if KIT_TOOL_AS_ENABLED {"as", driver_as, NULL, driver_help_as, "Assemble a GAS-subset text source into a relocatable object", - DRIVER_GROUP_TOOLCHAIN}, + DRIVER_HELP_BUILD, DRIVER_GROUP_TOOLCHAIN}, #endif #if KIT_TOOL_LD_ENABLED {"ld", driver_ld, NULL, driver_help_ld, "Link objects/archives into an executable or ELF shared library", - DRIVER_GROUP_TOOLCHAIN}, + DRIVER_HELP_BUILD, DRIVER_GROUP_TOOLCHAIN}, #endif #if KIT_TOOL_AR_ENABLED {"ar", driver_ar, NULL, driver_help_ar, - "Create / modify / list / extract POSIX `ar` archives", + "Create / modify / list / extract POSIX `ar` archives", DRIVER_HELP_BINARY, DRIVER_GROUP_TOOLCHAIN}, #endif #if KIT_TOOL_CPIO_ENABLED {"cpio", driver_cpio, NULL, driver_help_cpio, "Create / list / extract SVR4 newc cpio (initramfs) archives", - DRIVER_GROUP_TOOLCHAIN}, + DRIVER_HELP_BINARY, DRIVER_GROUP_TOOLCHAIN}, #endif #if KIT_TOOL_RANLIB_ENABLED {"ranlib", driver_ranlib, NULL, driver_help_ranlib, - "Refresh the symbol index of an `ar` archive", DRIVER_GROUP_TOOLCHAIN}, + "Refresh the symbol index of an `ar` archive", DRIVER_HELP_BINARY, + DRIVER_GROUP_TOOLCHAIN}, #endif #if KIT_TOOL_STRIP_ENABLED {"strip", driver_strip, NULL, driver_help_strip, - "Drop debug sections and/or symbols from a .o or .a", + "Drop debug sections and/or symbols from a .o or .a", DRIVER_HELP_BINARY, DRIVER_GROUP_TOOLCHAIN}, #endif #if KIT_TOOL_OBJCOPY_ENABLED {"objcopy", driver_objcopy, NULL, driver_help_objcopy, "Copy and transform an object file (rename / remove / format)", - DRIVER_GROUP_TOOLCHAIN}, + DRIVER_HELP_BINARY, DRIVER_GROUP_TOOLCHAIN}, #endif #if KIT_TOOL_IMAGE_ENABLED {"image", driver_image, NULL, driver_help_image, - "Emit flat kernel/load images from linked objects", DRIVER_GROUP_TOOLCHAIN}, + "Emit flat kernel/load images from linked objects", DRIVER_HELP_BINARY, + DRIVER_GROUP_TOOLCHAIN}, #endif #if KIT_TOOL_OBJDUMP_ENABLED {"objdump", driver_objdump, NULL, driver_help_objdump, "Dump sections, symbols, disassembly, hex, and relocations", - DRIVER_GROUP_TOOLCHAIN}, + DRIVER_HELP_BINARY, DRIVER_GROUP_TOOLCHAIN}, #endif #if KIT_TOOL_RUN_ENABLED {"run", driver_run, driver_run_ex, driver_help_run, "JIT-compile inputs and invoke the entry symbol in-process", - DRIVER_GROUP_OTHER}, + DRIVER_HELP_EXECUTION, DRIVER_GROUP_OTHER}, #endif #if KIT_TOOL_DBG_ENABLED {"dbg", driver_dbg, driver_dbg_ex, driver_help_dbg, "Interactive JIT debugger (REPL on top of the JIT image)", - DRIVER_GROUP_OTHER}, + DRIVER_HELP_EXECUTION, DRIVER_GROUP_OTHER}, #endif #if KIT_TOOL_EMU_ENABLED - {"emu", driver_emu, NULL, driver_help_emu, NULL, DRIVER_GROUP_OTHER}, + {"emu", driver_emu, NULL, driver_help_emu, NULL, DRIVER_HELP_EXECUTION, + DRIVER_GROUP_OTHER}, #endif #if KIT_TOOL_NM_ENABLED {"nm", driver_nm, NULL, driver_help_nm, "List symbols from object files", - DRIVER_GROUP_TOOLCHAIN}, + DRIVER_HELP_BINARY, DRIVER_GROUP_TOOLCHAIN}, #endif #if KIT_TOOL_SIZE_ENABLED {"size", driver_size, NULL, driver_help_size, - "Display section sizes of object files", DRIVER_GROUP_TOOLCHAIN}, + "Display section sizes of object files", DRIVER_HELP_BINARY, + DRIVER_GROUP_TOOLCHAIN}, #endif #if KIT_TOOL_ADDR2LINE_ENABLED {"addr2line", driver_addr2line, NULL, driver_help_addr2line, - "Translate addresses to file:line using debug info", + "Translate addresses to file:line using debug info", DRIVER_HELP_BINARY, DRIVER_GROUP_TOOLCHAIN}, #endif #if KIT_TOOL_SYMBOLIZE_ENABLED {"symbolize", driver_symbolize, NULL, driver_help_symbolize, "Annotate a kit backtrace stream with func at file:line", - DRIVER_GROUP_OTHER}, + DRIVER_HELP_BINARY, DRIVER_GROUP_OTHER}, #endif #if KIT_TOOL_STRINGS_ENABLED {"strings", driver_strings, NULL, driver_help_strings, - "Print printable character sequences found in a file", + "Print printable character sequences found in a file", DRIVER_HELP_BINARY, DRIVER_GROUP_TOOLCHAIN}, #endif #if KIT_TOOL_CAS_ENABLED {"cas", driver_cas, NULL, driver_help_cas, "Store, inspect, verify, and materialize kit CAS blobs and trees", - DRIVER_GROUP_OTHER}, + DRIVER_HELP_DISTRIBUTION, DRIVER_GROUP_OTHER}, #endif #if KIT_TOOL_PKG_ENABLED {"pkg", driver_pkg, NULL, driver_help_pkg, "Bundle, sign, verify, and unpack distributable .kpkg packages", - DRIVER_GROUP_OTHER}, + DRIVER_HELP_DISTRIBUTION, DRIVER_GROUP_OTHER}, #endif #if KIT_TOOL_XXD_ENABLED {"xxd", driver_xxd, NULL, driver_help_xxd, - "Hex dump any file (and reverse a dump back to binary)", + "Hex dump any file (and reverse a dump back to binary)", DRIVER_HELP_DATA, DRIVER_GROUP_BYTEUTIL}, #endif #if KIT_TOOL_CMP_ENABLED {"cmp", driver_cmp, NULL, driver_help_cmp, "Compare two files byte by byte", - DRIVER_GROUP_BYTEUTIL}, + DRIVER_HELP_DATA, DRIVER_GROUP_BYTEUTIL}, #endif #if KIT_TOOL_HASH_ENABLED {"hash", driver_hash, NULL, driver_help_hash, - "Hash files with SHA-256, BLAKE2b, or CRC-32", DRIVER_GROUP_OTHER}, + "Hash files with SHA-256, BLAKE2b, or CRC-32", DRIVER_HELP_DATA, + DRIVER_GROUP_OTHER}, {"sha256sum", driver_sha256sum, NULL, driver_help_sha256sum, - "SHA-256 of files or stdin (sha256sum-compatible)", DRIVER_GROUP_BYTEUTIL}, + "SHA-256 of files or stdin (sha256sum-compatible)", DRIVER_HELP_DATA, + DRIVER_GROUP_BYTEUTIL}, {"b2sum", driver_b2sum, NULL, driver_help_b2sum, - "BLAKE2b-256 of files or stdin (b2sum-style)", DRIVER_GROUP_BYTEUTIL}, - {"crc32", driver_crc32, NULL, driver_help_crc32, - "CRC-32 of files or stdin", DRIVER_GROUP_BYTEUTIL}, + "BLAKE2b-256 of files or stdin (b2sum-style)", DRIVER_HELP_DATA, + DRIVER_GROUP_BYTEUTIL}, + {"crc32", driver_crc32, NULL, driver_help_crc32, "CRC-32 of files or stdin", + DRIVER_HELP_DATA, DRIVER_GROUP_BYTEUTIL}, #endif #if KIT_TOOL_COMPRESS_ENABLED {"compress", driver_compress, NULL, driver_help_compress, - "Compress or decompress data (gzip, lz4 frame)", DRIVER_GROUP_OTHER}, + "Compress or decompress data (gzip, lz4 frame)", DRIVER_HELP_DATA, + DRIVER_GROUP_OTHER}, {"gzip", driver_gzip, NULL, driver_help_gzip, - "Compress to gzip (.gz); -d to decompress", DRIVER_GROUP_BYTEUTIL}, + "Compress to gzip (.gz); -d to decompress", DRIVER_HELP_DATA, + DRIVER_GROUP_BYTEUTIL}, {"gunzip", driver_gunzip, NULL, driver_help_gunzip, - "Decompress gzip (.gz) streams", DRIVER_GROUP_BYTEUTIL}, + "Decompress gzip (.gz) streams", DRIVER_HELP_DATA, DRIVER_GROUP_BYTEUTIL}, {"lz4", driver_lz4, NULL, driver_help_lz4, - "Compress to LZ4 frame (.lz4); -d to decompress", DRIVER_GROUP_BYTEUTIL}, + "Compress to LZ4 frame (.lz4); -d to decompress", DRIVER_HELP_DATA, + DRIVER_GROUP_BYTEUTIL}, {"lz4c", driver_lz4c, NULL, driver_help_lz4c, - "Compress to LZ4 frame (.lz4) (lz4 alias)", DRIVER_GROUP_BYTEUTIL}, + "Compress to LZ4 frame (.lz4) (lz4 alias)", DRIVER_HELP_DATA, + DRIVER_GROUP_BYTEUTIL}, #endif #if KIT_TOOL_DISAS_ENABLED {"disas", driver_disas, NULL, driver_help_disas, - "Disassemble raw machine-code bytes for a target arch", + "Disassemble raw machine-code bytes for a target arch", DRIVER_HELP_BINARY, DRIVER_GROUP_OTHER}, #endif #if KIT_TOOL_MC_ENABLED {"mc", driver_mc, NULL, driver_help_mc, "Assemble one instruction and show its machine-code encoding", - DRIVER_GROUP_OTHER}, + DRIVER_HELP_BINARY, DRIVER_GROUP_OTHER}, #endif #if KIT_TOOL_GRAM_ENABLED {"gram", driver_gram, NULL, driver_help_gram, - "Generate a C parser/lexer from an EBNF grammar", DRIVER_GROUP_OTHER}, + "Generate a C parser/lexer from an EBNF grammar", DRIVER_HELP_BUILD, + DRIVER_GROUP_OTHER}, #endif #if KIT_TOOL_TARGETS_ENABLED {"targets", driver_targets, NULL, driver_help_targets, - "List and inspect compiled target profiles", DRIVER_GROUP_OTHER}, + "List and inspect compiled target profiles", DRIVER_HELP_KIT, + DRIVER_GROUP_OTHER}, #endif {"version", driver_version_command, NULL, driver_help_version_command, - "Print canonical release/build/host identity", 0}, + "Print canonical release/build/host identity", DRIVER_HELP_KIT, 0}, #if KIT_TOOL_UPDATE_ENABLED {"update", driver_update, NULL, driver_help_update, "Verify and install a newer kit; manage installed versions", - DRIVER_GROUP_OTHER}, + DRIVER_HELP_KIT, DRIVER_GROUP_OTHER}, #endif - {NULL, NULL, NULL, NULL, NULL, DRIVER_GROUP_OTHER}, + {NULL, NULL, NULL, NULL, NULL, DRIVER_HELP_GROUP_COUNT, DRIVER_GROUP_OTHER}, }; unsigned driver_tool_count(void) { @@ -370,22 +396,54 @@ static int driver_version_command(int argc, char** argv) { return 0; } +static const char* driver_help_group_name(DriverHelpGroup group) { + switch (group) { + case DRIVER_HELP_BUILD: + return "Compilation and build"; + case DRIVER_HELP_BINARY: + return "Binary and object tools"; + case DRIVER_HELP_EXECUTION: + return "Execution and debugging"; + case DRIVER_HELP_DISTRIBUTION: + return "Distribution"; + case DRIVER_HELP_DATA: + return "Data utilities"; + case DRIVER_HELP_KIT: + return "Kit management"; + case DRIVER_HELP_GROUP_COUNT: + break; + } + return NULL; +} + void driver_help_top(void) { + unsigned group; unsigned i; driver_printf( "kit — standalone compilation, linking, execution, and binary toolkit\n" "\n" "USAGE\n" " kit <tool> [args...] multi-call dispatch by name\n" - " <tool> [args...] when invoked via the tool's " + " <tool> [args...] when invoked via the tool's " "symlink\n" " kit help [<tool>] this help, or per-tool help\n" " kit --version release/build/host identity\n" "\n" "TOOLS\n"); - for (i = 0; i < driver_tool_count(); ++i) { - if (!driver_tool_public(i)) continue; - driver_printf(" %-9s %s\n", driver_tools[i].name, driver_tools[i].summary); + for (group = 0; group < (unsigned)DRIVER_HELP_GROUP_COUNT; ++group) { + int heading_printed = 0; + for (i = 0; i < driver_tool_count(); ++i) { + if (!driver_tool_public(i) || + driver_tools[i].help_group != (DriverHelpGroup)group) + continue; + if (!heading_printed) { + driver_printf("\n %s\n", + driver_help_group_name((DriverHelpGroup)group)); + heading_printed = 1; + } + driver_printf(" %-9s %s\n", driver_tools[i].name, + driver_tools[i].summary); + } } driver_printf( "\n" diff --git a/test/audit/release/modules/help.sh b/test/audit/release/modules/help.sh @@ -143,7 +143,7 @@ audit_help_top() { audit_expect_stdout_regex '^TOOLS$' audit_expect_stderr_empty for audit_help_inventory_cmd in $audit_help_commands; do - audit_expect_stdout_regex "^ $audit_help_inventory_cmd[[:space:]]" + audit_expect_stdout_regex "^ $audit_help_inventory_cmd[[:space:]]" done audit_reject_stdout_regex 'no args.*show help' audit_case_finish diff --git a/test/driver/help_uniform.sh b/test/driver/help_uniform.sh @@ -20,6 +20,78 @@ KIT_KIT_DIR="$repo_root/test/lib" . "$repo_root/test/lib/kit_sh_kit.sh" kit_report_init +# The top-level inventory stays complete, but is split into task-oriented +# groups so a user can scan it without already knowing a tool's name. +"$KIT" --help > "$work/top.help" 2> "$work/top.help.err" +awk ' + $0 == "TOOLS" { in_tools = 1; next } + $0 == "GETTING HELP" { exit } + in_tools && /^ [^ ]/ { + group = $0 + sub(/^ /, "", group) + next + } + in_tools && /^ [^ ]/ { print group "|" $1 } +' "$work/top.help" > "$work/top.groups" +cat > "$work/top.groups.expected" <<'EOF' +Compilation and build|cc +Compilation and build|check +Compilation and build|build-exe +Compilation and build|build-lib +Compilation and build|build-obj +Compilation and build|build +Compilation and build|cpp +Compilation and build|as +Compilation and build|ld +Compilation and build|gram +Binary and object tools|ar +Binary and object tools|cpio +Binary and object tools|ranlib +Binary and object tools|strip +Binary and object tools|objcopy +Binary and object tools|image +Binary and object tools|objdump +Binary and object tools|nm +Binary and object tools|size +Binary and object tools|addr2line +Binary and object tools|symbolize +Binary and object tools|strings +Binary and object tools|disas +Binary and object tools|mc +Execution and debugging|run +Execution and debugging|dbg +Distribution|cas +Distribution|pkg +Data utilities|xxd +Data utilities|cmp +Data utilities|hash +Data utilities|sha256sum +Data utilities|b2sum +Data utilities|crc32 +Data utilities|compress +Data utilities|gzip +Data utilities|gunzip +Data utilities|lz4 +Data utilities|lz4c +Kit management|install +Kit management|targets +Kit management|version +Kit management|update +EOF +if cmp -s "$work/top.groups.expected" "$work/top.groups" && + [ ! -s "$work/top.help.err" ]; then + ok "top-help-groups" +else + { + printf '%s\n' 'expected groups:' + sed 's/^/ /' "$work/top.groups.expected" + printf '%s\n' 'actual groups:' + sed 's/^/ /' "$work/top.groups" + sed 's/^/stderr: /' "$work/top.help.err" + } > "$work/top.groups.diag" + not_ok "top-help-groups" "$work/top.groups.diag" +fi + help_shape() { tool=$1 out="$work/$tool.help"