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:
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"