Copyright (c) 2026 Muhammad Anisur Rahman. All rights reserved.
Version 1.0.0
kcpp compiles C and C++ to machine code for small targets, and comes with the whole chain around it: an assembler, a linker, a librarian, a disassembler and the tools that turn a linked image into something a board or a simulator can load.
The same binary also runs C as a script, without producing any object code at all - see icpp-manual.md.
kcpp -cpu32 hello.c # -> hello.asm, hello.o
miskasm hello.asm # assemble (and single-file link)
klink -o hello.kx hello.o # link
kdis hello.kx # read back what you built
kcpp [options] <sourcefile.c>
Output is written next to the source, not to a name you choose:
| File | Is |
|---|---|
<source>.asm | assembly for the target |
<source>.o | object file |
<source>.error | errors and warnings |
-o is an optimisation LEVEL, not an output name. -o0 is the default and -o1 reuses values already in registers; higher numbers clamp to -o1 with a warning, because nothing above it exists yet.
Register width and address width are independent, which is not a convenience - it is a real machine shape:
| Option | Means |
|---|---|
-cpu32 / -cpu64 | data register width. 64 is the default |
-addr32 / -addr64 | address bus and pointer width |
-cpu32 implies -addr32 unless you also say -addr64. An explicit -addr32/-addr64 always wins, whatever the order.
64-bit registers on a 32-bit bus is a shape real hardware has - RV32D, ARMv7 with NEON, MIPS64 in 32-bit addressing mode - so the compiler models the two separately rather than tying them together.
exe=native | kx | elf | coff | pe
native (the .kx) is the default and is what bare-metal targets and TUWA-RTOS link against. The container is independent of the CPU: the same code ships as .kx or as ELF. It is stamped into the object header, so every later tool reads it from the file rather than being told again.
-exe=FMT, exeformat=FMT and -exeformat=FMT all mean the same thing.
| Option | Does |
|---|---|
-Ipath | additional include directory (repeatable) |
-Dname[=value] | define a macro. -DNAME, -DNAME=VALUE, -D NAME all work |
-Werr | warnings become errors (-Werror also accepted) |
-debug / -nodebug | keep or strip debug symbols. Saying neither leaves current behaviour alone |
-core=rv32 | emit RV32I through the retarget back end |
-rtl | translate integer functions to synthesizable Verilog instead of running |
-core=rv32 writes <source>.rv32.lst and prints a coverage summary naming every three-address opcode not yet implemented - so an incomplete back end tells you exactly what is missing instead of emitting something that looks finished.
kcpp -cpu32 -pic mod.c
miskasm -nolink mod.asm
klink -pic -dll -import TuwaPrintConsole -export modmain -o mod.kx mod.obj
# -> also writes mod.twa
-pic makes the compiler reach globals through a base register instead of at absolute addresses, so the code runs wherever it is loaded.
klink -pic plus one of -exe / -dll / -drv writes a .twa module next to the .kx. The .kx is still written, because that is what kdis, kmap and ksym read and losing it makes a bad module much harder to diagnose.
-import <names> - comma-separated symbols the module may reference without defining. Without it an outside reference is a hard link error, on purpose, so a typo is caught at the command line rather than at load time.-export <names> - what the module offers. Keeps compiler-generated labels out of the export table.The extension is .twa and not .tuwa because a FAT 8.3 name allows a three-character extension. A four-character one cannot be created on a FAT volume at all - the filesystem refuses it rather than truncating - so a module could not be copied onto a target under the name the linker gave it.
| Tool | Does | |
|---|---|---|
miskasm <file.asm> | assemble. -nolink gives an object only, skipping the automatic single-file link | |
klink [-o out.kx] [-e entry] files... | link objects and libraries. Entry defaults to _start | |
klib | librarian - build and manage .lib archives | |
| `kmake <project.tpj \ | makefile>` | build driver. Takes the IDE's native project file or a legacy makefile |
kdis <file.kx> | disassemble to readable .dis | |
kmap <file.kx> | memory map: sections, symbols, source layout | |
ksym <file.kx> | symbol address table | |
knosym <file.kx> | strip debug symbols, writing a smaller .kx | |
kxtobin <file.kx> | flat .bin of the raw image | |
khex16, khex32, khex16withaddr, khex32withaddr | Intel-hex style output at 16 or 32 bits, with or without addresses | |
kice <file.kx> | in-circuit-emulator load file | |
kverilogsram <file.kx> | ICE file plus a Verilog SRAM initialisation file, for loading a design in simulation |
Every tool that takes a .kx accepts an optional output filename and picks a sensible default otherwise.
The native target is the RBT instruction set, 32- and 64-bit. -core=rv32 emits RV32I through the retarget back end, and RETARGET_PLAN.md describes how further targets are added.
For what a compiled program runs on, see the TUWA-RTOS documentation: TUWA-RTOS is the real-time operating system that loads and runs what this toolchain builds.
Errors and warnings go to <source>.error as well as to the console, so a build driven from a script leaves a record.
Check the exit code, not the output. A run can print Total errors:0 and still fail - the exit status is what a build script should test.