Building: the CLI, teko.toml and the fixed point

teko is taught to mc: a build first assembles the taught compiler out of the modules of this package, and then that binary compiles the program. Both steps are one build command reading one config file.

The mc a build uses is pinned by ../../MC_VERSION: download the release of exactly that version. Another one may teach a different compiler, or none.


teko build #

teko build [DIR] [--config FILE] [--entry-only] [--compiler-only]
           [--limits | --fix-limits] [--sysroot-dir DIR] [--libs-dir DIR]

DIR defaults to .. With no --config, DIR/teko.toml is used when it exists, and DIR/mc.toml otherwise. Every path inside a config is resolved against the config's own directory, and that directory is also the project root the internal check measures from — so the path stays relative, without a leading ./, and lives at the package root.

flagmeans
--config FILEread FILE instead of the default
--compiler-onlybuild the taught compiler from [compiler].modules, print its path, stop
--entry-onlyskip the [compiler] step and compile [project].entry with the running binary
--limitsafter the build, print the table report and give a verdict
--fix-limitsthe same report, and rewrite only [limits] with the smallest tolerance that fits
--libs-dir DIRwhere an installed package lives, instead of $HOME/.mc/libs
--sysroot-dir DIRthis directory is the sysroot for [target]

--entry-only and --compiler-only are exclusive. One line is printed per step, always what from -> to.

mc build . --config teko.toml       # the stock mc: builds build/teko, then the entry
build/teko build . --config mc.host.toml --entry-only    # the taught compiler, one file

teko limits #

teko limits [DIR | FILE.tk]

With a .tk file it runs the whole pipeline over that one file and writes no object; with a directory it is teko build DIR --limits. The report is one row per internal table — the static estimate, what was reserved, the high-water usage, how many times the block doubled — and a verdict of ok, tight or grew.

The single-file modes #

Anything that is not a subcommand goes to the compiler driver teko inherits, so teko [MODE] SOURCE [-o OUT] compiles one file, and the dumps are the core's own: --dump-tokens, --dump-ast (after every pass), --dump-rules, --dump-asm, --dump-syms, --dump-machine. teko --host prints the pair this binary was built for and teko --version the mc version underneath it.

Exit codes #

codemeans
0success
1a diagnostic: a compile error, a TOML error, a tool that failed
2the environment is not ready (no sysroot, a dependency not fetched)
3verdict tight or grew, under --limits
70a program that panicked at run time (memory.md)

teko.toml — how a project is built #

[project]
name  = "teko"
entry = "tests/hello.tk"
out   = "build/teko-hello"
kind  = "exe"

[target]
os   = "linux"
arch = "x86_64"

[compiler]
core    = "<mc/core_min>"
modules = ["core_teko.mc", "teko.tk", "user.mc"]
out     = "build/teko"

[linker]
cmd  = "cc"
args = ["-o", "{out}", "{obj}"]

[limits]
tolerance = 1.0

[include]
paths = ["lib"]
sectionkeymeans
[project]namethe project's name
entrythe source the build compiles with the taught compiler
outwhere that program is written
kindexe or obj
[target]os, archthe pair to build for; interp and libc name a Linux loader and C library family
[compiler]corethe core parts the taught compiler is assembled from
modulesthe modules taught on top of it, in order — the last one defines user_init
outwhere the taught compiler is written
[linker]cmd, argsthe external linker, with {out} and {obj} substituted. With no [linker], the built-in executable writer is used where the host has one
[limits]tolerancethe slack over the static estimate the tables are reserved with
[include]pathsextra roots a #include "…" is resolved against, after the includer's own directory

A host that does not link the pair in [target] derives its own config from this file rather than editing it — replace os/arch, drop [linker] where the platform has a built-in writer — which is what the CI legs and the fixed-point script do.

mc.toml — the package manifest #

The package and the build are two files on purpose: mc pkg hash DIR reads DIR/mc.toml and takes no --config, so the two roles cannot share one file once the package is the repository.

[package]
name  = "teko"
lib   = "lib/rt.tk"
files = [ "core_teko.mc", "lib/rt.tk", "teko.tk", "..." ]
check = ["mc_teko.tk"]
keymeans
namethe package name — teko, the library
libthe file #include <teko> serves
filesevery file the package ships; the tree hash digests exactly these bytes
checkunits the registry compiles on their own, with the stock mc and no teko loaded, to validate a publication

There is no [project] here, and that is what makes the name a library rather than a tool: a manifest carrying kind = "exe" would be published as a tool for good.


The fixed point #

../../scripts/bootstrap.sh proves the compiler reproduces itself:

sh scripts/bootstrap.sh                          # the host pair, from `mc --host`
sh scripts/bootstrap.sh --os linux --arch x86_64
stagebuilt byfrom
teko0the stock mc[compiler].modules
teko1teko0mc_teko.tk — the whole compiler as one unit
teko2teko1the same
teko3teko2the same

Three criteria, all of them checked:

  1. cmp build/teko2.o build/teko3.o — byte-identical objects. teko1.o against teko2.o is deliberately not the criterion: those come from two different compilers.
  2. the --dump-asm of teko2 and of teko3 differ nowhere.
  3. teko1 compiles and runs all 45 fixtures of tests/, each one's own // expect-exit: N being the oracle.

It prints FIXPOINT OK when all three hold. The ladder runs every stage it builds, so the target pair is checked against mc --host and a cross build is refused rather than produced unproven.

The gates a change has to pass #

gatewhat it proves
the five native legseach (os, arch) pair builds the taught compiler on its own runner and runs the 45 fixtures there
the five fixpoint legsthe ladder above closes on the same five pairs
docs../../scripts/check-docs.sh: links resolve, every teko example on this site is compiled and run, every teko: … message the sources carry is documented in diagnostics.md

Edit this page