# Multicall binary

A *multicall binary* is a single compiled executable that contains many subprograms (often called *applets*) and decides at runtime which one to run by looking at `argv[0]` — the name the binary was invoked under. Symlinks (or hardlinks) point each Unix tool name (`ls`, `wget`, `cp`, `sh`, ...) at the same executable; when one of them is exec'd, the binary reads its own name and dispatches.

The canonical implementation is [BusyBox](https://busybox.net/) — see [[specular-what-is-busybox]] for a walk-through of the dispatch code. Toybox, sbase, [[toolbox/oh-my-pi|Pi]]-style consolidated CLIs, and quite a few research kernels' userlands use the same trick.

## The mechanism

The startup path inside BusyBox is roughly:

```c
applet_name = argv[0];
if (applet_name[0] == '-')         // login shells: argv[0] starts with -
  applet_name++;
applet_name = bb_basename(applet_name);

int applet = find_applet_by_name(name);
run_applet_no_and_exit(applet, name, argv);
// internally:
xfunc_error_retval = applet_main[applet_no](argc, argv);
```

Each applet has its own `main`-shaped function (`wget_main`, `ls_main`, ...) and gets dispatched as if it were the program entry point. From the user's perspective, `wget URL` and `busybox wget URL` are equivalent — the multicall just defaults the applet name to `argv[0]` and falls back to `argv[1]` when invoked as the umbrella binary.

`busybox --install -s` populates a directory with one symlink per applet (the `-s` flag chooses symlinks; hard links are also supported). `busybox --list` enumerates the compiled-in applets.

Each applet file also carries Kconfig-style metadata in C comments:

```c
//config:config WGET
//config:    bool "wget (41 kb)"
//config:    default y
//config:    help wget is a utility for non-interactive download ...
//applet:IF_WGET(APPLET(wget, BB_DIR_USR_BIN, BB_SUID_DROP))
//kbuild:lib-$(CONFIG_WGET) += wget.o
```

A build-time scan turns those into Kconfig entries, so a downstream distribution (Alpine, OpenWrt, Buildroot) can pick the applets it wants and compile only those into its BusyBox binary.

## Why it exists

Three benefits that compound:

- **Disk size.** One binary, many symlinks. Each applet shares the runtime (libc init, string handling, getopt, etc.), so the marginal cost of an applet is small. Alpine ships ~130 BusyBox applets under `/usr/bin` as symlinks to a single ~1 MB binary.
- **Memory and startup.** Multicall binaries can be page-cached once and reused for every applet exec, instead of touching dozens of different ELF files.
- **Build-time selection.** Including or excluding an applet is a config flag, not a separate package. Embedded distros can ship exactly the toolchain they need.

The trade-off Alpine users notice in [[specular-what-is-busybox|Specular's post]] is that the BusyBox applets are *not* the full coreutils binaries — many flags, locales, regex dialects, and corner-case behaviours are intentionally stripped down. `awk` works; some POSIX edge cases differ. `wget` works; the option surface is smaller than GNU wget. For most container workloads this is invisible. For a script ported from a Debian box, it's the source of occasional confusion.

## Where it fits

- Distinct from a *batteries-included monorepo CLI* like git or `cargo` or `gh` — those are single binaries with subcommands as arguments (`git commit`, not `commit`), not symlinks pretending to be standalone tools. The multicall pattern requires symlinks because each applet has to be reachable as its *original* Unix name.
- The closest parallel in the wiki is the cc-mirror approach to [[claude-code|Claude Code]] variants — one underlying installation, many top-level command names invoking it under different configurations. The dispatch mechanism is different (wrapper script vs. argv[0]), but the *user model* is identical: one program, many command names, each "presets" the runtime behaviour.
- Compare to [[fil-c]] and [[retrofitting-jit-c-interpreters]] for the broader theme of *reuse the substrate, vary the entry point* — single mechanism, many user-facing surfaces.

## Operational notes

- Symlink the binary as the *applet name*, not as a generic alias. The dispatch reads `argv[0]`, so `ln -s busybox foo` and invoking `foo` calls `find_applet_by_name("foo")` — which returns "applet not found" unless `foo` is a real BusyBox applet name.
- Login shells get `argv[0]` prefixed with `-` (e.g. `-bash`); the dispatch code handles that with the `if (applet_name[0] == '-')` strip.
- `busybox <applet> args...` is always available as an alternative invocation form, useful when the symlinks aren't in place.

## Implementations to be aware of

- **BusyBox** — GPL-2, ~300+ applets, the de facto Alpine / OpenWrt / Buildroot tool.
- **Toybox** — 0BSD-licensed, smaller scope, used in Android since ~2015.
- **sbase + ubase** (suckless) — applets as standalone binaries by default, also buildable as a single multicall.
- **GNU coreutils** — *not* a multicall binary; each utility is its own ELF. The disk-size case for multicall is what GNU coreutils gives up.
