A small make for TSVM / TVDOS.
TerranMAKE is a deliberate subset of GNU Make. It reads a Makefile, works out
which targets are out of date, and runs their recipes through the TVDOS shell.
The command is still make and the file is still Makefile — "TerranMAKE" is
just the name of this implementation.
make # build the first target in the Makefile
make clean # build a specific target
make all CFLAGS=-O2 # build 'all', overriding a variable
make -n install # dry run: show the recipes without running them
- Explicit rules —
target: prerequisitesfollowed by TAB-indented recipe lines. Multiple targets per rule, multiple rules adding prerequisites to the same target, and inlinetarget: dep ; reciperecipes. - Variables —
=(recursive),:=(simple),?=(set-if-unset),+=(append). Expansion with$(NAME),${NAME},$X, and$$for a literal$. Command-lineVAR=valueoverrides win over the Makefile. - Automatic variables in recipes —
$@(target),$<(first prerequisite),$^(all prerequisites),$?(changed prerequisites),$+. - Special targets —
.PHONY(always considered out of date), plus.SILENTand.IGNORE. - Order-only prerequisites —
target: normal | order-only. - Recipe prefixes —
@(don't echo),-(ignore errors),+(run even under-n). - Comments (
#), and line continuations (\at end of line). - Flags —
-f FILE,-C DIR,-n,-s,-B,-i,-k,-h,-v.
By design (per the project brief): conditionals (ifeq/ifdef), loops,
recursion, functions ($(wildcard …), $(patsubst …), …), and
pattern / implicit rules (%.o: %.c) — i.e. no dynamic rule generation.
GNU Make compares file modification times. TSVM's disk protocol never
reports a file's mtime to a JS program (you can ask whether a file exists, its
type, its size, and read its bytes — but there is no stat). A faithful mtime
comparison is therefore impossible on this platform.
Instead, TerranMAKE records a content fingerprint (a hash of the bytes) of
every prerequisite the last time a target was built, in a .tmake.state file
next to the Makefile. A target is rebuilt when it is missing, phony, or
when any prerequisite's contents changed since the last successful build.
The everyday effect is what you expect — edit a source, its dependents rebuild — but note the differences from real make:
touch-ing a file without changing its contents does not force a rebuild.- Deleting
.tmake.statemakes the nextmakerebuild everything.
Recipe lines are handed to the TVDOS shell (_G.shell.execute) exactly as
written (after stripping any @ - + prefix), one line per shell invocation.
Whatever the shell can run, a recipe can run: coreutils (cp, rm, mkdir,
echo, …), pipes (|), and installed programs.
The TVDOS shell has no > file redirection (only pipes). To write a file
from a recipe, pipe into writeto or tee, or use a program that writes its
own output file:
# portable on TVDOS:
report.txt: data
sort data | writeto report.txt
copy: original
cp original copySee examples/Makefile for a working example.
Via Hopper:
hop in make
The engine and parser are covered by a headless test suite that runs under the
TSVM Node harness (no emulator needed). From a checkout of both this repo and
tsvm:
node test/run.mjs # engine + parser unit tests (uses a shell shim)
node test/integration.mjs # end-to-end against the real TVDOS command.js shell
GPL-3.0-or-later. See COPYING.