Download the binary release package matching your hardware and OS; it holds one small binary and nothing else.
If you have Rust installed, clone the repo and install with
cargo install --path . --features full
or, without the source tree,
cargo install badc --features full
--features full is required for the command-line compiler. The crate’s
default feature set is the host-architecture JIT library alone; the badc
binary additionally needs the native object writers and the
cross-translation-unit linker, which full enables.
badc --jit hello.c # runs native code in-process
Hello 123
or
badc -O hello.c # produces an optimized native binary
./hello
Hello 123
The first non-flag argument is the source file. By default badc lowers it to a
native binary at the obvious path next to the source (hello.c -> hello on
POSIX targets, hello.exe on Windows targets); -o <path> chooses a different
one.
badc can add the standard-library header for you, so a bare hello.c with
int main() {
puts("Hello");
return 0;
}
works:
info: auto-including <stdio.h> for undeclared `puts`
info: wrote file hello for target `macos-aarch64`
| flag | what it does |
|---|---|
| (default) | Lower to a native Mach-O / ELF / PE32+ at -o <path> and exit. |
--jit |
Lower in-process, mmap the result, call main directly. |
--interp |
Run the SSA IR under a watchful VM (pointer tracking, traces). |
Flags (--target=<spec>, --optimize / -O, --dump-ssa, --list-symbols,
-H / --show-includes, plus the VM-only --track-pointers / --trace) can
appear anywhere before the source. -D NAME[=VALUE], -U NAME, -I path, and
-include FILE work the same way they do on gcc / clang, as does the -M
dependency-output family (-M, -MM, -MD, -MMD, -MF, -MT, -MQ,
-MP, and the -Wp,-M[M]D,<file> spellings a kbuild-style build passes).
badc --help prints the full set.
badc’s driver has no accept-and-ignore bucket: a dash-prefixed argument it does
not implement is an error rather than a warning. Source-driven build flags ride
on #pragmas instead – see
headers and bindings.
Every warning and error ends with its code and its name:
hello.c:4: warning: unused variable `x` [B2001] [-Wunused-variable]
hello.c:7: error: `)` expected after cast [B2020] [syntax]
-W<name>, -Wno-<name>, -Werror=<name> and -Wno-error=<name> select one
diagnostic by either spelling; -Wall, -Wextra, -Wpedantic, -Werror and
-w work as they do on gcc, and #pragma GCC diagnostic,
#pragma clang diagnostic and MSVC’s #pragma warning(...) apply from their
position. badc --explain <name> describes one row, badc --list-diagnostics
prints the catalogue; diagnostics is the same table.
-g emits DWARF, so the binary can be debugged and profiled:
badc -g hello.c
info: wrote file hello for target macos-aarch64
lldb ./hello
(lldb) target create "./hello"
Current executable set to 'hello' (arm64).
(lldb) b main
Breakpoint 1: where = hello`main + 16 at hello.c:5, address = 0x00000001000006fc
(lldb) run
Process 19800 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x00000001000006fc hello`main at hello.c:5
2 #include <stdlib.h>
3
4 int main() {
-> 5 int a = 123;
6 printf("Hello %d\n", a);
7 return 0;
8 }
(lldb) n
Process 19800 stopped
frame #0: 0x0000000100000704 hello`main at hello.c:6
-> 6 printf("Hello %d\n", a);
(lldb) v
(int) a = 123
For the SSA IR plus the register allocator’s per-value placement, pass
--dump-ssa; it prints to stderr before lowering.
A .c file may start with a shebang. With badc on PATH, chmod +x script.c
makes the file directly executable, and the shebang line picks the mode:
#!/usr/bin/env badc --interp for the VM, the bare form for native compilation.
The bundled headers and runtime are embedded in the binary. --install [<dir>]
writes them under <dir> (default $BADC_HOME, else ~/.badc). A build that
names the tree, with --badc-home=<dir> or $BADC_HOME, prefers the installed
copies, so editing an installed header or the runtime changes the build without
rebuilding badc. Only a named tree is read: ~/.badc and the directory the
executable sits in play no part, and --badc-home= with no directory withdraws
the variable, so what an image contains follows from the command line and the
environment alone. --dump-headers prints the embedded set to stdout instead.