# dhake $ dhake -j 4

A build tool whose buildfile can’t lie.

Dhall is total, terminating, and typechecked — so your build definition always means exactly what it says. Typed actions · incremental · parallel · self-hosting.

Build (self-hosting)

// dhake builds itself from a Dhakefile.dhall

No build system required — dhake evaluates its own buildfile and builds dhake.com from source. The committed dhake.com is the bootstrap binary.

$ ./dhake.com.dbg          # evaluates Dhakefile.dhall, builds dhake.com
$ ./dhake.com.dbg --list   # list targets
$ ./tests/build.sh ./dhake.com.dbg   # run the test suite

Features

// parallel · typed · incremental
01

Parallel builds

-j N runs up to N independent targets concurrently. On first failure it stops scheduling new targets but lets running ones finish (make-style).

02

Typed actions

Recipes are Dhall tagged-union values: Shell, Copy, Mkdir, Rm, Touch, Move, Symlink, Chmod, Echo, Env, Run.

03

Dependency graph

Topologically orders targets, detects cycles, and builds only the subgraph reachable from the requested target(s).

04

Incremental

Nanosecond-mtime up-to-date checks skip unchanged targets and their dependency closures.

05

Dry-run & phony

-n prints the actions without running them; phony targets (e.g. clean) are always rebuilt.

06

Self-hosting

A single cosmocc APE that runs on Linux, macOS, Windows, and the BSDs — and builds itself.

Example Dhakefile.dhall

// targets = List { mapKey, mapValue } · default required
let Action = < Shell : Text | Copy : { from : Text, to : Text }
             | Mkdir : Text | Rm : Text | Touch : Text
             | Move : { from : Text, to : Text }
             | Symlink : { from : Text, to : Text }
             | Chmod : { path : Text, mode : Text }
             | Echo : Text
             | Env : { key : Text, value : Text }
             | Run : { argv : List Text } >
let Target = { deps : List Text, phony : Bool, recipe : List Action }
in  { targets =
        [ { mapKey = "hello"
          , mapValue = { deps = [ "hello.c" ], phony = False
                       , recipe = [ < Shell = "cc -o hello hello.c" > ] } }
        , { mapKey = "clean"
          , mapValue = { deps = [] : List Text, phony = True
                       , recipe = [ < Rm = "hello" > ] } }
        ]
    , default = "hello" }

Why Dhall?

// total · terminating · typechecked

Makefiles are turing-tarpit shell scripts with surprising whitespace semantics. Dhall is a strongly-typed, total configuration language — your build definition gets type checking, imports, and reusable functions, and it always terminates. The build plan is a plain value you can reason about, not a recipe of shell side effects.