~sircmpwn/hare-dev

This thread contains a patchset. You're looking at the original emails, but you may wish to use the patch review UI. Review patch
10 6

[PATCH hare] replace scripts/gen-stdlib with cmd/genbootstrap

Details
Message ID
<20230913232612.21752-1-ecs@d2evs.net>
DKIM signature
pass
Download raw message
Patch: +1757 -7108
- uses hare::module to automatically generate the makefiles, so keeping
  the bootstrap makefiles up-to-date only requires running
  make bootstrap (or scripts/genbootstrap if merge conflicts temporarily
  break the makefiles)
- the ci also verifies that you've done this, so it's impossible for it
  to get out of sync
- tests are run with `hare test` rather than reimplementing that in
  make
- dependencies of a module are only forcibly recompiled when the
  module's public interface changes, rather than on any changes anywhere
  in the dependency tree, making it much more pleasant to work on eg.
  rt::

Co-authored-by: Autumn! <autumnull@posteo.net>
Co-authored-by: Sebastian <sebastian@sebsite.pw>
Signed-off-by: Ember Sawady <ecs@d2evs.net>
---
sending this off now because it's already a huge improvement over
gen-stdlib, but it's worth noting that it may make sense to replace make
with ninja here

a few more misc notes:
- we could probably shrink the combined size of the generated makefiles
  quite a bit by pulling generic modules out into a separate makefile,
  but it'd be more complex to generate and woudln't decrease the actual
  complexity of anything, so it's probably not worth it
- it'd be nice to recompile everything automatically when harec -v
  changes, but i'm not sure how to do that in make

ci likely won't work for this since it makes nontrivial changes to
.build.yml, see https://builds.sr.ht/~ecs/job/1057278 for a successful
build
 .builds/alpine.yml           |   16 +-
 .builds/freebsd.yml          |    3 -
 Makefile                     |  154 +-
 cmd/genbootstrap/main.ha     |   96 +
 config.example.mk            |   31 +-
 makefiles/freebsd.aarch64.mk |  250 ++
 makefiles/freebsd.riscv64.mk |  250 ++
 makefiles/freebsd.x86_64.mk  |  250 ++
 makefiles/linux.aarch64.mk   |  268 ++
 makefiles/linux.riscv64.mk   |  268 ++
 makefiles/linux.x86_64.mk    |  268 ++
 scripts/gen-docs.sh          |   32 -
 scripts/gen-stdlib           | 1775 ------------
 scripts/gen-stdlib.sh        |  138 -
 scripts/genbootstrap         |   11 +
 scripts/install-mods         |   45 -
 scripts/moddirs              |    4 +
 scripts/modules              |   27 -
 stdlib.mk                    | 4962 ----------------------------------
 targets.mk                   |   17 -
 20 files changed, 1757 insertions(+), 7108 deletions(-)
 create mode 100644 cmd/genbootstrap/main.ha
 create mode 100644 makefiles/freebsd.aarch64.mk
 create mode 100644 makefiles/freebsd.riscv64.mk
 create mode 100644 makefiles/freebsd.x86_64.mk
 create mode 100644 makefiles/linux.aarch64.mk
 create mode 100644 makefiles/linux.riscv64.mk
 create mode 100644 makefiles/linux.x86_64.mk
 delete mode 100644 scripts/gen-docs.sh
 delete mode 100755 scripts/gen-stdlib
 delete mode 100644 scripts/gen-stdlib.sh
 create mode 100755 scripts/genbootstrap
 delete mode 100755 scripts/install-mods
 create mode 100755 scripts/moddirs
 delete mode 100755 scripts/modules
 delete mode 100644 stdlib.mk
 delete mode 100644 targets.mk

diff --git a/.builds/alpine.yml b/.builds/alpine.yml
index 0dec402f..a429b51b 100644
--- a/.builds/alpine.yml
+++ b/.builds/alpine.yml
@@ -32,18 +32,20 @@ tasks:
    cp config.example.mk config.mk
    make -j2
    sudo make install
- tests: |
    cd hare
    make -j2 .bin/hare-tests
- check: |
    cd hare
    make -j2 check
- tests_with_libc: |
    cd hare
    hare test -T+libc -lc -o .bin/hare-tests-libc
- check_with_libc: |
    cd hare
    .bin/hare-tests-libc
    hare test -lc
- bootstrap: |
    cd hare
    make -j2 bootstrap
    if ! [ -z "$(git status --porcelain)" ]
    then
        echo "bootstrap makefiles out of date, run make bootstrap to regenerate"
        exit 1
    fi
- docs: |
    if [ $BUILD_SUBMITTER != "git.sr.ht" ]
    then
diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml
index 54e6adf9..08d00a2f 100644
--- a/.builds/freebsd.yml
+++ b/.builds/freebsd.yml
@@ -22,9 +22,6 @@ tasks:
    sed -e 's/linux/freebsd/g' < config.example.mk > config.mk
    make -j2
    sudo make install
- tests: |
    cd hare
    make -j2 .bin/hare-tests
- check: |
    cd hare
    make -j2 check
diff --git a/Makefile b/Makefile
index 1a9bd98c..b38d8a73 100644
--- a/Makefile
+++ b/Makefile
@@ -1,96 +1,75 @@
.POSIX:
.SUFFIXES:
include config.mk
TESTCACHE = $(HARECACHE)/+test
TESTHARECFLAGS = $(HARECFLAGS) -T
STDLIB = .
stdlib_env = env
testlib_env = env

all:

.SUFFIXES: .ha .ssa .s .o .scd
include config.mk
include makefiles/$(PLATFORM).$(ARCH).mk

all: $(BINOUT)/hare $(BINOUT)/harec2 $(BINOUT)/haredoc docs

HARE_DEFINES:=\
	-D PLATFORM:str='"'"$(PLATFORM)"'"' \
	-D ARCH:str='"'"$(ARCH)"'"' \
	-D VERSION:str='"'"$(VERSION)"'"' \
	-D HAREPATH:str='"'"$(HAREPATH)"'"' \
	-D AARCH64_AS:str='"'"$(AARCH64_AS)"'"' \
	-D AARCH64_CC:str='"'"$(AARCH64_CC)"'"' \
	-D AARCH64_LD:str='"'"$(AARCH64_LD)"'"' \
	-D RISCV64_AS:str='"'"$(RISCV64_AS)"'"' \
	-D RISCV64_CC:str='"'"$(RISCV64_CC)"'"' \
	-D RISCV64_LD:str='"'"$(RISCV64_LD)"'"' \
	-D X86_64_AS:str='"'"$(X86_64_AS)"'"' \
	-D X86_64_CC:str='"'"$(X86_64_CC)"'"' \
	-D X86_64_LD:str='"'"$(X86_64_LD)"'"'

.SUFFIXES: # clear suffixes
.SUFFIXES: .ha .ssa .td .s .o .scd
.ssa.td:
	@cmp -s $@ $@.tmp 2>/dev/null || cp $@.tmp $@

.ssa.s:
	@printf 'QBE\t%s\n' "$@"
	@$(QBE) -o $@ $<
	@$(QBE) $(QBEFLAGS) -o $@ $<

.s.o:
	@printf 'AS\t%s\n' "$@"
	@$(AS) -g -o $@ $<
	@$(AS) $(ASFLAGS) -o $@ $<

.scd:
	@printf 'SCDOC\t%s\n' "$@"
	@$(SCDOC) < $< > $@


include stdlib.mk

hare_srcs = \
	./cmd/hare/arch.ha \
	./cmd/hare/build.ha \
	./cmd/hare/cache.ha \
	./cmd/hare/deps.ha \
	./cmd/hare/error.ha \
	./cmd/hare/main.ha \
	./cmd/hare/util.ha \
	./cmd/hare/version.ha

harec_srcs = \
	./cmd/harec/main.ha \
	./cmd/harec/errors.ha

haredoc_srcs = \
	./cmd/haredoc/main.ha \
	./cmd/haredoc/arch.ha \
	./cmd/haredoc/error.ha \
	./cmd/haredoc/util.ha \
	./cmd/haredoc/doc/color.ha \
	./cmd/haredoc/doc/hare.ha \
	./cmd/haredoc/doc/html.ha \
	./cmd/haredoc/doc/resolve.ha \
	./cmd/haredoc/doc/sort.ha \
	./cmd/haredoc/doc/tty.ha \
	./cmd/haredoc/doc/types.ha \
	./cmd/haredoc/doc/util.ha

include targets.mk

$(HARECACHE)/hare.ssa: $(hare_srcs) $(stdlib_deps_any) $(stdlib_deps_$(PLATFORM)) scripts/version
	@printf 'HAREC\t%s\n' "$@"
	@$(stdlib_env) $(HAREC) $(HARECFLAGS) \
		$(HARE_DEFINES) -o $@ $(hare_srcs)

$(TESTCACHE)/hare.ssa: $(hare_srcs) $(testlib_deps_any) $(testlib_deps_$(PLATFORM)) scripts/version
	@printf 'HAREC\t%s\n' "$@"
	@$(testlib_env) $(HAREC) $(TESTHARECFLAGS) \
		$(HARE_DEFINES) -o $@ $(hare_srcs)

$(BINOUT)/hare: $(HARECACHE)/hare.o
	@mkdir -p $(BINOUT)
$(BINOUT)/hare: $(OBJS)
	@mkdir -p -- "$(BINOUT)"
	@printf 'LD\t%s\n' "$@"
	@$(LD) $(LDLINKFLAGS) --gc-sections -z noexecstack -T $(rtscript) -o $@ \
		$(HARECACHE)/hare.o $(stdlib_deps_any) $(stdlib_deps_$(PLATFORM))
	@$(LD) $(LDLINKFLAGS) --gc-sections -z noexecstack -T $(RTSCRIPT) -o $@ $(OBJS)

$(BINOUT)/hare-tests: $(TESTCACHE)/hare.o
	@mkdir -p $(BINOUT)
	@printf 'LD\t%s\n' "$@"
	@$(LD) $(LDLINKFLAGS) -T $(rtscript) -o $@ \
		$(testlib_deps_any) $(testlib_deps_$(PLATFORM))

$(BINOUT)/harec2: $(BINOUT)/hare $(harec_srcs)
	@mkdir -p $(BINOUT)
$(BINOUT)/harec2: $(BINOUT)/hare
	@printf 'HARE\t%s\n' "$@"
	@env HAREPATH=. HAREC=$(HAREC) QBE=$(QBE) $(BINOUT)/hare build \
		$(HARE_DEFINES) -o $(BINOUT)/harec2 cmd/harec
	@env HAREPATH=. HAREC=$(HAREC) QBE=$(QBE) AS=$(AS) LD=$(LD) \
		HAREFLAGS=$(HAREFLAGS) HARECFLAGS=$(HARECFLAGS) \
		QBEFLAGS=$(QBEFLAGS) ASFLAGS=$(ASFLAGS) \
		LDLINKFLAGS=$(LDLINKFLAGS) \
		$(BINOUT)/hare build $(HARE_DEFINES) -o $(BINOUT)/harec2 cmd/harec

$(BINOUT)/haredoc: $(BINOUT)/hare $(haredoc_srcs)
$(BINOUT)/haredoc: $(BINOUT)/hare
	@mkdir -p $(BINOUT)
	@printf 'HARE\t%s\n' "$@"
	@env HAREPATH=. HAREC=$(HAREC) QBE=$(QBE) $(BINOUT)/hare build \
		$(HARE_DEFINES) -o $(BINOUT)/haredoc ./cmd/haredoc

docs/html: $(BINOUT)/haredoc scripts/gen-docs.sh
	BINOUT=$(BINOUT) $(SHELL) ./scripts/gen-docs.sh
docs/html: $(BINOUT)/haredoc
	mkdir -p docs/html
	$(BINOUT)/haredoc -Fhtml > docs/html/index.html
	for d in $$(scripts/moddirs); do \
		find $$d -type d | sed -E '/(\+|-)/d'; \
	done \
	| while read path; do \
		mod=$$(echo $$path | sed -E 's@/@::@g'); \
		echo $$mod; \
		mkdir -p docs/html/$$path; \
		$(BINOUT)/hare doc -Fhtml $$mod > docs/html/$$path/index.html; \
	done

docs/hare.1: docs/hare.1.scd
docs/haredoc.1: docs/haredoc.1.scd
@@ -98,29 +77,35 @@ docs/hare-doc.5: docs/hare-doc.5.scd

docs: docs/hare.1 docs/haredoc.1 docs/hare-doc.5

bootstrap:
	@BINOUT=$(BINOUT) ./scripts/genbootstrap

clean:
	rm -rf $(HARECACHE) $(BINOUT) docs/hare.1 docs/haredoc.1 docs/hare-doc.5 \
		docs/html

check: $(BINOUT)/hare-tests
	@$(BINOUT)/hare-tests

scripts/gen-docs.sh: scripts/gen-stdlib
scripts/gen-stdlib: scripts/gen-stdlib.sh
check: $(BINOUT)/hare
	@env HAREPATH=. HAREC=$(HAREC) QBE=$(QBE) AS=$(AS) LD=$(LD) \
		HAREFLAGS=$(HAREFLAGS) HARECFLAGS=$(HARECFLAGS) \
		QBEFLAGS=$(QBEFLAGS) ASFLAGS=$(ASFLAGS) \
		LDLINKFLAGS=$(LDLINKFLAGS) $(BINOUT)/hare test

all: $(BINOUT)/hare $(BINOUT)/harec2 $(BINOUT)/haredoc docs
install: install-cmd install-mods

install: docs scripts/install-mods
	mkdir -p \
		$(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man1 \
		$(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man5 \
		$(DESTDIR)$(SRCDIR)/hare/stdlib
install-cmd:
	mkdir -p -- \
		"$(DESTDIR)$(BINDIR)" "$(DESTDIR)$(MANDIR)/man1" \
		"$(DESTDIR)$(BINDIR)" "$(DESTDIR)$(MANDIR)/man5"
	install -m755 $(BINOUT)/hare $(DESTDIR)$(BINDIR)/hare
	install -m755 $(BINOUT)/haredoc $(DESTDIR)$(BINDIR)/haredoc
	install -m644 docs/hare.1 $(DESTDIR)$(MANDIR)/man1/hare.1
	install -m644 docs/haredoc.1 $(DESTDIR)$(MANDIR)/man1/haredoc.1
	install -m644 docs/hare-doc.5 $(DESTDIR)$(MANDIR)/man5/hare-doc.5
	./scripts/install-mods "$(DESTDIR)$(SRCDIR)/hare/stdlib"

install-mods:
	rm -rf -- "$(DESTDIR)$(STDLIB)"
	mkdir -p -- "$(DESTDIR)$(STDLIB)"
	cp -R $$(scripts/moddirs) "$(DESTDIR)$(STDLIB)"

uninstall:
	$(RM) $(DESTDIR)$(BINDIR)/hare
@@ -128,6 +113,7 @@ uninstall:
	$(RM) $(DESTDIR)$(MANDIR)/man1/hare.1
	$(RM) $(DESTDIR)$(MANDIR)/man1/haredoc.1
	$(RM) $(DESTDIR)$(MANDIR)/man5/hare-doc.5
	$(RM) -r $(DESTDIR)$(SRCDIR)/hare/stdlib
	$(RM) -r $(DESTDIR)$(STDLIB)

.PHONY: all clean check docs install uninstall
.PHONY: all $(BINOUT)/harec2 $(BINOUT)/haredoc bootstrap clean check docs \
	docs/html install start uninstall write_version
diff --git a/cmd/genbootstrap/main.ha b/cmd/genbootstrap/main.ha
new file mode 100644
index 00000000..03b2d539
--- /dev/null
+++ b/cmd/genbootstrap/main.ha
@@ -0,0 +1,96 @@
use fmt;
use hare::module;
use hare::unparse;
use io;
use memio;
use os;
use path;
use strings;

export fn main() void = {
	if (len(os::args) > 1 && os::args[1] == "-h") {
		fmt::errorln("usage:", os::args[0], "[<tag>...]")!;
		os::exit(0);
	};

	const ctx = module::context {
		harepath = os::tryenv("HAREPATH", "."),
		harecache = os::tryenv("HARECACHE", ".cache"),
		tags = os::args[1..],
	};
	let mods: []module::module = [];
	defer module::free_slice(mods);
	module::gather(&ctx, &mods, ["rt"])!;
	module::gather(&ctx, &mods, ["cmd", "hare"])!;

	let ids: [](str, str) = [];
	defer free(ids);
	defer for (let i = 0z; i < len(ids); i += 1) {
		free(ids[i].0);
		free(ids[i].1);
	};

	let tds = memio::dynamic();
	defer io::close(&tds)!;
	let objs = memio::dynamic();
	defer io::close(&objs)!;
	for (let i = 0z; i < len(mods); i += 1) {
		append(ids, (strings::join("_", mods[i].ns...),
			unparse::identstr(mods[i].ns)));
		fmt::fprintf(&tds, ` HARE_TD_{}=$(HARECACHE)/{}.td`,
			ids[i].1, ids[i].0)!;
		fmt::fprintf(&objs, ` $(HARECACHE)/{}.o`, ids[i].0)!;
	};

	let cwd = os::getcwd();
	let buf = path::init(mods[0].srcs.sc[0])!;
	fmt::println(`# generated by cmd/genbootstrap`)!;
	fmt::println(`# DO NOT EDIT BY HAND. run 'make bootstrap' to update`)!;
	fmt::printfln(`TDENV = env{}`, memio::string(&tds)!)!;
	fmt::printfln(`RTSCRIPT = {}`, path::trimprefix(&buf, cwd)!)!;
	fmt::printfln(`OBJS ={}`, memio::string(&objs)!)!;

	let deps = memio::dynamic();
	defer io::close(&deps)!;
	let sources = memio::dynamic();
	defer io::close(&sources)!;
	for (let i = 0z; i < len(mods); i += 1) {
		memio::reset(&deps);
		for (let j = 0z; j < len(mods[i].deps); j += 1) {
			fmt::fprintf(&deps, ` $(HARECACHE)/{}.td`,
				ids[mods[i].deps[j].0].0)!;
		};
		memio::reset(&sources);
		for (let j = 0z; j < len(mods[i].srcs.ha); j += 1) {
			path::set(&buf, mods[i].srcs.ha[j])!;
			fmt::fprint(&sources, "", path::trimprefix(&buf, cwd)!)!;
		};

		fmt::println()!;
		fmt::printfln(`{}_ha ={}`, ids[i].0, memio::string(&sources)!)!;
		fmt::printfln(`$(HARECACHE)/{}.ssa: $({}_ha){}`,
			ids[i].0, ids[i].0, memio::string(&deps)!)!;
		fmt::println("\t" `@mkdir -p -- "$(HARECACHE)"`)!;
		fmt::println("\t" `@printf 'HAREC\t%s\n' "$@"`)!;
		fmt::printfln("\t" `@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/{}.ssa -t $(HARECACHE)/{}.td.tmp {} {} $({}_ha)`,
			ids[i].0, ids[i].0,
			if (i == len(mods) - 1) `$(HARE_DEFINES)` else `-N`,
			if (i == len(mods) - 1) `` else ids[i].1, ids[i].0)!;
		if (len(mods[i].srcs.s) == 0) {
			continue;
		};

		memio::reset(&sources);
		for (let j = 0z; j < len(mods[i].srcs.s); j += 1) {
			path::set(&buf, mods[i].srcs.s[j])!;
			fmt::fprint(&sources, "", path::trimprefix(&buf, cwd)!)!;
		};

		fmt::println()!;
		fmt::printfln(`{}_s = $(HARECACHE)/{}.s{}`,
			ids[i].0, ids[i].0, memio::string(&sources)!)!;
		fmt::printfln(`$(HARECACHE)/{}.o: $({}_s)`, ids[i].0, ids[i].0)!;
		fmt::println("\t" `@printf 'AS\t%s\n' "$@"`)!;
		fmt::printfln("\t" `@$(AS) $(ASFLAGS) -o $@ $({}_s)`, ids[i].0)!;
	};
};
diff --git a/config.example.mk b/config.example.mk
index 75ef9a88..1424afaf 100644
--- a/config.example.mk
+++ b/config.example.mk
@@ -1,47 +1,42 @@
## Install configuration

# install locations
PREFIX = /usr/local
BINDIR = $(PREFIX)/bin
MANDIR = $(PREFIX)/share/man
SRCDIR = $(PREFIX)/src

# Where to install the stdlib tree
STDLIB = $(SRCDIR)/hare/stdlib

# Default HAREPATH
HAREPATH = $(SRCDIR)/hare/stdlib:$(SRCDIR)/hare/third-party

## Build configuration

# Platform to build for
# variables used during build
PLATFORM = linux
ARCH = x86_64
HAREFLAGS =
HARECFLAGS =
QBEFLAGS =
ASFLAGS =
LDLINKFLAGS =

# External tools and flags
# commands used by the build script
HAREC = harec
HAREFLAGS =
QBE = qbe
AS = as
LD = ld
AR = ar
SCDOC = scdoc

# Where to store build artifacts
# build locations
HARECACHE = .cache
BINOUT = .bin

# Cross-compiler toolchains
# variables that will be embedded in the binary with -D definitions
HAREPATH = $(SRCDIR)/hare/stdlib:$(SRCDIR)/hare/third-party
VERSION=$$(./scripts/version)

AARCH64_AS=aarch64-as
AARCH64_AR=aarch64-ar
AARCH64_CC=aarch64-cc
AARCH64_LD=aarch64-ld

RISCV64_AS=riscv64-as
RISCV64_AR=riscv64-ar
RISCV64_CC=riscv64-cc
RISCV64_LD=riscv64-ld

X86_64_AS=as
X86_64_AR=ar
X86_64_CC=cc
X86_64_LD=ld
diff --git a/makefiles/freebsd.aarch64.mk b/makefiles/freebsd.aarch64.mk
new file mode 100644
index 00000000..93665531
--- /dev/null
+++ b/makefiles/freebsd.aarch64.mk
@@ -0,0 +1,250 @@
# generated by cmd/genbootstrap
# DO NOT EDIT BY HAND. run 'make bootstrap' to update
TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_encoding::utf8=$(HARECACHE)/encoding_utf8.td HARE_TD_types=$(HARECACHE)/types.td HARE_TD_bytes=$(HARECACHE)/bytes.td HARE_TD_strings=$(HARECACHE)/strings.td HARE_TD_ascii=$(HARECACHE)/ascii.td HARE_TD_errors=$(HARECACHE)/errors.td HARE_TD_io=$(HARECACHE)/io.td HARE_TD_bufio=$(HARECACHE)/bufio.td HARE_TD_crypto::math=$(HARECACHE)/crypto_math.td HARE_TD_endian=$(HARECACHE)/endian.td HARE_TD_math=$(HARECACHE)/math.td HARE_TD_memio=$(HARECACHE)/memio.td HARE_TD_path=$(HARECACHE)/path.td HARE_TD_time=$(HARECACHE)/time.td HARE_TD_fs=$(HARECACHE)/fs.td HARE_TD_types::c=$(HARECACHE)/types_c.td HARE_TD_os=$(HARECACHE)/os.td HARE_TD_strconv=$(HARECACHE)/strconv.td HARE_TD_fmt=$(HARECACHE)/fmt.td HARE_TD_hash=$(HARECACHE)/hash.td HARE_TD_crypto::sha256=$(HARECACHE)/crypto_sha256.td HARE_TD_encoding::hex=$(HARECACHE)/encoding_hex.td HARE_TD_sort=$(HARECACHE)/sort.td HARE_TD_hare::lex=$(HARECACHE)/hare_lex.td HARE_TD_hare::ast=$(HARECACHE)/hare_ast.td HARE_TD_hare::parse=$(HARECACHE)/hare_parse.td HARE_TD_hare::unparse=$(HARECACHE)/hare_unparse.td HARE_TD_time::chrono=$(HARECACHE)/time_chrono.td HARE_TD_time::date=$(HARECACHE)/time_date.td HARE_TD_hare::module=$(HARECACHE)/hare_module.td HARE_TD_unix=$(HARECACHE)/unix.td HARE_TD_unix::signal=$(HARECACHE)/unix_signal.td HARE_TD_os::exec=$(HARECACHE)/os_exec.td HARE_TD_shlex=$(HARECACHE)/shlex.td HARE_TD_unix::tty=$(HARECACHE)/unix_tty.td HARE_TD_cmd::hare::build=$(HARECACHE)/cmd_hare_build.td HARE_TD_dirs=$(HARECACHE)/dirs.td HARE_TD_getopt=$(HARECACHE)/getopt.td HARE_TD_cmd::hare=$(HARECACHE)/cmd_hare.td
RTSCRIPT = rt/hare.sc
OBJS = $(HARECACHE)/rt.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/types_c.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/time_chrono.o $(HARECACHE)/time_date.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o

rt_ha = rt/+aarch64/arch_jmp.ha rt/+aarch64/backtrace.ha rt/+aarch64/cpuid.ha rt/+freebsd/+aarch64.ha rt/+freebsd/env.ha rt/+freebsd/errno.ha rt/+freebsd/platform_abort.ha rt/+freebsd/platformstart.ha rt/+freebsd/segmalloc.ha rt/+freebsd/signal.ha rt/+freebsd/socket.ha rt/+freebsd/syscallno.ha rt/+freebsd/syscalls.ha rt/+freebsd/types.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/start.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
$(HARECACHE)/rt.ssa: $(rt_ha)
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/rt.ssa -t $(HARECACHE)/rt.td.tmp -N rt $(rt_ha)

rt_s = $(HARECACHE)/rt.s rt/+aarch64/cpuid.s rt/+aarch64/fenv.s rt/+aarch64/getfp.s rt/+aarch64/longjmp.s rt/+aarch64/restore.s rt/+aarch64/setjmp.s rt/+freebsd/start+aarch64-libc.s rt/+freebsd/syscall+aarch64.s
$(HARECACHE)/rt.o: $(rt_s)
	@printf 'AS\t%s\n' "$@"
	@$(AS) $(ASFLAGS) -o $@ $(rt_s)

encoding_utf8_ha = encoding/utf8/decode.ha encoding/utf8/decodetable.ha encoding/utf8/encode.ha encoding/utf8/rune.ha
$(HARECACHE)/encoding_utf8.ssa: $(encoding_utf8_ha)
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/encoding_utf8.ssa -t $(HARECACHE)/encoding_utf8.td.tmp -N encoding::utf8 $(encoding_utf8_ha)

types_ha = types/arch+aarch64.ha types/classes.ha types/limits.ha
$(HARECACHE)/types.ssa: $(types_ha)
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/types.ssa -t $(HARECACHE)/types.td.tmp -N types $(types_ha)

bytes_ha = bytes/contains.ha bytes/equal.ha bytes/index.ha bytes/reverse.ha bytes/tokenize.ha bytes/trim.ha bytes/two_way.ha bytes/zero.ha
$(HARECACHE)/bytes.ssa: $(bytes_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/bytes.ssa -t $(HARECACHE)/bytes.td.tmp -N bytes $(bytes_ha)

strings_ha = strings/compare.ha strings/concat.ha strings/contains.ha strings/dup.ha strings/index.ha strings/iter.ha strings/pad.ha strings/replace.ha strings/runes.ha strings/sub.ha strings/suffix.ha strings/tokenize.ha strings/trim.ha strings/utf8.ha
$(HARECACHE)/strings.ssa: $(strings_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/strings.ssa -t $(HARECACHE)/strings.td.tmp -N strings $(strings_ha)

ascii_ha = ascii/ctype.ha ascii/string.ha ascii/valid.ha
$(HARECACHE)/ascii.ssa: $(ascii_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/ascii.ssa -t $(HARECACHE)/ascii.td.tmp -N ascii $(ascii_ha)

errors_ha = errors/common.ha errors/opaque.ha errors/rt.ha errors/string.ha
$(HARECACHE)/errors.ssa: $(errors_ha) $(HARECACHE)/rt.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/errors.ssa -t $(HARECACHE)/errors.td.tmp -N errors $(errors_ha)

io_ha = io/+freebsd/mmap.ha io/+freebsd/platform_file.ha io/+freebsd/vector.ha io/arch+aarch64.ha io/copy.ha io/drain.ha io/empty.ha io/file.ha io/handle.ha io/limit.ha io/stream.ha io/tee.ha io/types.ha io/util.ha io/zero.ha
$(HARECACHE)/io.ssa: $(io_ha) $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/rt.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/io.ssa -t $(HARECACHE)/io.td.tmp -N io $(io_ha)

bufio_ha = bufio/scanner.ha bufio/stream.ha
$(HARECACHE)/bufio.ssa: $(bufio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/bufio.ssa -t $(HARECACHE)/bufio.td.tmp -N bufio $(bufio_ha)

crypto_math_ha = crypto/math/arithm.ha crypto/math/bits.ha
$(HARECACHE)/crypto_math.ssa: $(crypto_math_ha)
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/crypto_math.ssa -t $(HARECACHE)/crypto_math.td.tmp -N crypto::math $(crypto_math_ha)

endian_ha = endian/big.ha endian/endian.ha endian/host+aarch64.ha endian/little.ha endian/network.ha
$(HARECACHE)/endian.ssa: $(endian_ha)
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/endian.ssa -t $(HARECACHE)/endian.td.tmp -N endian $(endian_ha)

math_ha = math/fenv+aarch64.ha math/fenv_func.ha math/floats.ha math/ints.ha math/math.ha math/trig.ha math/uints.ha
$(HARECACHE)/math.ssa: $(math_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/math.ssa -t $(HARECACHE)/math.td.tmp -N math $(math_ha)

memio_ha = memio/ops.ha memio/stream.ha
$(HARECACHE)/memio.ssa: $(memio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/memio.ssa -t $(HARECACHE)/memio.td.tmp -N memio $(memio_ha)

path_ha = path/+freebsd.ha path/buffer.ha path/error.ha path/ext_stack.ha path/iter.ha path/posix.ha path/prefix.ha path/stack.ha
$(HARECACHE)/path.ssa: $(path_ha) $(HARECACHE)/bytes.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/path.ssa -t $(HARECACHE)/path.td.tmp -N path $(path_ha)

time_ha = time/+freebsd/functions.ha time/arithm.ha time/conv.ha time/types.ha
$(HARECACHE)/time.ssa: $(time_ha) $(HARECACHE)/math.td $(HARECACHE)/rt.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/time.ssa -t $(HARECACHE)/time.td.tmp -N time $(time_ha)

fs_ha = fs/fs.ha fs/types.ha fs/util.ha
$(HARECACHE)/fs.ssa: $(fs_ha) $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/strings.td $(HARECACHE)/time.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/fs.ssa -t $(HARECACHE)/fs.td.tmp -N fs $(fs_ha)

types_c_ha = types/c/arch+aarch64.ha types/c/strings.ha types/c/types.ha
$(HARECACHE)/types_c.ssa: $(types_c_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/types_c.ssa -t $(HARECACHE)/types_c.td.tmp -N types::c $(types_c_ha)

os_ha = os/+freebsd/dirfdfs.ha os/+freebsd/exit.ha os/+freebsd/fs.ha os/+freebsd/platform_environ.ha os/+freebsd/status.ha os/+freebsd/stdfd.ha os/environ.ha os/os.ha
$(HARECACHE)/os.ssa: $(os_ha) $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/os.ssa -t $(HARECACHE)/os.td.tmp -N os $(os_ha)

strconv_ha = strconv/ftos.ha strconv/itos.ha strconv/numeric.ha strconv/stof.ha strconv/stof_data.ha strconv/stoi.ha strconv/stou.ha strconv/types.ha strconv/utos.ha
$(HARECACHE)/strconv.ssa: $(strconv_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/math.td $(HARECACHE)/strings.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/strconv.ssa -t $(HARECACHE)/strconv.td.tmp -N strconv $(strconv_ha)

fmt_ha = fmt/fmt.ha
$(HARECACHE)/fmt.ssa: $(fmt_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/fmt.ssa -t $(HARECACHE)/fmt.td.tmp -N fmt $(fmt_ha)

hash_ha = hash/hash.ha
$(HARECACHE)/hash.ssa: $(hash_ha) $(HARECACHE)/fmt.td $(HARECACHE)/io.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/hash.ssa -t $(HARECACHE)/hash.td.tmp -N hash $(hash_ha)

crypto_sha256_ha = crypto/sha256/sha256.ha
$(HARECACHE)/crypto_sha256.ssa: $(crypto_sha256_ha) $(HARECACHE)/bytes.td $(HARECACHE)/crypto_math.td $(HARECACHE)/endian.td $(HARECACHE)/hash.td $(HARECACHE)/io.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/crypto_sha256.ssa -t $(HARECACHE)/crypto_sha256.td.tmp -N crypto::sha256 $(crypto_sha256_ha)

encoding_hex_ha = encoding/hex/hex.ha
$(HARECACHE)/encoding_hex.ssa: $(encoding_hex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/encoding_hex.ssa -t $(HARECACHE)/encoding_hex.td.tmp -N encoding::hex $(encoding_hex_ha)

sort_ha = sort/bisect.ha sort/search.ha sort/sort.ha sort/types.ha
$(HARECACHE)/sort.ssa: $(sort_ha) $(HARECACHE)/math.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/sort.ssa -t $(HARECACHE)/sort.td.tmp -N sort $(sort_ha)

hare_lex_ha = hare/lex/lex.ha hare/lex/token.ha
$(HARECACHE)/hare_lex.ssa: $(hare_lex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/hare_lex.ssa -t $(HARECACHE)/hare_lex.td.tmp -N hare::lex $(hare_lex_ha)

hare_ast_ha = hare/ast/decl.ha hare/ast/expr.ha hare/ast/ident.ha hare/ast/import.ha hare/ast/type.ha hare/ast/unit.ha
$(HARECACHE)/hare_ast.ssa: $(hare_ast_ha) $(HARECACHE)/hare_lex.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/hare_ast.ssa -t $(HARECACHE)/hare_ast.td.tmp -N hare::ast $(hare_ast_ha)

hare_parse_ha = hare/parse/decl.ha hare/parse/expr.ha hare/parse/ident.ha hare/parse/import.ha hare/parse/parse.ha hare/parse/type.ha hare/parse/unit.ha
$(HARECACHE)/hare_parse.ssa: $(hare_parse_ha) $(HARECACHE)/ascii.td $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/hare_parse.ssa -t $(HARECACHE)/hare_parse.td.tmp -N hare::parse $(hare_parse_ha)

hare_unparse_ha = hare/unparse/decl.ha hare/unparse/expr.ha hare/unparse/ident.ha hare/unparse/import.ha hare/unparse/type.ha hare/unparse/unit.ha hare/unparse/util.ha
$(HARECACHE)/hare_unparse.ssa: $(hare_unparse_ha) $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/hare_unparse.ssa -t $(HARECACHE)/hare_unparse.td.tmp -N hare::unparse $(hare_unparse_ha)

time_chrono_ha = time/chrono/+freebsd.ha time/chrono/arithmetic.ha time/chrono/chronology.ha time/chrono/error.ha time/chrono/leapsec.ha time/chrono/timescale.ha time/chrono/timezone.ha time/chrono/tzdb.ha
$(HARECACHE)/time_chrono.ssa: $(time_chrono_ha) $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/endian.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/time_chrono.ssa -t $(HARECACHE)/time_chrono.td.tmp -N time::chrono $(time_chrono_ha)

time_date_ha = time/date/date.ha time/date/daydate.ha time/date/daytime.ha time/date/error.ha time/date/format.ha time/date/locality.ha time/date/observe.ha time/date/parithm.ha time/date/parse.ha time/date/period.ha time/date/reckon.ha time/date/tarithm.ha time/date/virtual.ha
$(HARECACHE)/time_date.ssa: $(time_date_ha) $(HARECACHE)/ascii.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/time_date.ssa -t $(HARECACHE)/time_date.td.tmp -N time::date $(time_date_ha)

hare_module_ha = hare/module/cache.ha hare/module/deps.ha hare/module/format.ha hare/module/srcs.ha hare/module/types.ha hare/module/util.ha
$(HARECACHE)/hare_module.ssa: $(hare_module_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_parse.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td $(HARECACHE)/time_date.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/hare_module.ssa -t $(HARECACHE)/hare_module.td.tmp -N hare::module $(hare_module_ha)

unix_ha = unix/+freebsd/getuid.ha unix/+freebsd/groups.ha unix/+freebsd/nice.ha unix/+freebsd/pipe.ha unix/+freebsd/setuid.ha unix/+freebsd/umask.ha
$(HARECACHE)/unix.ssa: $(unix_ha) $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/rt.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/unix.ssa -t $(HARECACHE)/unix.td.tmp -N unix $(unix_ha)

unix_signal_ha = unix/signal/+freebsd.ha unix/signal/types.ha
$(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/io.td $(HARECACHE)/rt.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/unix_signal.ssa -t $(HARECACHE)/unix_signal.td.tmp -N unix::signal $(unix_signal_ha)

os_exec_ha = os/exec/cmd.ha os/exec/exec+freebsd.ha os/exec/process+freebsd.ha os/exec/types.ha
$(HARECACHE)/os_exec.ssa: $(os_exec_ha) $(HARECACHE)/ascii.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td $(HARECACHE)/unix.td $(HARECACHE)/unix_signal.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/os_exec.ssa -t $(HARECACHE)/os_exec.td.tmp -N os::exec $(os_exec_ha)

shlex_ha = shlex/escape.ha shlex/split.ha
$(HARECACHE)/shlex.ssa: $(shlex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/shlex.ssa -t $(HARECACHE)/shlex.td.tmp -N shlex $(shlex_ha)

unix_tty_ha = unix/tty/+freebsd/isatty.ha unix/tty/+freebsd/open.ha unix/tty/+freebsd/pty.ha unix/tty/+freebsd/termios.ha unix/tty/+freebsd/winsize.ha unix/tty/pty_common.ha unix/tty/types.ha
$(HARECACHE)/unix_tty.ssa: $(unix_tty_ha) $(HARECACHE)/bufio.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/types_c.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/unix_tty.ssa -t $(HARECACHE)/unix_tty.td.tmp -N unix::tty $(unix_tty_ha)

cmd_hare_build_ha = cmd/hare/build/gather.ha cmd/hare/build/queue.ha cmd/hare/build/types.ha cmd/hare/build/util.ha
$(HARECACHE)/cmd_hare_build.ssa: $(cmd_hare_build_ha) $(HARECACHE)/crypto_sha256.td $(HARECACHE)/encoding_hex.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/hash.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/shlex.td $(HARECACHE)/sort.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/cmd_hare_build.ssa -t $(HARECACHE)/cmd_hare_build.td.tmp -N cmd::hare::build $(cmd_hare_build_ha)

dirs_ha = dirs/xdg.ha
$(HARECACHE)/dirs.ssa: $(dirs_ha) $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/unix.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/dirs.ssa -t $(HARECACHE)/dirs.td.tmp -N dirs $(dirs_ha)

getopt_ha = getopt/getopts.ha
$(HARECACHE)/getopt.ssa: $(getopt_ha) $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/getopt.ssa -t $(HARECACHE)/getopt.td.tmp -N getopt $(getopt_ha)

cmd_hare_ha = cmd/hare/arch.ha cmd/hare/build.ha cmd/hare/cache.ha cmd/hare/deps.ha cmd/hare/error.ha cmd/hare/main.ha cmd/hare/util.ha cmd/hare/version.ha
$(HARECACHE)/cmd_hare.ssa: $(cmd_hare_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/cmd_hare_build.td $(HARECACHE)/dirs.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/getopt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_parse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/cmd_hare.ssa -t $(HARECACHE)/cmd_hare.td.tmp $(HARE_DEFINES)  $(cmd_hare_ha)
diff --git a/makefiles/freebsd.riscv64.mk b/makefiles/freebsd.riscv64.mk
new file mode 100644
index 00000000..7987723b
--- /dev/null
+++ b/makefiles/freebsd.riscv64.mk
@@ -0,0 +1,250 @@
# generated by cmd/genbootstrap
# DO NOT EDIT BY HAND. run 'make bootstrap' to update
TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_encoding::utf8=$(HARECACHE)/encoding_utf8.td HARE_TD_types=$(HARECACHE)/types.td HARE_TD_bytes=$(HARECACHE)/bytes.td HARE_TD_strings=$(HARECACHE)/strings.td HARE_TD_ascii=$(HARECACHE)/ascii.td HARE_TD_errors=$(HARECACHE)/errors.td HARE_TD_io=$(HARECACHE)/io.td HARE_TD_bufio=$(HARECACHE)/bufio.td HARE_TD_crypto::math=$(HARECACHE)/crypto_math.td HARE_TD_endian=$(HARECACHE)/endian.td HARE_TD_math=$(HARECACHE)/math.td HARE_TD_memio=$(HARECACHE)/memio.td HARE_TD_path=$(HARECACHE)/path.td HARE_TD_time=$(HARECACHE)/time.td HARE_TD_fs=$(HARECACHE)/fs.td HARE_TD_types::c=$(HARECACHE)/types_c.td HARE_TD_os=$(HARECACHE)/os.td HARE_TD_strconv=$(HARECACHE)/strconv.td HARE_TD_fmt=$(HARECACHE)/fmt.td HARE_TD_hash=$(HARECACHE)/hash.td HARE_TD_crypto::sha256=$(HARECACHE)/crypto_sha256.td HARE_TD_encoding::hex=$(HARECACHE)/encoding_hex.td HARE_TD_sort=$(HARECACHE)/sort.td HARE_TD_hare::lex=$(HARECACHE)/hare_lex.td HARE_TD_hare::ast=$(HARECACHE)/hare_ast.td HARE_TD_hare::parse=$(HARECACHE)/hare_parse.td HARE_TD_hare::unparse=$(HARECACHE)/hare_unparse.td HARE_TD_time::chrono=$(HARECACHE)/time_chrono.td HARE_TD_time::date=$(HARECACHE)/time_date.td HARE_TD_hare::module=$(HARECACHE)/hare_module.td HARE_TD_unix=$(HARECACHE)/unix.td HARE_TD_unix::signal=$(HARECACHE)/unix_signal.td HARE_TD_os::exec=$(HARECACHE)/os_exec.td HARE_TD_shlex=$(HARECACHE)/shlex.td HARE_TD_unix::tty=$(HARECACHE)/unix_tty.td HARE_TD_cmd::hare::build=$(HARECACHE)/cmd_hare_build.td HARE_TD_dirs=$(HARECACHE)/dirs.td HARE_TD_getopt=$(HARECACHE)/getopt.td HARE_TD_cmd::hare=$(HARECACHE)/cmd_hare.td
RTSCRIPT = rt/hare.sc
OBJS = $(HARECACHE)/rt.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/types_c.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/time_chrono.o $(HARECACHE)/time_date.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o

rt_ha = rt/+freebsd/+riscv64.ha rt/+freebsd/env.ha rt/+freebsd/errno.ha rt/+freebsd/platform_abort.ha rt/+freebsd/platformstart.ha rt/+freebsd/segmalloc.ha rt/+freebsd/signal.ha rt/+freebsd/socket.ha rt/+freebsd/syscallno.ha rt/+freebsd/syscalls.ha rt/+freebsd/types.ha rt/+riscv64/arch_jmp.ha rt/+riscv64/backtrace.ha rt/+riscv64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/start.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
$(HARECACHE)/rt.ssa: $(rt_ha)
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/rt.ssa -t $(HARECACHE)/rt.td.tmp -N rt $(rt_ha)

rt_s = $(HARECACHE)/rt.s rt/+freebsd/start+riscv64-libc.s rt/+freebsd/syscall+riscv64.s rt/+riscv64/cpuid.s rt/+riscv64/fenv.s rt/+riscv64/getfp.s rt/+riscv64/longjmp.s rt/+riscv64/restore.s rt/+riscv64/setjmp.s
$(HARECACHE)/rt.o: $(rt_s)
	@printf 'AS\t%s\n' "$@"
	@$(AS) $(ASFLAGS) -o $@ $(rt_s)

encoding_utf8_ha = encoding/utf8/decode.ha encoding/utf8/decodetable.ha encoding/utf8/encode.ha encoding/utf8/rune.ha
$(HARECACHE)/encoding_utf8.ssa: $(encoding_utf8_ha)
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/encoding_utf8.ssa -t $(HARECACHE)/encoding_utf8.td.tmp -N encoding::utf8 $(encoding_utf8_ha)

types_ha = types/arch+riscv64.ha types/classes.ha types/limits.ha
$(HARECACHE)/types.ssa: $(types_ha)
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/types.ssa -t $(HARECACHE)/types.td.tmp -N types $(types_ha)

bytes_ha = bytes/contains.ha bytes/equal.ha bytes/index.ha bytes/reverse.ha bytes/tokenize.ha bytes/trim.ha bytes/two_way.ha bytes/zero.ha
$(HARECACHE)/bytes.ssa: $(bytes_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/bytes.ssa -t $(HARECACHE)/bytes.td.tmp -N bytes $(bytes_ha)

strings_ha = strings/compare.ha strings/concat.ha strings/contains.ha strings/dup.ha strings/index.ha strings/iter.ha strings/pad.ha strings/replace.ha strings/runes.ha strings/sub.ha strings/suffix.ha strings/tokenize.ha strings/trim.ha strings/utf8.ha
$(HARECACHE)/strings.ssa: $(strings_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/strings.ssa -t $(HARECACHE)/strings.td.tmp -N strings $(strings_ha)

ascii_ha = ascii/ctype.ha ascii/string.ha ascii/valid.ha
$(HARECACHE)/ascii.ssa: $(ascii_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/ascii.ssa -t $(HARECACHE)/ascii.td.tmp -N ascii $(ascii_ha)

errors_ha = errors/common.ha errors/opaque.ha errors/rt.ha errors/string.ha
$(HARECACHE)/errors.ssa: $(errors_ha) $(HARECACHE)/rt.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/errors.ssa -t $(HARECACHE)/errors.td.tmp -N errors $(errors_ha)

io_ha = io/+freebsd/mmap.ha io/+freebsd/platform_file.ha io/+freebsd/vector.ha io/arch+riscv64.ha io/copy.ha io/drain.ha io/empty.ha io/file.ha io/handle.ha io/limit.ha io/stream.ha io/tee.ha io/types.ha io/util.ha io/zero.ha
$(HARECACHE)/io.ssa: $(io_ha) $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/rt.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/io.ssa -t $(HARECACHE)/io.td.tmp -N io $(io_ha)

bufio_ha = bufio/scanner.ha bufio/stream.ha
$(HARECACHE)/bufio.ssa: $(bufio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/bufio.ssa -t $(HARECACHE)/bufio.td.tmp -N bufio $(bufio_ha)

crypto_math_ha = crypto/math/arithm.ha crypto/math/bits.ha
$(HARECACHE)/crypto_math.ssa: $(crypto_math_ha)
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/crypto_math.ssa -t $(HARECACHE)/crypto_math.td.tmp -N crypto::math $(crypto_math_ha)

endian_ha = endian/big.ha endian/endian.ha endian/host+riscv64.ha endian/little.ha endian/network.ha
$(HARECACHE)/endian.ssa: $(endian_ha)
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/endian.ssa -t $(HARECACHE)/endian.td.tmp -N endian $(endian_ha)

math_ha = math/fenv+riscv64.ha math/fenv_func.ha math/floats.ha math/ints.ha math/math.ha math/trig.ha math/uints.ha
$(HARECACHE)/math.ssa: $(math_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/math.ssa -t $(HARECACHE)/math.td.tmp -N math $(math_ha)

memio_ha = memio/ops.ha memio/stream.ha
$(HARECACHE)/memio.ssa: $(memio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/memio.ssa -t $(HARECACHE)/memio.td.tmp -N memio $(memio_ha)

path_ha = path/+freebsd.ha path/buffer.ha path/error.ha path/ext_stack.ha path/iter.ha path/posix.ha path/prefix.ha path/stack.ha
$(HARECACHE)/path.ssa: $(path_ha) $(HARECACHE)/bytes.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/path.ssa -t $(HARECACHE)/path.td.tmp -N path $(path_ha)

time_ha = time/+freebsd/functions.ha time/arithm.ha time/conv.ha time/types.ha
$(HARECACHE)/time.ssa: $(time_ha) $(HARECACHE)/math.td $(HARECACHE)/rt.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/time.ssa -t $(HARECACHE)/time.td.tmp -N time $(time_ha)

fs_ha = fs/fs.ha fs/types.ha fs/util.ha
$(HARECACHE)/fs.ssa: $(fs_ha) $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/strings.td $(HARECACHE)/time.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/fs.ssa -t $(HARECACHE)/fs.td.tmp -N fs $(fs_ha)

types_c_ha = types/c/arch+riscv64.ha types/c/strings.ha types/c/types.ha
$(HARECACHE)/types_c.ssa: $(types_c_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/types_c.ssa -t $(HARECACHE)/types_c.td.tmp -N types::c $(types_c_ha)

os_ha = os/+freebsd/dirfdfs.ha os/+freebsd/exit.ha os/+freebsd/fs.ha os/+freebsd/platform_environ.ha os/+freebsd/status.ha os/+freebsd/stdfd.ha os/environ.ha os/os.ha
$(HARECACHE)/os.ssa: $(os_ha) $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/os.ssa -t $(HARECACHE)/os.td.tmp -N os $(os_ha)

strconv_ha = strconv/ftos.ha strconv/itos.ha strconv/numeric.ha strconv/stof.ha strconv/stof_data.ha strconv/stoi.ha strconv/stou.ha strconv/types.ha strconv/utos.ha
$(HARECACHE)/strconv.ssa: $(strconv_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/math.td $(HARECACHE)/strings.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/strconv.ssa -t $(HARECACHE)/strconv.td.tmp -N strconv $(strconv_ha)

fmt_ha = fmt/fmt.ha
$(HARECACHE)/fmt.ssa: $(fmt_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/fmt.ssa -t $(HARECACHE)/fmt.td.tmp -N fmt $(fmt_ha)

hash_ha = hash/hash.ha
$(HARECACHE)/hash.ssa: $(hash_ha) $(HARECACHE)/fmt.td $(HARECACHE)/io.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/hash.ssa -t $(HARECACHE)/hash.td.tmp -N hash $(hash_ha)

crypto_sha256_ha = crypto/sha256/sha256.ha
$(HARECACHE)/crypto_sha256.ssa: $(crypto_sha256_ha) $(HARECACHE)/bytes.td $(HARECACHE)/crypto_math.td $(HARECACHE)/endian.td $(HARECACHE)/hash.td $(HARECACHE)/io.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/crypto_sha256.ssa -t $(HARECACHE)/crypto_sha256.td.tmp -N crypto::sha256 $(crypto_sha256_ha)

encoding_hex_ha = encoding/hex/hex.ha
$(HARECACHE)/encoding_hex.ssa: $(encoding_hex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/encoding_hex.ssa -t $(HARECACHE)/encoding_hex.td.tmp -N encoding::hex $(encoding_hex_ha)

sort_ha = sort/bisect.ha sort/search.ha sort/sort.ha sort/types.ha
$(HARECACHE)/sort.ssa: $(sort_ha) $(HARECACHE)/math.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/sort.ssa -t $(HARECACHE)/sort.td.tmp -N sort $(sort_ha)

hare_lex_ha = hare/lex/lex.ha hare/lex/token.ha
$(HARECACHE)/hare_lex.ssa: $(hare_lex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/hare_lex.ssa -t $(HARECACHE)/hare_lex.td.tmp -N hare::lex $(hare_lex_ha)

hare_ast_ha = hare/ast/decl.ha hare/ast/expr.ha hare/ast/ident.ha hare/ast/import.ha hare/ast/type.ha hare/ast/unit.ha
$(HARECACHE)/hare_ast.ssa: $(hare_ast_ha) $(HARECACHE)/hare_lex.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/hare_ast.ssa -t $(HARECACHE)/hare_ast.td.tmp -N hare::ast $(hare_ast_ha)

hare_parse_ha = hare/parse/decl.ha hare/parse/expr.ha hare/parse/ident.ha hare/parse/import.ha hare/parse/parse.ha hare/parse/type.ha hare/parse/unit.ha
$(HARECACHE)/hare_parse.ssa: $(hare_parse_ha) $(HARECACHE)/ascii.td $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/hare_parse.ssa -t $(HARECACHE)/hare_parse.td.tmp -N hare::parse $(hare_parse_ha)

hare_unparse_ha = hare/unparse/decl.ha hare/unparse/expr.ha hare/unparse/ident.ha hare/unparse/import.ha hare/unparse/type.ha hare/unparse/unit.ha hare/unparse/util.ha
$(HARECACHE)/hare_unparse.ssa: $(hare_unparse_ha) $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/hare_unparse.ssa -t $(HARECACHE)/hare_unparse.td.tmp -N hare::unparse $(hare_unparse_ha)

time_chrono_ha = time/chrono/+freebsd.ha time/chrono/arithmetic.ha time/chrono/chronology.ha time/chrono/error.ha time/chrono/leapsec.ha time/chrono/timescale.ha time/chrono/timezone.ha time/chrono/tzdb.ha
$(HARECACHE)/time_chrono.ssa: $(time_chrono_ha) $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/endian.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/time_chrono.ssa -t $(HARECACHE)/time_chrono.td.tmp -N time::chrono $(time_chrono_ha)

time_date_ha = time/date/date.ha time/date/daydate.ha time/date/daytime.ha time/date/error.ha time/date/format.ha time/date/locality.ha time/date/observe.ha time/date/parithm.ha time/date/parse.ha time/date/period.ha time/date/reckon.ha time/date/tarithm.ha time/date/virtual.ha
$(HARECACHE)/time_date.ssa: $(time_date_ha) $(HARECACHE)/ascii.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/time_date.ssa -t $(HARECACHE)/time_date.td.tmp -N time::date $(time_date_ha)

hare_module_ha = hare/module/cache.ha hare/module/deps.ha hare/module/format.ha hare/module/srcs.ha hare/module/types.ha hare/module/util.ha
$(HARECACHE)/hare_module.ssa: $(hare_module_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_parse.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td $(HARECACHE)/time_date.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/hare_module.ssa -t $(HARECACHE)/hare_module.td.tmp -N hare::module $(hare_module_ha)

unix_ha = unix/+freebsd/getuid.ha unix/+freebsd/groups.ha unix/+freebsd/nice.ha unix/+freebsd/pipe.ha unix/+freebsd/setuid.ha unix/+freebsd/umask.ha
$(HARECACHE)/unix.ssa: $(unix_ha) $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/rt.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/unix.ssa -t $(HARECACHE)/unix.td.tmp -N unix $(unix_ha)

unix_signal_ha = unix/signal/+freebsd.ha unix/signal/types.ha
$(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/io.td $(HARECACHE)/rt.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/unix_signal.ssa -t $(HARECACHE)/unix_signal.td.tmp -N unix::signal $(unix_signal_ha)

os_exec_ha = os/exec/cmd.ha os/exec/exec+freebsd.ha os/exec/process+freebsd.ha os/exec/types.ha
$(HARECACHE)/os_exec.ssa: $(os_exec_ha) $(HARECACHE)/ascii.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td $(HARECACHE)/unix.td $(HARECACHE)/unix_signal.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/os_exec.ssa -t $(HARECACHE)/os_exec.td.tmp -N os::exec $(os_exec_ha)

shlex_ha = shlex/escape.ha shlex/split.ha
$(HARECACHE)/shlex.ssa: $(shlex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/shlex.ssa -t $(HARECACHE)/shlex.td.tmp -N shlex $(shlex_ha)

unix_tty_ha = unix/tty/+freebsd/isatty.ha unix/tty/+freebsd/open.ha unix/tty/+freebsd/pty.ha unix/tty/+freebsd/termios.ha unix/tty/+freebsd/winsize.ha unix/tty/pty_common.ha unix/tty/types.ha
$(HARECACHE)/unix_tty.ssa: $(unix_tty_ha) $(HARECACHE)/bufio.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/types_c.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/unix_tty.ssa -t $(HARECACHE)/unix_tty.td.tmp -N unix::tty $(unix_tty_ha)

cmd_hare_build_ha = cmd/hare/build/gather.ha cmd/hare/build/queue.ha cmd/hare/build/types.ha cmd/hare/build/util.ha
$(HARECACHE)/cmd_hare_build.ssa: $(cmd_hare_build_ha) $(HARECACHE)/crypto_sha256.td $(HARECACHE)/encoding_hex.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/hash.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/shlex.td $(HARECACHE)/sort.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/cmd_hare_build.ssa -t $(HARECACHE)/cmd_hare_build.td.tmp -N cmd::hare::build $(cmd_hare_build_ha)

dirs_ha = dirs/xdg.ha
$(HARECACHE)/dirs.ssa: $(dirs_ha) $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/unix.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/dirs.ssa -t $(HARECACHE)/dirs.td.tmp -N dirs $(dirs_ha)

getopt_ha = getopt/getopts.ha
$(HARECACHE)/getopt.ssa: $(getopt_ha) $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/getopt.ssa -t $(HARECACHE)/getopt.td.tmp -N getopt $(getopt_ha)

cmd_hare_ha = cmd/hare/arch.ha cmd/hare/build.ha cmd/hare/cache.ha cmd/hare/deps.ha cmd/hare/error.ha cmd/hare/main.ha cmd/hare/util.ha cmd/hare/version.ha
$(HARECACHE)/cmd_hare.ssa: $(cmd_hare_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/cmd_hare_build.td $(HARECACHE)/dirs.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/getopt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_parse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/cmd_hare.ssa -t $(HARECACHE)/cmd_hare.td.tmp $(HARE_DEFINES)  $(cmd_hare_ha)
diff --git a/makefiles/freebsd.x86_64.mk b/makefiles/freebsd.x86_64.mk
new file mode 100644
index 00000000..dc61b331
--- /dev/null
+++ b/makefiles/freebsd.x86_64.mk
@@ -0,0 +1,250 @@
# generated by cmd/genbootstrap
# DO NOT EDIT BY HAND. run 'make bootstrap' to update
TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_encoding::utf8=$(HARECACHE)/encoding_utf8.td HARE_TD_types=$(HARECACHE)/types.td HARE_TD_bytes=$(HARECACHE)/bytes.td HARE_TD_strings=$(HARECACHE)/strings.td HARE_TD_ascii=$(HARECACHE)/ascii.td HARE_TD_errors=$(HARECACHE)/errors.td HARE_TD_io=$(HARECACHE)/io.td HARE_TD_bufio=$(HARECACHE)/bufio.td HARE_TD_crypto::math=$(HARECACHE)/crypto_math.td HARE_TD_endian=$(HARECACHE)/endian.td HARE_TD_math=$(HARECACHE)/math.td HARE_TD_memio=$(HARECACHE)/memio.td HARE_TD_path=$(HARECACHE)/path.td HARE_TD_time=$(HARECACHE)/time.td HARE_TD_fs=$(HARECACHE)/fs.td HARE_TD_types::c=$(HARECACHE)/types_c.td HARE_TD_os=$(HARECACHE)/os.td HARE_TD_strconv=$(HARECACHE)/strconv.td HARE_TD_fmt=$(HARECACHE)/fmt.td HARE_TD_hash=$(HARECACHE)/hash.td HARE_TD_crypto::sha256=$(HARECACHE)/crypto_sha256.td HARE_TD_encoding::hex=$(HARECACHE)/encoding_hex.td HARE_TD_sort=$(HARECACHE)/sort.td HARE_TD_hare::lex=$(HARECACHE)/hare_lex.td HARE_TD_hare::ast=$(HARECACHE)/hare_ast.td HARE_TD_hare::parse=$(HARECACHE)/hare_parse.td HARE_TD_hare::unparse=$(HARECACHE)/hare_unparse.td HARE_TD_time::chrono=$(HARECACHE)/time_chrono.td HARE_TD_time::date=$(HARECACHE)/time_date.td HARE_TD_hare::module=$(HARECACHE)/hare_module.td HARE_TD_unix=$(HARECACHE)/unix.td HARE_TD_unix::signal=$(HARECACHE)/unix_signal.td HARE_TD_os::exec=$(HARECACHE)/os_exec.td HARE_TD_shlex=$(HARECACHE)/shlex.td HARE_TD_unix::tty=$(HARECACHE)/unix_tty.td HARE_TD_cmd::hare::build=$(HARECACHE)/cmd_hare_build.td HARE_TD_dirs=$(HARECACHE)/dirs.td HARE_TD_getopt=$(HARECACHE)/getopt.td HARE_TD_cmd::hare=$(HARECACHE)/cmd_hare.td
RTSCRIPT = rt/hare.sc
OBJS = $(HARECACHE)/rt.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/types_c.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/time_chrono.o $(HARECACHE)/time_date.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o

rt_ha = rt/+freebsd/+x86_64.ha rt/+freebsd/env.ha rt/+freebsd/errno.ha rt/+freebsd/platform_abort.ha rt/+freebsd/platformstart.ha rt/+freebsd/segmalloc.ha rt/+freebsd/signal.ha rt/+freebsd/socket.ha rt/+freebsd/syscallno.ha rt/+freebsd/syscalls.ha rt/+freebsd/types.ha rt/+x86_64/arch_jmp.ha rt/+x86_64/backtrace.ha rt/+x86_64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/start.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
$(HARECACHE)/rt.ssa: $(rt_ha)
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/rt.ssa -t $(HARECACHE)/rt.td.tmp -N rt $(rt_ha)

rt_s = $(HARECACHE)/rt.s rt/+freebsd/start+x86_64-libc.s rt/+freebsd/syscall+x86_64.s rt/+x86_64/cpuid.s rt/+x86_64/fenv.s rt/+x86_64/getfp.s rt/+x86_64/longjmp.s rt/+x86_64/restore.s rt/+x86_64/setjmp.s
$(HARECACHE)/rt.o: $(rt_s)
	@printf 'AS\t%s\n' "$@"
	@$(AS) $(ASFLAGS) -o $@ $(rt_s)

encoding_utf8_ha = encoding/utf8/decode.ha encoding/utf8/decodetable.ha encoding/utf8/encode.ha encoding/utf8/rune.ha
$(HARECACHE)/encoding_utf8.ssa: $(encoding_utf8_ha)
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/encoding_utf8.ssa -t $(HARECACHE)/encoding_utf8.td.tmp -N encoding::utf8 $(encoding_utf8_ha)

types_ha = types/arch+x86_64.ha types/classes.ha types/limits.ha
$(HARECACHE)/types.ssa: $(types_ha)
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/types.ssa -t $(HARECACHE)/types.td.tmp -N types $(types_ha)

bytes_ha = bytes/contains.ha bytes/equal.ha bytes/index.ha bytes/reverse.ha bytes/tokenize.ha bytes/trim.ha bytes/two_way.ha bytes/zero.ha
$(HARECACHE)/bytes.ssa: $(bytes_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/bytes.ssa -t $(HARECACHE)/bytes.td.tmp -N bytes $(bytes_ha)

strings_ha = strings/compare.ha strings/concat.ha strings/contains.ha strings/dup.ha strings/index.ha strings/iter.ha strings/pad.ha strings/replace.ha strings/runes.ha strings/sub.ha strings/suffix.ha strings/tokenize.ha strings/trim.ha strings/utf8.ha
$(HARECACHE)/strings.ssa: $(strings_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/strings.ssa -t $(HARECACHE)/strings.td.tmp -N strings $(strings_ha)

ascii_ha = ascii/ctype.ha ascii/string.ha ascii/valid.ha
$(HARECACHE)/ascii.ssa: $(ascii_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/ascii.ssa -t $(HARECACHE)/ascii.td.tmp -N ascii $(ascii_ha)

errors_ha = errors/common.ha errors/opaque.ha errors/rt.ha errors/string.ha
$(HARECACHE)/errors.ssa: $(errors_ha) $(HARECACHE)/rt.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/errors.ssa -t $(HARECACHE)/errors.td.tmp -N errors $(errors_ha)

io_ha = io/+freebsd/mmap.ha io/+freebsd/platform_file.ha io/+freebsd/vector.ha io/arch+x86_64.ha io/copy.ha io/drain.ha io/empty.ha io/file.ha io/handle.ha io/limit.ha io/stream.ha io/tee.ha io/types.ha io/util.ha io/zero.ha
$(HARECACHE)/io.ssa: $(io_ha) $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/rt.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/io.ssa -t $(HARECACHE)/io.td.tmp -N io $(io_ha)

bufio_ha = bufio/scanner.ha bufio/stream.ha
$(HARECACHE)/bufio.ssa: $(bufio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/bufio.ssa -t $(HARECACHE)/bufio.td.tmp -N bufio $(bufio_ha)

crypto_math_ha = crypto/math/arithm.ha crypto/math/bits.ha
$(HARECACHE)/crypto_math.ssa: $(crypto_math_ha)
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/crypto_math.ssa -t $(HARECACHE)/crypto_math.td.tmp -N crypto::math $(crypto_math_ha)

endian_ha = endian/big.ha endian/endian.ha endian/host+x86_64.ha endian/little.ha endian/network.ha
$(HARECACHE)/endian.ssa: $(endian_ha)
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/endian.ssa -t $(HARECACHE)/endian.td.tmp -N endian $(endian_ha)

math_ha = math/fenv+x86_64.ha math/fenv_func.ha math/floats.ha math/ints.ha math/math.ha math/trig.ha math/uints.ha
$(HARECACHE)/math.ssa: $(math_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/math.ssa -t $(HARECACHE)/math.td.tmp -N math $(math_ha)

memio_ha = memio/ops.ha memio/stream.ha
$(HARECACHE)/memio.ssa: $(memio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/memio.ssa -t $(HARECACHE)/memio.td.tmp -N memio $(memio_ha)

path_ha = path/+freebsd.ha path/buffer.ha path/error.ha path/ext_stack.ha path/iter.ha path/posix.ha path/prefix.ha path/stack.ha
$(HARECACHE)/path.ssa: $(path_ha) $(HARECACHE)/bytes.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/path.ssa -t $(HARECACHE)/path.td.tmp -N path $(path_ha)

time_ha = time/+freebsd/functions.ha time/arithm.ha time/conv.ha time/types.ha
$(HARECACHE)/time.ssa: $(time_ha) $(HARECACHE)/math.td $(HARECACHE)/rt.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/time.ssa -t $(HARECACHE)/time.td.tmp -N time $(time_ha)

fs_ha = fs/fs.ha fs/types.ha fs/util.ha
$(HARECACHE)/fs.ssa: $(fs_ha) $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/strings.td $(HARECACHE)/time.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/fs.ssa -t $(HARECACHE)/fs.td.tmp -N fs $(fs_ha)

types_c_ha = types/c/arch+x86_64.ha types/c/strings.ha types/c/types.ha
$(HARECACHE)/types_c.ssa: $(types_c_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/types_c.ssa -t $(HARECACHE)/types_c.td.tmp -N types::c $(types_c_ha)

os_ha = os/+freebsd/dirfdfs.ha os/+freebsd/exit.ha os/+freebsd/fs.ha os/+freebsd/platform_environ.ha os/+freebsd/status.ha os/+freebsd/stdfd.ha os/environ.ha os/os.ha
$(HARECACHE)/os.ssa: $(os_ha) $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/os.ssa -t $(HARECACHE)/os.td.tmp -N os $(os_ha)

strconv_ha = strconv/ftos.ha strconv/itos.ha strconv/numeric.ha strconv/stof.ha strconv/stof_data.ha strconv/stoi.ha strconv/stou.ha strconv/types.ha strconv/utos.ha
$(HARECACHE)/strconv.ssa: $(strconv_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/math.td $(HARECACHE)/strings.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/strconv.ssa -t $(HARECACHE)/strconv.td.tmp -N strconv $(strconv_ha)

fmt_ha = fmt/fmt.ha
$(HARECACHE)/fmt.ssa: $(fmt_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/fmt.ssa -t $(HARECACHE)/fmt.td.tmp -N fmt $(fmt_ha)

hash_ha = hash/hash.ha
$(HARECACHE)/hash.ssa: $(hash_ha) $(HARECACHE)/fmt.td $(HARECACHE)/io.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/hash.ssa -t $(HARECACHE)/hash.td.tmp -N hash $(hash_ha)

crypto_sha256_ha = crypto/sha256/sha256.ha
$(HARECACHE)/crypto_sha256.ssa: $(crypto_sha256_ha) $(HARECACHE)/bytes.td $(HARECACHE)/crypto_math.td $(HARECACHE)/endian.td $(HARECACHE)/hash.td $(HARECACHE)/io.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/crypto_sha256.ssa -t $(HARECACHE)/crypto_sha256.td.tmp -N crypto::sha256 $(crypto_sha256_ha)

encoding_hex_ha = encoding/hex/hex.ha
$(HARECACHE)/encoding_hex.ssa: $(encoding_hex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/encoding_hex.ssa -t $(HARECACHE)/encoding_hex.td.tmp -N encoding::hex $(encoding_hex_ha)

sort_ha = sort/bisect.ha sort/search.ha sort/sort.ha sort/types.ha
$(HARECACHE)/sort.ssa: $(sort_ha) $(HARECACHE)/math.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/sort.ssa -t $(HARECACHE)/sort.td.tmp -N sort $(sort_ha)

hare_lex_ha = hare/lex/lex.ha hare/lex/token.ha
$(HARECACHE)/hare_lex.ssa: $(hare_lex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/hare_lex.ssa -t $(HARECACHE)/hare_lex.td.tmp -N hare::lex $(hare_lex_ha)

hare_ast_ha = hare/ast/decl.ha hare/ast/expr.ha hare/ast/ident.ha hare/ast/import.ha hare/ast/type.ha hare/ast/unit.ha
$(HARECACHE)/hare_ast.ssa: $(hare_ast_ha) $(HARECACHE)/hare_lex.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/hare_ast.ssa -t $(HARECACHE)/hare_ast.td.tmp -N hare::ast $(hare_ast_ha)

hare_parse_ha = hare/parse/decl.ha hare/parse/expr.ha hare/parse/ident.ha hare/parse/import.ha hare/parse/parse.ha hare/parse/type.ha hare/parse/unit.ha
$(HARECACHE)/hare_parse.ssa: $(hare_parse_ha) $(HARECACHE)/ascii.td $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/hare_parse.ssa -t $(HARECACHE)/hare_parse.td.tmp -N hare::parse $(hare_parse_ha)

hare_unparse_ha = hare/unparse/decl.ha hare/unparse/expr.ha hare/unparse/ident.ha hare/unparse/import.ha hare/unparse/type.ha hare/unparse/unit.ha hare/unparse/util.ha
$(HARECACHE)/hare_unparse.ssa: $(hare_unparse_ha) $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/hare_unparse.ssa -t $(HARECACHE)/hare_unparse.td.tmp -N hare::unparse $(hare_unparse_ha)

time_chrono_ha = time/chrono/+freebsd.ha time/chrono/arithmetic.ha time/chrono/chronology.ha time/chrono/error.ha time/chrono/leapsec.ha time/chrono/timescale.ha time/chrono/timezone.ha time/chrono/tzdb.ha
$(HARECACHE)/time_chrono.ssa: $(time_chrono_ha) $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/endian.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/time_chrono.ssa -t $(HARECACHE)/time_chrono.td.tmp -N time::chrono $(time_chrono_ha)

time_date_ha = time/date/date.ha time/date/daydate.ha time/date/daytime.ha time/date/error.ha time/date/format.ha time/date/locality.ha time/date/observe.ha time/date/parithm.ha time/date/parse.ha time/date/period.ha time/date/reckon.ha time/date/tarithm.ha time/date/virtual.ha
$(HARECACHE)/time_date.ssa: $(time_date_ha) $(HARECACHE)/ascii.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/time_date.ssa -t $(HARECACHE)/time_date.td.tmp -N time::date $(time_date_ha)

hare_module_ha = hare/module/cache.ha hare/module/deps.ha hare/module/format.ha hare/module/srcs.ha hare/module/types.ha hare/module/util.ha
$(HARECACHE)/hare_module.ssa: $(hare_module_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_parse.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td $(HARECACHE)/time_date.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/hare_module.ssa -t $(HARECACHE)/hare_module.td.tmp -N hare::module $(hare_module_ha)

unix_ha = unix/+freebsd/getuid.ha unix/+freebsd/groups.ha unix/+freebsd/nice.ha unix/+freebsd/pipe.ha unix/+freebsd/setuid.ha unix/+freebsd/umask.ha
$(HARECACHE)/unix.ssa: $(unix_ha) $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/rt.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/unix.ssa -t $(HARECACHE)/unix.td.tmp -N unix $(unix_ha)

unix_signal_ha = unix/signal/+freebsd.ha unix/signal/types.ha
$(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/io.td $(HARECACHE)/rt.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/unix_signal.ssa -t $(HARECACHE)/unix_signal.td.tmp -N unix::signal $(unix_signal_ha)

os_exec_ha = os/exec/cmd.ha os/exec/exec+freebsd.ha os/exec/process+freebsd.ha os/exec/types.ha
$(HARECACHE)/os_exec.ssa: $(os_exec_ha) $(HARECACHE)/ascii.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td $(HARECACHE)/unix.td $(HARECACHE)/unix_signal.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/os_exec.ssa -t $(HARECACHE)/os_exec.td.tmp -N os::exec $(os_exec_ha)

shlex_ha = shlex/escape.ha shlex/split.ha
$(HARECACHE)/shlex.ssa: $(shlex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/shlex.ssa -t $(HARECACHE)/shlex.td.tmp -N shlex $(shlex_ha)

unix_tty_ha = unix/tty/+freebsd/isatty.ha unix/tty/+freebsd/open.ha unix/tty/+freebsd/pty.ha unix/tty/+freebsd/termios.ha unix/tty/+freebsd/winsize.ha unix/tty/pty_common.ha unix/tty/types.ha
$(HARECACHE)/unix_tty.ssa: $(unix_tty_ha) $(HARECACHE)/bufio.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/types_c.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/unix_tty.ssa -t $(HARECACHE)/unix_tty.td.tmp -N unix::tty $(unix_tty_ha)

cmd_hare_build_ha = cmd/hare/build/gather.ha cmd/hare/build/queue.ha cmd/hare/build/types.ha cmd/hare/build/util.ha
$(HARECACHE)/cmd_hare_build.ssa: $(cmd_hare_build_ha) $(HARECACHE)/crypto_sha256.td $(HARECACHE)/encoding_hex.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/hash.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/shlex.td $(HARECACHE)/sort.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/cmd_hare_build.ssa -t $(HARECACHE)/cmd_hare_build.td.tmp -N cmd::hare::build $(cmd_hare_build_ha)

dirs_ha = dirs/xdg.ha
$(HARECACHE)/dirs.ssa: $(dirs_ha) $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/unix.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/dirs.ssa -t $(HARECACHE)/dirs.td.tmp -N dirs $(dirs_ha)

getopt_ha = getopt/getopts.ha
$(HARECACHE)/getopt.ssa: $(getopt_ha) $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/getopt.ssa -t $(HARECACHE)/getopt.td.tmp -N getopt $(getopt_ha)

cmd_hare_ha = cmd/hare/arch.ha cmd/hare/build.ha cmd/hare/cache.ha cmd/hare/deps.ha cmd/hare/error.ha cmd/hare/main.ha cmd/hare/util.ha cmd/hare/version.ha
$(HARECACHE)/cmd_hare.ssa: $(cmd_hare_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/cmd_hare_build.td $(HARECACHE)/dirs.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/getopt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_parse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/cmd_hare.ssa -t $(HARECACHE)/cmd_hare.td.tmp $(HARE_DEFINES)  $(cmd_hare_ha)
diff --git a/makefiles/linux.aarch64.mk b/makefiles/linux.aarch64.mk
new file mode 100644
index 00000000..0c11e232
--- /dev/null
+++ b/makefiles/linux.aarch64.mk
@@ -0,0 +1,268 @@
# generated by cmd/genbootstrap
# DO NOT EDIT BY HAND. run 'make bootstrap' to update
TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_encoding::utf8=$(HARECACHE)/encoding_utf8.td HARE_TD_types=$(HARECACHE)/types.td HARE_TD_bytes=$(HARECACHE)/bytes.td HARE_TD_strings=$(HARECACHE)/strings.td HARE_TD_ascii=$(HARECACHE)/ascii.td HARE_TD_errors=$(HARECACHE)/errors.td HARE_TD_io=$(HARECACHE)/io.td HARE_TD_bufio=$(HARECACHE)/bufio.td HARE_TD_crypto::math=$(HARECACHE)/crypto_math.td HARE_TD_endian=$(HARECACHE)/endian.td HARE_TD_math=$(HARECACHE)/math.td HARE_TD_memio=$(HARECACHE)/memio.td HARE_TD_path=$(HARECACHE)/path.td HARE_TD_format::elf=$(HARECACHE)/format_elf.td HARE_TD_linux=$(HARECACHE)/linux.td HARE_TD_types::c=$(HARECACHE)/types_c.td HARE_TD_linux::vdso=$(HARECACHE)/linux_vdso.td HARE_TD_time=$(HARECACHE)/time.td HARE_TD_fs=$(HARECACHE)/fs.td HARE_TD_os=$(HARECACHE)/os.td HARE_TD_strconv=$(HARECACHE)/strconv.td HARE_TD_fmt=$(HARECACHE)/fmt.td HARE_TD_hash=$(HARECACHE)/hash.td HARE_TD_crypto::sha256=$(HARECACHE)/crypto_sha256.td HARE_TD_encoding::hex=$(HARECACHE)/encoding_hex.td HARE_TD_sort=$(HARECACHE)/sort.td HARE_TD_hare::lex=$(HARECACHE)/hare_lex.td HARE_TD_hare::ast=$(HARECACHE)/hare_ast.td HARE_TD_hare::parse=$(HARECACHE)/hare_parse.td HARE_TD_hare::unparse=$(HARECACHE)/hare_unparse.td HARE_TD_time::chrono=$(HARECACHE)/time_chrono.td HARE_TD_time::date=$(HARECACHE)/time_date.td HARE_TD_hare::module=$(HARECACHE)/hare_module.td HARE_TD_unix=$(HARECACHE)/unix.td HARE_TD_unix::signal=$(HARECACHE)/unix_signal.td HARE_TD_os::exec=$(HARECACHE)/os_exec.td HARE_TD_shlex=$(HARECACHE)/shlex.td HARE_TD_unix::tty=$(HARECACHE)/unix_tty.td HARE_TD_cmd::hare::build=$(HARECACHE)/cmd_hare_build.td HARE_TD_dirs=$(HARECACHE)/dirs.td HARE_TD_getopt=$(HARECACHE)/getopt.td HARE_TD_cmd::hare=$(HARECACHE)/cmd_hare.td
RTSCRIPT = rt/hare.sc
OBJS = $(HARECACHE)/rt.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/format_elf.o $(HARECACHE)/linux.o $(HARECACHE)/types_c.o $(HARECACHE)/linux_vdso.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/time_chrono.o $(HARECACHE)/time_date.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o

rt_ha = rt/+aarch64/arch_jmp.ha rt/+aarch64/backtrace.ha rt/+aarch64/cpuid.ha rt/+linux/+aarch64.ha rt/+linux/env.ha rt/+linux/errno.ha rt/+linux/platform_abort.ha rt/+linux/platformstart-libc.ha rt/+linux/prctl.ha rt/+linux/segmalloc.ha rt/+linux/signal.ha rt/+linux/socket.ha rt/+linux/stat.ha rt/+linux/syscallno+aarch64.ha rt/+linux/syscalls.ha rt/+linux/types.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/start.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
$(HARECACHE)/rt.ssa: $(rt_ha)
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/rt.ssa -t $(HARECACHE)/rt.td.tmp -N rt $(rt_ha)

rt_s = $(HARECACHE)/rt.s rt/+aarch64/cpuid.s rt/+aarch64/fenv.s rt/+aarch64/getfp.s rt/+aarch64/longjmp.s rt/+aarch64/restore.s rt/+aarch64/setjmp.s rt/+linux/start+aarch64-libc.s rt/+linux/syscall+aarch64.s
$(HARECACHE)/rt.o: $(rt_s)
	@printf 'AS\t%s\n' "$@"
	@$(AS) $(ASFLAGS) -o $@ $(rt_s)

encoding_utf8_ha = encoding/utf8/decode.ha encoding/utf8/decodetable.ha encoding/utf8/encode.ha encoding/utf8/rune.ha
$(HARECACHE)/encoding_utf8.ssa: $(encoding_utf8_ha)
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/encoding_utf8.ssa -t $(HARECACHE)/encoding_utf8.td.tmp -N encoding::utf8 $(encoding_utf8_ha)

types_ha = types/arch+aarch64.ha types/classes.ha types/limits.ha
$(HARECACHE)/types.ssa: $(types_ha)
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/types.ssa -t $(HARECACHE)/types.td.tmp -N types $(types_ha)

bytes_ha = bytes/contains.ha bytes/equal.ha bytes/index.ha bytes/reverse.ha bytes/tokenize.ha bytes/trim.ha bytes/two_way.ha bytes/zero.ha
$(HARECACHE)/bytes.ssa: $(bytes_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/bytes.ssa -t $(HARECACHE)/bytes.td.tmp -N bytes $(bytes_ha)

strings_ha = strings/compare.ha strings/concat.ha strings/contains.ha strings/dup.ha strings/index.ha strings/iter.ha strings/pad.ha strings/replace.ha strings/runes.ha strings/sub.ha strings/suffix.ha strings/tokenize.ha strings/trim.ha strings/utf8.ha
$(HARECACHE)/strings.ssa: $(strings_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/strings.ssa -t $(HARECACHE)/strings.td.tmp -N strings $(strings_ha)

ascii_ha = ascii/ctype.ha ascii/string.ha ascii/valid.ha
$(HARECACHE)/ascii.ssa: $(ascii_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/ascii.ssa -t $(HARECACHE)/ascii.td.tmp -N ascii $(ascii_ha)

errors_ha = errors/common.ha errors/opaque.ha errors/rt.ha errors/string.ha
$(HARECACHE)/errors.ssa: $(errors_ha) $(HARECACHE)/rt.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/errors.ssa -t $(HARECACHE)/errors.td.tmp -N errors $(errors_ha)

io_ha = io/+linux/mmap.ha io/+linux/platform_file.ha io/+linux/vector.ha io/arch+aarch64.ha io/copy.ha io/drain.ha io/empty.ha io/file.ha io/handle.ha io/limit.ha io/stream.ha io/tee.ha io/types.ha io/util.ha io/zero.ha
$(HARECACHE)/io.ssa: $(io_ha) $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/rt.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/io.ssa -t $(HARECACHE)/io.td.tmp -N io $(io_ha)

bufio_ha = bufio/scanner.ha bufio/stream.ha
$(HARECACHE)/bufio.ssa: $(bufio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/bufio.ssa -t $(HARECACHE)/bufio.td.tmp -N bufio $(bufio_ha)

crypto_math_ha = crypto/math/arithm.ha crypto/math/bits.ha
$(HARECACHE)/crypto_math.ssa: $(crypto_math_ha)
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/crypto_math.ssa -t $(HARECACHE)/crypto_math.td.tmp -N crypto::math $(crypto_math_ha)

endian_ha = endian/big.ha endian/endian.ha endian/host+aarch64.ha endian/little.ha endian/network.ha
$(HARECACHE)/endian.ssa: $(endian_ha)
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/endian.ssa -t $(HARECACHE)/endian.td.tmp -N endian $(endian_ha)

math_ha = math/fenv+aarch64.ha math/fenv_func.ha math/floats.ha math/ints.ha math/math.ha math/trig.ha math/uints.ha
$(HARECACHE)/math.ssa: $(math_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/math.ssa -t $(HARECACHE)/math.td.tmp -N math $(math_ha)

memio_ha = memio/ops.ha memio/stream.ha
$(HARECACHE)/memio.ssa: $(memio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/memio.ssa -t $(HARECACHE)/memio.td.tmp -N memio $(memio_ha)

path_ha = path/+linux.ha path/buffer.ha path/error.ha path/ext_stack.ha path/iter.ha path/posix.ha path/prefix.ha path/stack.ha
$(HARECACHE)/path.ssa: $(path_ha) $(HARECACHE)/bytes.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/path.ssa -t $(HARECACHE)/path.td.tmp -N path $(path_ha)

format_elf_ha = format/elf/arch+aarch64.ha format/elf/platform+linux.ha format/elf/types.ha
$(HARECACHE)/format_elf.ssa: $(format_elf_ha)
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/format_elf.ssa -t $(HARECACHE)/format_elf.td.tmp -N format::elf $(format_elf_ha)

linux_ha = linux/env.ha linux/start.ha
$(HARECACHE)/linux.ssa: $(linux_ha) $(HARECACHE)/format_elf.td $(HARECACHE)/rt.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/linux.ssa -t $(HARECACHE)/linux.td.tmp -N linux $(linux_ha)

types_c_ha = types/c/arch+aarch64.ha types/c/strings.ha types/c/types.ha
$(HARECACHE)/types_c.ssa: $(types_c_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/types_c.ssa -t $(HARECACHE)/types_c.td.tmp -N types::c $(types_c_ha)

linux_vdso_ha = linux/vdso/vdso.ha
$(HARECACHE)/linux_vdso.ssa: $(linux_vdso_ha) $(HARECACHE)/format_elf.td $(HARECACHE)/linux.td $(HARECACHE)/types_c.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/linux_vdso.ssa -t $(HARECACHE)/linux_vdso.td.tmp -N linux::vdso $(linux_vdso_ha)

time_ha = time/+linux/+aarch64.ha time/+linux/functions.ha time/arithm.ha time/conv.ha time/types.ha
$(HARECACHE)/time.ssa: $(time_ha) $(HARECACHE)/linux_vdso.td $(HARECACHE)/math.td $(HARECACHE)/rt.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/time.ssa -t $(HARECACHE)/time.td.tmp -N time $(time_ha)

fs_ha = fs/fs.ha fs/types.ha fs/util.ha
$(HARECACHE)/fs.ssa: $(fs_ha) $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/strings.td $(HARECACHE)/time.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/fs.ssa -t $(HARECACHE)/fs.td.tmp -N fs $(fs_ha)

os_ha = os/+linux/dirfdfs.ha os/+linux/exit.ha os/+linux/fs.ha os/+linux/memory.ha os/+linux/platform_environ.ha os/+linux/status.ha os/+linux/stdfd.ha os/environ.ha os/os.ha
$(HARECACHE)/os.ssa: $(os_ha) $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/os.ssa -t $(HARECACHE)/os.td.tmp -N os $(os_ha)

strconv_ha = strconv/ftos.ha strconv/itos.ha strconv/numeric.ha strconv/stof.ha strconv/stof_data.ha strconv/stoi.ha strconv/stou.ha strconv/types.ha strconv/utos.ha
$(HARECACHE)/strconv.ssa: $(strconv_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/math.td $(HARECACHE)/strings.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/strconv.ssa -t $(HARECACHE)/strconv.td.tmp -N strconv $(strconv_ha)

fmt_ha = fmt/fmt.ha
$(HARECACHE)/fmt.ssa: $(fmt_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/fmt.ssa -t $(HARECACHE)/fmt.td.tmp -N fmt $(fmt_ha)

hash_ha = hash/hash.ha
$(HARECACHE)/hash.ssa: $(hash_ha) $(HARECACHE)/fmt.td $(HARECACHE)/io.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/hash.ssa -t $(HARECACHE)/hash.td.tmp -N hash $(hash_ha)

crypto_sha256_ha = crypto/sha256/sha256.ha
$(HARECACHE)/crypto_sha256.ssa: $(crypto_sha256_ha) $(HARECACHE)/bytes.td $(HARECACHE)/crypto_math.td $(HARECACHE)/endian.td $(HARECACHE)/hash.td $(HARECACHE)/io.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/crypto_sha256.ssa -t $(HARECACHE)/crypto_sha256.td.tmp -N crypto::sha256 $(crypto_sha256_ha)

encoding_hex_ha = encoding/hex/hex.ha
$(HARECACHE)/encoding_hex.ssa: $(encoding_hex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/encoding_hex.ssa -t $(HARECACHE)/encoding_hex.td.tmp -N encoding::hex $(encoding_hex_ha)

sort_ha = sort/bisect.ha sort/search.ha sort/sort.ha sort/types.ha
$(HARECACHE)/sort.ssa: $(sort_ha) $(HARECACHE)/math.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/sort.ssa -t $(HARECACHE)/sort.td.tmp -N sort $(sort_ha)

hare_lex_ha = hare/lex/lex.ha hare/lex/token.ha
$(HARECACHE)/hare_lex.ssa: $(hare_lex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/hare_lex.ssa -t $(HARECACHE)/hare_lex.td.tmp -N hare::lex $(hare_lex_ha)

hare_ast_ha = hare/ast/decl.ha hare/ast/expr.ha hare/ast/ident.ha hare/ast/import.ha hare/ast/type.ha hare/ast/unit.ha
$(HARECACHE)/hare_ast.ssa: $(hare_ast_ha) $(HARECACHE)/hare_lex.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/hare_ast.ssa -t $(HARECACHE)/hare_ast.td.tmp -N hare::ast $(hare_ast_ha)

hare_parse_ha = hare/parse/decl.ha hare/parse/expr.ha hare/parse/ident.ha hare/parse/import.ha hare/parse/parse.ha hare/parse/type.ha hare/parse/unit.ha
$(HARECACHE)/hare_parse.ssa: $(hare_parse_ha) $(HARECACHE)/ascii.td $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/hare_parse.ssa -t $(HARECACHE)/hare_parse.td.tmp -N hare::parse $(hare_parse_ha)

hare_unparse_ha = hare/unparse/decl.ha hare/unparse/expr.ha hare/unparse/ident.ha hare/unparse/import.ha hare/unparse/type.ha hare/unparse/unit.ha hare/unparse/util.ha
$(HARECACHE)/hare_unparse.ssa: $(hare_unparse_ha) $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/hare_unparse.ssa -t $(HARECACHE)/hare_unparse.td.tmp -N hare::unparse $(hare_unparse_ha)

time_chrono_ha = time/chrono/+linux.ha time/chrono/arithmetic.ha time/chrono/chronology.ha time/chrono/error.ha time/chrono/leapsec.ha time/chrono/timescale.ha time/chrono/timezone.ha time/chrono/tzdb.ha
$(HARECACHE)/time_chrono.ssa: $(time_chrono_ha) $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/endian.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/time_chrono.ssa -t $(HARECACHE)/time_chrono.td.tmp -N time::chrono $(time_chrono_ha)

time_date_ha = time/date/date.ha time/date/daydate.ha time/date/daytime.ha time/date/error.ha time/date/format.ha time/date/locality.ha time/date/observe.ha time/date/parithm.ha time/date/parse.ha time/date/period.ha time/date/reckon.ha time/date/tarithm.ha time/date/virtual.ha
$(HARECACHE)/time_date.ssa: $(time_date_ha) $(HARECACHE)/ascii.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/time_date.ssa -t $(HARECACHE)/time_date.td.tmp -N time::date $(time_date_ha)

hare_module_ha = hare/module/cache.ha hare/module/deps.ha hare/module/format.ha hare/module/srcs.ha hare/module/types.ha hare/module/util.ha
$(HARECACHE)/hare_module.ssa: $(hare_module_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_parse.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td $(HARECACHE)/time_date.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/hare_module.ssa -t $(HARECACHE)/hare_module.td.tmp -N hare::module $(hare_module_ha)

unix_ha = unix/+linux/getuid.ha unix/+linux/groups.ha unix/+linux/nice.ha unix/+linux/pipe.ha unix/+linux/setuid.ha unix/+linux/umask.ha
$(HARECACHE)/unix.ssa: $(unix_ha) $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/rt.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/unix.ssa -t $(HARECACHE)/unix.td.tmp -N unix $(unix_ha)

unix_signal_ha = unix/signal/+linux.ha unix/signal/types.ha
$(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/rt.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/unix_signal.ssa -t $(HARECACHE)/unix_signal.td.tmp -N unix::signal $(unix_signal_ha)

os_exec_ha = os/exec/cmd.ha os/exec/exec+linux.ha os/exec/process+linux.ha os/exec/types.ha
$(HARECACHE)/os_exec.ssa: $(os_exec_ha) $(HARECACHE)/ascii.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td $(HARECACHE)/unix.td $(HARECACHE)/unix_signal.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/os_exec.ssa -t $(HARECACHE)/os_exec.td.tmp -N os::exec $(os_exec_ha)

shlex_ha = shlex/escape.ha shlex/split.ha
$(HARECACHE)/shlex.ssa: $(shlex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/shlex.ssa -t $(HARECACHE)/shlex.td.tmp -N shlex $(shlex_ha)

unix_tty_ha = unix/tty/+linux/isatty.ha unix/tty/+linux/open.ha unix/tty/+linux/pty.ha unix/tty/+linux/termios.ha unix/tty/+linux/winsize.ha unix/tty/pty_common.ha unix/tty/types.ha
$(HARECACHE)/unix_tty.ssa: $(unix_tty_ha) $(HARECACHE)/bufio.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/unix_tty.ssa -t $(HARECACHE)/unix_tty.td.tmp -N unix::tty $(unix_tty_ha)

cmd_hare_build_ha = cmd/hare/build/gather.ha cmd/hare/build/queue.ha cmd/hare/build/types.ha cmd/hare/build/util.ha
$(HARECACHE)/cmd_hare_build.ssa: $(cmd_hare_build_ha) $(HARECACHE)/crypto_sha256.td $(HARECACHE)/encoding_hex.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/hash.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/shlex.td $(HARECACHE)/sort.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/cmd_hare_build.ssa -t $(HARECACHE)/cmd_hare_build.td.tmp -N cmd::hare::build $(cmd_hare_build_ha)

dirs_ha = dirs/xdg.ha
$(HARECACHE)/dirs.ssa: $(dirs_ha) $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/unix.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/dirs.ssa -t $(HARECACHE)/dirs.td.tmp -N dirs $(dirs_ha)

getopt_ha = getopt/getopts.ha
$(HARECACHE)/getopt.ssa: $(getopt_ha) $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/getopt.ssa -t $(HARECACHE)/getopt.td.tmp -N getopt $(getopt_ha)

cmd_hare_ha = cmd/hare/arch.ha cmd/hare/build.ha cmd/hare/cache.ha cmd/hare/deps.ha cmd/hare/error.ha cmd/hare/main.ha cmd/hare/util.ha cmd/hare/version.ha
$(HARECACHE)/cmd_hare.ssa: $(cmd_hare_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/cmd_hare_build.td $(HARECACHE)/dirs.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/getopt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_parse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/cmd_hare.ssa -t $(HARECACHE)/cmd_hare.td.tmp $(HARE_DEFINES)  $(cmd_hare_ha)
diff --git a/makefiles/linux.riscv64.mk b/makefiles/linux.riscv64.mk
new file mode 100644
index 00000000..f334007f
--- /dev/null
+++ b/makefiles/linux.riscv64.mk
@@ -0,0 +1,268 @@
# generated by cmd/genbootstrap
# DO NOT EDIT BY HAND. run 'make bootstrap' to update
TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_encoding::utf8=$(HARECACHE)/encoding_utf8.td HARE_TD_types=$(HARECACHE)/types.td HARE_TD_bytes=$(HARECACHE)/bytes.td HARE_TD_strings=$(HARECACHE)/strings.td HARE_TD_ascii=$(HARECACHE)/ascii.td HARE_TD_errors=$(HARECACHE)/errors.td HARE_TD_io=$(HARECACHE)/io.td HARE_TD_bufio=$(HARECACHE)/bufio.td HARE_TD_crypto::math=$(HARECACHE)/crypto_math.td HARE_TD_endian=$(HARECACHE)/endian.td HARE_TD_math=$(HARECACHE)/math.td HARE_TD_memio=$(HARECACHE)/memio.td HARE_TD_path=$(HARECACHE)/path.td HARE_TD_format::elf=$(HARECACHE)/format_elf.td HARE_TD_linux=$(HARECACHE)/linux.td HARE_TD_types::c=$(HARECACHE)/types_c.td HARE_TD_linux::vdso=$(HARECACHE)/linux_vdso.td HARE_TD_time=$(HARECACHE)/time.td HARE_TD_fs=$(HARECACHE)/fs.td HARE_TD_os=$(HARECACHE)/os.td HARE_TD_strconv=$(HARECACHE)/strconv.td HARE_TD_fmt=$(HARECACHE)/fmt.td HARE_TD_hash=$(HARECACHE)/hash.td HARE_TD_crypto::sha256=$(HARECACHE)/crypto_sha256.td HARE_TD_encoding::hex=$(HARECACHE)/encoding_hex.td HARE_TD_sort=$(HARECACHE)/sort.td HARE_TD_hare::lex=$(HARECACHE)/hare_lex.td HARE_TD_hare::ast=$(HARECACHE)/hare_ast.td HARE_TD_hare::parse=$(HARECACHE)/hare_parse.td HARE_TD_hare::unparse=$(HARECACHE)/hare_unparse.td HARE_TD_time::chrono=$(HARECACHE)/time_chrono.td HARE_TD_time::date=$(HARECACHE)/time_date.td HARE_TD_hare::module=$(HARECACHE)/hare_module.td HARE_TD_unix=$(HARECACHE)/unix.td HARE_TD_unix::signal=$(HARECACHE)/unix_signal.td HARE_TD_os::exec=$(HARECACHE)/os_exec.td HARE_TD_shlex=$(HARECACHE)/shlex.td HARE_TD_unix::tty=$(HARECACHE)/unix_tty.td HARE_TD_cmd::hare::build=$(HARECACHE)/cmd_hare_build.td HARE_TD_dirs=$(HARECACHE)/dirs.td HARE_TD_getopt=$(HARECACHE)/getopt.td HARE_TD_cmd::hare=$(HARECACHE)/cmd_hare.td
RTSCRIPT = rt/hare.sc
OBJS = $(HARECACHE)/rt.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/format_elf.o $(HARECACHE)/linux.o $(HARECACHE)/types_c.o $(HARECACHE)/linux_vdso.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/time_chrono.o $(HARECACHE)/time_date.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o

rt_ha = rt/+linux/+riscv64.ha rt/+linux/env.ha rt/+linux/errno.ha rt/+linux/platform_abort.ha rt/+linux/platformstart-libc.ha rt/+linux/prctl.ha rt/+linux/segmalloc.ha rt/+linux/signal.ha rt/+linux/socket.ha rt/+linux/stat.ha rt/+linux/syscallno+riscv64.ha rt/+linux/syscalls.ha rt/+linux/types.ha rt/+riscv64/arch_jmp.ha rt/+riscv64/backtrace.ha rt/+riscv64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/start.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
$(HARECACHE)/rt.ssa: $(rt_ha)
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/rt.ssa -t $(HARECACHE)/rt.td.tmp -N rt $(rt_ha)

rt_s = $(HARECACHE)/rt.s rt/+linux/start+riscv64-libc.s rt/+linux/syscall+riscv64.s rt/+riscv64/cpuid.s rt/+riscv64/fenv.s rt/+riscv64/getfp.s rt/+riscv64/longjmp.s rt/+riscv64/restore.s rt/+riscv64/setjmp.s
$(HARECACHE)/rt.o: $(rt_s)
	@printf 'AS\t%s\n' "$@"
	@$(AS) $(ASFLAGS) -o $@ $(rt_s)

encoding_utf8_ha = encoding/utf8/decode.ha encoding/utf8/decodetable.ha encoding/utf8/encode.ha encoding/utf8/rune.ha
$(HARECACHE)/encoding_utf8.ssa: $(encoding_utf8_ha)
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/encoding_utf8.ssa -t $(HARECACHE)/encoding_utf8.td.tmp -N encoding::utf8 $(encoding_utf8_ha)

types_ha = types/arch+riscv64.ha types/classes.ha types/limits.ha
$(HARECACHE)/types.ssa: $(types_ha)
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/types.ssa -t $(HARECACHE)/types.td.tmp -N types $(types_ha)

bytes_ha = bytes/contains.ha bytes/equal.ha bytes/index.ha bytes/reverse.ha bytes/tokenize.ha bytes/trim.ha bytes/two_way.ha bytes/zero.ha
$(HARECACHE)/bytes.ssa: $(bytes_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/bytes.ssa -t $(HARECACHE)/bytes.td.tmp -N bytes $(bytes_ha)

strings_ha = strings/compare.ha strings/concat.ha strings/contains.ha strings/dup.ha strings/index.ha strings/iter.ha strings/pad.ha strings/replace.ha strings/runes.ha strings/sub.ha strings/suffix.ha strings/tokenize.ha strings/trim.ha strings/utf8.ha
$(HARECACHE)/strings.ssa: $(strings_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/strings.ssa -t $(HARECACHE)/strings.td.tmp -N strings $(strings_ha)

ascii_ha = ascii/ctype.ha ascii/string.ha ascii/valid.ha
$(HARECACHE)/ascii.ssa: $(ascii_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/ascii.ssa -t $(HARECACHE)/ascii.td.tmp -N ascii $(ascii_ha)

errors_ha = errors/common.ha errors/opaque.ha errors/rt.ha errors/string.ha
$(HARECACHE)/errors.ssa: $(errors_ha) $(HARECACHE)/rt.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/errors.ssa -t $(HARECACHE)/errors.td.tmp -N errors $(errors_ha)

io_ha = io/+linux/mmap.ha io/+linux/platform_file.ha io/+linux/vector.ha io/arch+riscv64.ha io/copy.ha io/drain.ha io/empty.ha io/file.ha io/handle.ha io/limit.ha io/stream.ha io/tee.ha io/types.ha io/util.ha io/zero.ha
$(HARECACHE)/io.ssa: $(io_ha) $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/rt.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/io.ssa -t $(HARECACHE)/io.td.tmp -N io $(io_ha)

bufio_ha = bufio/scanner.ha bufio/stream.ha
$(HARECACHE)/bufio.ssa: $(bufio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/bufio.ssa -t $(HARECACHE)/bufio.td.tmp -N bufio $(bufio_ha)

crypto_math_ha = crypto/math/arithm.ha crypto/math/bits.ha
$(HARECACHE)/crypto_math.ssa: $(crypto_math_ha)
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/crypto_math.ssa -t $(HARECACHE)/crypto_math.td.tmp -N crypto::math $(crypto_math_ha)

endian_ha = endian/big.ha endian/endian.ha endian/host+riscv64.ha endian/little.ha endian/network.ha
$(HARECACHE)/endian.ssa: $(endian_ha)
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/endian.ssa -t $(HARECACHE)/endian.td.tmp -N endian $(endian_ha)

math_ha = math/fenv+riscv64.ha math/fenv_func.ha math/floats.ha math/ints.ha math/math.ha math/trig.ha math/uints.ha
$(HARECACHE)/math.ssa: $(math_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/math.ssa -t $(HARECACHE)/math.td.tmp -N math $(math_ha)

memio_ha = memio/ops.ha memio/stream.ha
$(HARECACHE)/memio.ssa: $(memio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/memio.ssa -t $(HARECACHE)/memio.td.tmp -N memio $(memio_ha)

path_ha = path/+linux.ha path/buffer.ha path/error.ha path/ext_stack.ha path/iter.ha path/posix.ha path/prefix.ha path/stack.ha
$(HARECACHE)/path.ssa: $(path_ha) $(HARECACHE)/bytes.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/path.ssa -t $(HARECACHE)/path.td.tmp -N path $(path_ha)

format_elf_ha = format/elf/arch+riscv64.ha format/elf/platform+linux.ha format/elf/types.ha
$(HARECACHE)/format_elf.ssa: $(format_elf_ha)
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/format_elf.ssa -t $(HARECACHE)/format_elf.td.tmp -N format::elf $(format_elf_ha)

linux_ha = linux/env.ha linux/start.ha
$(HARECACHE)/linux.ssa: $(linux_ha) $(HARECACHE)/format_elf.td $(HARECACHE)/rt.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/linux.ssa -t $(HARECACHE)/linux.td.tmp -N linux $(linux_ha)

types_c_ha = types/c/arch+riscv64.ha types/c/strings.ha types/c/types.ha
$(HARECACHE)/types_c.ssa: $(types_c_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/types_c.ssa -t $(HARECACHE)/types_c.td.tmp -N types::c $(types_c_ha)

linux_vdso_ha = linux/vdso/vdso.ha
$(HARECACHE)/linux_vdso.ssa: $(linux_vdso_ha) $(HARECACHE)/format_elf.td $(HARECACHE)/linux.td $(HARECACHE)/types_c.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/linux_vdso.ssa -t $(HARECACHE)/linux_vdso.td.tmp -N linux::vdso $(linux_vdso_ha)

time_ha = time/+linux/+riscv64.ha time/+linux/functions.ha time/arithm.ha time/conv.ha time/types.ha
$(HARECACHE)/time.ssa: $(time_ha) $(HARECACHE)/linux_vdso.td $(HARECACHE)/math.td $(HARECACHE)/rt.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/time.ssa -t $(HARECACHE)/time.td.tmp -N time $(time_ha)

fs_ha = fs/fs.ha fs/types.ha fs/util.ha
$(HARECACHE)/fs.ssa: $(fs_ha) $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/strings.td $(HARECACHE)/time.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/fs.ssa -t $(HARECACHE)/fs.td.tmp -N fs $(fs_ha)

os_ha = os/+linux/dirfdfs.ha os/+linux/exit.ha os/+linux/fs.ha os/+linux/memory.ha os/+linux/platform_environ.ha os/+linux/status.ha os/+linux/stdfd.ha os/environ.ha os/os.ha
$(HARECACHE)/os.ssa: $(os_ha) $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/os.ssa -t $(HARECACHE)/os.td.tmp -N os $(os_ha)

strconv_ha = strconv/ftos.ha strconv/itos.ha strconv/numeric.ha strconv/stof.ha strconv/stof_data.ha strconv/stoi.ha strconv/stou.ha strconv/types.ha strconv/utos.ha
$(HARECACHE)/strconv.ssa: $(strconv_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/math.td $(HARECACHE)/strings.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/strconv.ssa -t $(HARECACHE)/strconv.td.tmp -N strconv $(strconv_ha)

fmt_ha = fmt/fmt.ha
$(HARECACHE)/fmt.ssa: $(fmt_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/fmt.ssa -t $(HARECACHE)/fmt.td.tmp -N fmt $(fmt_ha)

hash_ha = hash/hash.ha
$(HARECACHE)/hash.ssa: $(hash_ha) $(HARECACHE)/fmt.td $(HARECACHE)/io.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/hash.ssa -t $(HARECACHE)/hash.td.tmp -N hash $(hash_ha)

crypto_sha256_ha = crypto/sha256/sha256.ha
$(HARECACHE)/crypto_sha256.ssa: $(crypto_sha256_ha) $(HARECACHE)/bytes.td $(HARECACHE)/crypto_math.td $(HARECACHE)/endian.td $(HARECACHE)/hash.td $(HARECACHE)/io.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/crypto_sha256.ssa -t $(HARECACHE)/crypto_sha256.td.tmp -N crypto::sha256 $(crypto_sha256_ha)

encoding_hex_ha = encoding/hex/hex.ha
$(HARECACHE)/encoding_hex.ssa: $(encoding_hex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/encoding_hex.ssa -t $(HARECACHE)/encoding_hex.td.tmp -N encoding::hex $(encoding_hex_ha)

sort_ha = sort/bisect.ha sort/search.ha sort/sort.ha sort/types.ha
$(HARECACHE)/sort.ssa: $(sort_ha) $(HARECACHE)/math.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/sort.ssa -t $(HARECACHE)/sort.td.tmp -N sort $(sort_ha)

hare_lex_ha = hare/lex/lex.ha hare/lex/token.ha
$(HARECACHE)/hare_lex.ssa: $(hare_lex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/hare_lex.ssa -t $(HARECACHE)/hare_lex.td.tmp -N hare::lex $(hare_lex_ha)

hare_ast_ha = hare/ast/decl.ha hare/ast/expr.ha hare/ast/ident.ha hare/ast/import.ha hare/ast/type.ha hare/ast/unit.ha
$(HARECACHE)/hare_ast.ssa: $(hare_ast_ha) $(HARECACHE)/hare_lex.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/hare_ast.ssa -t $(HARECACHE)/hare_ast.td.tmp -N hare::ast $(hare_ast_ha)

hare_parse_ha = hare/parse/decl.ha hare/parse/expr.ha hare/parse/ident.ha hare/parse/import.ha hare/parse/parse.ha hare/parse/type.ha hare/parse/unit.ha
$(HARECACHE)/hare_parse.ssa: $(hare_parse_ha) $(HARECACHE)/ascii.td $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/hare_parse.ssa -t $(HARECACHE)/hare_parse.td.tmp -N hare::parse $(hare_parse_ha)

hare_unparse_ha = hare/unparse/decl.ha hare/unparse/expr.ha hare/unparse/ident.ha hare/unparse/import.ha hare/unparse/type.ha hare/unparse/unit.ha hare/unparse/util.ha
$(HARECACHE)/hare_unparse.ssa: $(hare_unparse_ha) $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/hare_unparse.ssa -t $(HARECACHE)/hare_unparse.td.tmp -N hare::unparse $(hare_unparse_ha)

time_chrono_ha = time/chrono/+linux.ha time/chrono/arithmetic.ha time/chrono/chronology.ha time/chrono/error.ha time/chrono/leapsec.ha time/chrono/timescale.ha time/chrono/timezone.ha time/chrono/tzdb.ha
$(HARECACHE)/time_chrono.ssa: $(time_chrono_ha) $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/endian.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/time_chrono.ssa -t $(HARECACHE)/time_chrono.td.tmp -N time::chrono $(time_chrono_ha)

time_date_ha = time/date/date.ha time/date/daydate.ha time/date/daytime.ha time/date/error.ha time/date/format.ha time/date/locality.ha time/date/observe.ha time/date/parithm.ha time/date/parse.ha time/date/period.ha time/date/reckon.ha time/date/tarithm.ha time/date/virtual.ha
$(HARECACHE)/time_date.ssa: $(time_date_ha) $(HARECACHE)/ascii.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/time_date.ssa -t $(HARECACHE)/time_date.td.tmp -N time::date $(time_date_ha)

hare_module_ha = hare/module/cache.ha hare/module/deps.ha hare/module/format.ha hare/module/srcs.ha hare/module/types.ha hare/module/util.ha
$(HARECACHE)/hare_module.ssa: $(hare_module_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_parse.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td $(HARECACHE)/time_date.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/hare_module.ssa -t $(HARECACHE)/hare_module.td.tmp -N hare::module $(hare_module_ha)

unix_ha = unix/+linux/getuid.ha unix/+linux/groups.ha unix/+linux/nice.ha unix/+linux/pipe.ha unix/+linux/setuid.ha unix/+linux/umask.ha
$(HARECACHE)/unix.ssa: $(unix_ha) $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/rt.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/unix.ssa -t $(HARECACHE)/unix.td.tmp -N unix $(unix_ha)

unix_signal_ha = unix/signal/+linux.ha unix/signal/types.ha
$(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/rt.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/unix_signal.ssa -t $(HARECACHE)/unix_signal.td.tmp -N unix::signal $(unix_signal_ha)

os_exec_ha = os/exec/cmd.ha os/exec/exec+linux.ha os/exec/process+linux.ha os/exec/types.ha
$(HARECACHE)/os_exec.ssa: $(os_exec_ha) $(HARECACHE)/ascii.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td $(HARECACHE)/unix.td $(HARECACHE)/unix_signal.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/os_exec.ssa -t $(HARECACHE)/os_exec.td.tmp -N os::exec $(os_exec_ha)

shlex_ha = shlex/escape.ha shlex/split.ha
$(HARECACHE)/shlex.ssa: $(shlex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/shlex.ssa -t $(HARECACHE)/shlex.td.tmp -N shlex $(shlex_ha)

unix_tty_ha = unix/tty/+linux/isatty.ha unix/tty/+linux/open.ha unix/tty/+linux/pty.ha unix/tty/+linux/termios.ha unix/tty/+linux/winsize.ha unix/tty/pty_common.ha unix/tty/types.ha
$(HARECACHE)/unix_tty.ssa: $(unix_tty_ha) $(HARECACHE)/bufio.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/unix_tty.ssa -t $(HARECACHE)/unix_tty.td.tmp -N unix::tty $(unix_tty_ha)

cmd_hare_build_ha = cmd/hare/build/gather.ha cmd/hare/build/queue.ha cmd/hare/build/types.ha cmd/hare/build/util.ha
$(HARECACHE)/cmd_hare_build.ssa: $(cmd_hare_build_ha) $(HARECACHE)/crypto_sha256.td $(HARECACHE)/encoding_hex.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/hash.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/shlex.td $(HARECACHE)/sort.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/cmd_hare_build.ssa -t $(HARECACHE)/cmd_hare_build.td.tmp -N cmd::hare::build $(cmd_hare_build_ha)

dirs_ha = dirs/xdg.ha
$(HARECACHE)/dirs.ssa: $(dirs_ha) $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/unix.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/dirs.ssa -t $(HARECACHE)/dirs.td.tmp -N dirs $(dirs_ha)

getopt_ha = getopt/getopts.ha
$(HARECACHE)/getopt.ssa: $(getopt_ha) $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/getopt.ssa -t $(HARECACHE)/getopt.td.tmp -N getopt $(getopt_ha)

cmd_hare_ha = cmd/hare/arch.ha cmd/hare/build.ha cmd/hare/cache.ha cmd/hare/deps.ha cmd/hare/error.ha cmd/hare/main.ha cmd/hare/util.ha cmd/hare/version.ha
$(HARECACHE)/cmd_hare.ssa: $(cmd_hare_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/cmd_hare_build.td $(HARECACHE)/dirs.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/getopt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_parse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/cmd_hare.ssa -t $(HARECACHE)/cmd_hare.td.tmp $(HARE_DEFINES)  $(cmd_hare_ha)
diff --git a/makefiles/linux.x86_64.mk b/makefiles/linux.x86_64.mk
new file mode 100644
index 00000000..57144b81
--- /dev/null
+++ b/makefiles/linux.x86_64.mk
@@ -0,0 +1,268 @@
# generated by cmd/genbootstrap
# DO NOT EDIT BY HAND. run 'make bootstrap' to update
TDENV = env HARE_TD_rt=$(HARECACHE)/rt.td HARE_TD_encoding::utf8=$(HARECACHE)/encoding_utf8.td HARE_TD_types=$(HARECACHE)/types.td HARE_TD_bytes=$(HARECACHE)/bytes.td HARE_TD_strings=$(HARECACHE)/strings.td HARE_TD_ascii=$(HARECACHE)/ascii.td HARE_TD_errors=$(HARECACHE)/errors.td HARE_TD_io=$(HARECACHE)/io.td HARE_TD_bufio=$(HARECACHE)/bufio.td HARE_TD_crypto::math=$(HARECACHE)/crypto_math.td HARE_TD_endian=$(HARECACHE)/endian.td HARE_TD_math=$(HARECACHE)/math.td HARE_TD_memio=$(HARECACHE)/memio.td HARE_TD_path=$(HARECACHE)/path.td HARE_TD_format::elf=$(HARECACHE)/format_elf.td HARE_TD_linux=$(HARECACHE)/linux.td HARE_TD_types::c=$(HARECACHE)/types_c.td HARE_TD_linux::vdso=$(HARECACHE)/linux_vdso.td HARE_TD_time=$(HARECACHE)/time.td HARE_TD_fs=$(HARECACHE)/fs.td HARE_TD_os=$(HARECACHE)/os.td HARE_TD_strconv=$(HARECACHE)/strconv.td HARE_TD_fmt=$(HARECACHE)/fmt.td HARE_TD_hash=$(HARECACHE)/hash.td HARE_TD_crypto::sha256=$(HARECACHE)/crypto_sha256.td HARE_TD_encoding::hex=$(HARECACHE)/encoding_hex.td HARE_TD_sort=$(HARECACHE)/sort.td HARE_TD_hare::lex=$(HARECACHE)/hare_lex.td HARE_TD_hare::ast=$(HARECACHE)/hare_ast.td HARE_TD_hare::parse=$(HARECACHE)/hare_parse.td HARE_TD_hare::unparse=$(HARECACHE)/hare_unparse.td HARE_TD_time::chrono=$(HARECACHE)/time_chrono.td HARE_TD_time::date=$(HARECACHE)/time_date.td HARE_TD_hare::module=$(HARECACHE)/hare_module.td HARE_TD_unix=$(HARECACHE)/unix.td HARE_TD_unix::signal=$(HARECACHE)/unix_signal.td HARE_TD_os::exec=$(HARECACHE)/os_exec.td HARE_TD_shlex=$(HARECACHE)/shlex.td HARE_TD_unix::tty=$(HARECACHE)/unix_tty.td HARE_TD_cmd::hare::build=$(HARECACHE)/cmd_hare_build.td HARE_TD_dirs=$(HARECACHE)/dirs.td HARE_TD_getopt=$(HARECACHE)/getopt.td HARE_TD_cmd::hare=$(HARECACHE)/cmd_hare.td
RTSCRIPT = rt/hare.sc
OBJS = $(HARECACHE)/rt.o $(HARECACHE)/encoding_utf8.o $(HARECACHE)/types.o $(HARECACHE)/bytes.o $(HARECACHE)/strings.o $(HARECACHE)/ascii.o $(HARECACHE)/errors.o $(HARECACHE)/io.o $(HARECACHE)/bufio.o $(HARECACHE)/crypto_math.o $(HARECACHE)/endian.o $(HARECACHE)/math.o $(HARECACHE)/memio.o $(HARECACHE)/path.o $(HARECACHE)/format_elf.o $(HARECACHE)/linux.o $(HARECACHE)/types_c.o $(HARECACHE)/linux_vdso.o $(HARECACHE)/time.o $(HARECACHE)/fs.o $(HARECACHE)/os.o $(HARECACHE)/strconv.o $(HARECACHE)/fmt.o $(HARECACHE)/hash.o $(HARECACHE)/crypto_sha256.o $(HARECACHE)/encoding_hex.o $(HARECACHE)/sort.o $(HARECACHE)/hare_lex.o $(HARECACHE)/hare_ast.o $(HARECACHE)/hare_parse.o $(HARECACHE)/hare_unparse.o $(HARECACHE)/time_chrono.o $(HARECACHE)/time_date.o $(HARECACHE)/hare_module.o $(HARECACHE)/unix.o $(HARECACHE)/unix_signal.o $(HARECACHE)/os_exec.o $(HARECACHE)/shlex.o $(HARECACHE)/unix_tty.o $(HARECACHE)/cmd_hare_build.o $(HARECACHE)/dirs.o $(HARECACHE)/getopt.o $(HARECACHE)/cmd_hare.o

rt_ha = rt/+linux/+x86_64.ha rt/+linux/env.ha rt/+linux/errno.ha rt/+linux/platform_abort.ha rt/+linux/platformstart-libc.ha rt/+linux/prctl.ha rt/+linux/segmalloc.ha rt/+linux/signal.ha rt/+linux/socket.ha rt/+linux/stat.ha rt/+linux/syscallno+x86_64.ha rt/+linux/syscalls.ha rt/+linux/types.ha rt/+x86_64/arch_jmp.ha rt/+x86_64/backtrace.ha rt/+x86_64/cpuid.ha rt/abort.ha rt/ensure.ha rt/fenv_defs.ha rt/jmp.ha rt/malloc.ha rt/memcpy.ha rt/memfunc_ptr.ha rt/memmove.ha rt/memset.ha rt/start.ha rt/strcmp.ha rt/u64tos.ha rt/unknown_errno.ha
$(HARECACHE)/rt.ssa: $(rt_ha)
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/rt.ssa -t $(HARECACHE)/rt.td.tmp -N rt $(rt_ha)

rt_s = $(HARECACHE)/rt.s rt/+linux/start+x86_64-libc.s rt/+linux/syscall+x86_64.s rt/+x86_64/cpuid.s rt/+x86_64/fenv.s rt/+x86_64/getfp.s rt/+x86_64/longjmp.s rt/+x86_64/restore.s rt/+x86_64/setjmp.s
$(HARECACHE)/rt.o: $(rt_s)
	@printf 'AS\t%s\n' "$@"
	@$(AS) $(ASFLAGS) -o $@ $(rt_s)

encoding_utf8_ha = encoding/utf8/decode.ha encoding/utf8/decodetable.ha encoding/utf8/encode.ha encoding/utf8/rune.ha
$(HARECACHE)/encoding_utf8.ssa: $(encoding_utf8_ha)
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/encoding_utf8.ssa -t $(HARECACHE)/encoding_utf8.td.tmp -N encoding::utf8 $(encoding_utf8_ha)

types_ha = types/arch+x86_64.ha types/classes.ha types/limits.ha
$(HARECACHE)/types.ssa: $(types_ha)
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/types.ssa -t $(HARECACHE)/types.td.tmp -N types $(types_ha)

bytes_ha = bytes/contains.ha bytes/equal.ha bytes/index.ha bytes/reverse.ha bytes/tokenize.ha bytes/trim.ha bytes/two_way.ha bytes/zero.ha
$(HARECACHE)/bytes.ssa: $(bytes_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/bytes.ssa -t $(HARECACHE)/bytes.td.tmp -N bytes $(bytes_ha)

strings_ha = strings/compare.ha strings/concat.ha strings/contains.ha strings/dup.ha strings/index.ha strings/iter.ha strings/pad.ha strings/replace.ha strings/runes.ha strings/sub.ha strings/suffix.ha strings/tokenize.ha strings/trim.ha strings/utf8.ha
$(HARECACHE)/strings.ssa: $(strings_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/strings.ssa -t $(HARECACHE)/strings.td.tmp -N strings $(strings_ha)

ascii_ha = ascii/ctype.ha ascii/string.ha ascii/valid.ha
$(HARECACHE)/ascii.ssa: $(ascii_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/ascii.ssa -t $(HARECACHE)/ascii.td.tmp -N ascii $(ascii_ha)

errors_ha = errors/common.ha errors/opaque.ha errors/rt.ha errors/string.ha
$(HARECACHE)/errors.ssa: $(errors_ha) $(HARECACHE)/rt.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/errors.ssa -t $(HARECACHE)/errors.td.tmp -N errors $(errors_ha)

io_ha = io/+linux/mmap.ha io/+linux/platform_file.ha io/+linux/vector.ha io/arch+x86_64.ha io/copy.ha io/drain.ha io/empty.ha io/file.ha io/handle.ha io/limit.ha io/stream.ha io/tee.ha io/types.ha io/util.ha io/zero.ha
$(HARECACHE)/io.ssa: $(io_ha) $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/rt.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/io.ssa -t $(HARECACHE)/io.td.tmp -N io $(io_ha)

bufio_ha = bufio/scanner.ha bufio/stream.ha
$(HARECACHE)/bufio.ssa: $(bufio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/bufio.ssa -t $(HARECACHE)/bufio.td.tmp -N bufio $(bufio_ha)

crypto_math_ha = crypto/math/arithm.ha crypto/math/bits.ha
$(HARECACHE)/crypto_math.ssa: $(crypto_math_ha)
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/crypto_math.ssa -t $(HARECACHE)/crypto_math.td.tmp -N crypto::math $(crypto_math_ha)

endian_ha = endian/big.ha endian/endian.ha endian/host+x86_64.ha endian/little.ha endian/network.ha
$(HARECACHE)/endian.ssa: $(endian_ha)
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/endian.ssa -t $(HARECACHE)/endian.td.tmp -N endian $(endian_ha)

math_ha = math/fenv+x86_64.ha math/fenv_func.ha math/floats.ha math/ints.ha math/math.ha math/trig.ha math/uints.ha
$(HARECACHE)/math.ssa: $(math_ha) $(HARECACHE)/rt.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/math.ssa -t $(HARECACHE)/math.td.tmp -N math $(math_ha)

memio_ha = memio/ops.ha memio/stream.ha
$(HARECACHE)/memio.ssa: $(memio_ha) $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/memio.ssa -t $(HARECACHE)/memio.td.tmp -N memio $(memio_ha)

path_ha = path/+linux.ha path/buffer.ha path/error.ha path/ext_stack.ha path/iter.ha path/posix.ha path/prefix.ha path/stack.ha
$(HARECACHE)/path.ssa: $(path_ha) $(HARECACHE)/bytes.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/path.ssa -t $(HARECACHE)/path.td.tmp -N path $(path_ha)

format_elf_ha = format/elf/arch+x86_64.ha format/elf/platform+linux.ha format/elf/types.ha
$(HARECACHE)/format_elf.ssa: $(format_elf_ha)
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/format_elf.ssa -t $(HARECACHE)/format_elf.td.tmp -N format::elf $(format_elf_ha)

linux_ha = linux/env.ha linux/start.ha
$(HARECACHE)/linux.ssa: $(linux_ha) $(HARECACHE)/format_elf.td $(HARECACHE)/rt.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/linux.ssa -t $(HARECACHE)/linux.td.tmp -N linux $(linux_ha)

types_c_ha = types/c/arch+x86_64.ha types/c/strings.ha types/c/types.ha
$(HARECACHE)/types_c.ssa: $(types_c_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/types_c.ssa -t $(HARECACHE)/types_c.td.tmp -N types::c $(types_c_ha)

linux_vdso_ha = linux/vdso/vdso.ha
$(HARECACHE)/linux_vdso.ssa: $(linux_vdso_ha) $(HARECACHE)/format_elf.td $(HARECACHE)/linux.td $(HARECACHE)/types_c.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/linux_vdso.ssa -t $(HARECACHE)/linux_vdso.td.tmp -N linux::vdso $(linux_vdso_ha)

time_ha = time/+linux/+x86_64.ha time/+linux/functions.ha time/arithm.ha time/conv.ha time/types.ha
$(HARECACHE)/time.ssa: $(time_ha) $(HARECACHE)/linux_vdso.td $(HARECACHE)/math.td $(HARECACHE)/rt.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/time.ssa -t $(HARECACHE)/time.td.tmp -N time $(time_ha)

fs_ha = fs/fs.ha fs/types.ha fs/util.ha
$(HARECACHE)/fs.ssa: $(fs_ha) $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/strings.td $(HARECACHE)/time.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/fs.ssa -t $(HARECACHE)/fs.td.tmp -N fs $(fs_ha)

os_ha = os/+linux/dirfdfs.ha os/+linux/exit.ha os/+linux/fs.ha os/+linux/memory.ha os/+linux/platform_environ.ha os/+linux/status.ha os/+linux/stdfd.ha os/environ.ha os/os.ha
$(HARECACHE)/os.ssa: $(os_ha) $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/os.ssa -t $(HARECACHE)/os.td.tmp -N os $(os_ha)

strconv_ha = strconv/ftos.ha strconv/itos.ha strconv/numeric.ha strconv/stof.ha strconv/stof_data.ha strconv/stoi.ha strconv/stou.ha strconv/types.ha strconv/utos.ha
$(HARECACHE)/strconv.ssa: $(strconv_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/math.td $(HARECACHE)/strings.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/strconv.ssa -t $(HARECACHE)/strconv.td.tmp -N strconv $(strconv_ha)

fmt_ha = fmt/fmt.ha
$(HARECACHE)/fmt.ssa: $(fmt_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/fmt.ssa -t $(HARECACHE)/fmt.td.tmp -N fmt $(fmt_ha)

hash_ha = hash/hash.ha
$(HARECACHE)/hash.ssa: $(hash_ha) $(HARECACHE)/fmt.td $(HARECACHE)/io.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/hash.ssa -t $(HARECACHE)/hash.td.tmp -N hash $(hash_ha)

crypto_sha256_ha = crypto/sha256/sha256.ha
$(HARECACHE)/crypto_sha256.ssa: $(crypto_sha256_ha) $(HARECACHE)/bytes.td $(HARECACHE)/crypto_math.td $(HARECACHE)/endian.td $(HARECACHE)/hash.td $(HARECACHE)/io.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/crypto_sha256.ssa -t $(HARECACHE)/crypto_sha256.td.tmp -N crypto::sha256 $(crypto_sha256_ha)

encoding_hex_ha = encoding/hex/hex.ha
$(HARECACHE)/encoding_hex.ssa: $(encoding_hex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bytes.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/encoding_hex.ssa -t $(HARECACHE)/encoding_hex.td.tmp -N encoding::hex $(encoding_hex_ha)

sort_ha = sort/bisect.ha sort/search.ha sort/sort.ha sort/types.ha
$(HARECACHE)/sort.ssa: $(sort_ha) $(HARECACHE)/math.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/sort.ssa -t $(HARECACHE)/sort.td.tmp -N sort $(sort_ha)

hare_lex_ha = hare/lex/lex.ha hare/lex/token.ha
$(HARECACHE)/hare_lex.ssa: $(hare_lex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/hare_lex.ssa -t $(HARECACHE)/hare_lex.td.tmp -N hare::lex $(hare_lex_ha)

hare_ast_ha = hare/ast/decl.ha hare/ast/expr.ha hare/ast/ident.ha hare/ast/import.ha hare/ast/type.ha hare/ast/unit.ha
$(HARECACHE)/hare_ast.ssa: $(hare_ast_ha) $(HARECACHE)/hare_lex.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/hare_ast.ssa -t $(HARECACHE)/hare_ast.td.tmp -N hare::ast $(hare_ast_ha)

hare_parse_ha = hare/parse/decl.ha hare/parse/expr.ha hare/parse/ident.ha hare/parse/import.ha hare/parse/parse.ha hare/parse/type.ha hare/parse/unit.ha
$(HARECACHE)/hare_parse.ssa: $(hare_parse_ha) $(HARECACHE)/ascii.td $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td $(HARECACHE)/types.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/hare_parse.ssa -t $(HARECACHE)/hare_parse.td.tmp -N hare::parse $(hare_parse_ha)

hare_unparse_ha = hare/unparse/decl.ha hare/unparse/expr.ha hare/unparse/ident.ha hare/unparse/import.ha hare/unparse/type.ha hare/unparse/unit.ha hare/unparse/util.ha
$(HARECACHE)/hare_unparse.ssa: $(hare_unparse_ha) $(HARECACHE)/fmt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/hare_unparse.ssa -t $(HARECACHE)/hare_unparse.td.tmp -N hare::unparse $(hare_unparse_ha)

time_chrono_ha = time/chrono/+linux.ha time/chrono/arithmetic.ha time/chrono/chronology.ha time/chrono/error.ha time/chrono/leapsec.ha time/chrono/timescale.ha time/chrono/timezone.ha time/chrono/tzdb.ha
$(HARECACHE)/time_chrono.ssa: $(time_chrono_ha) $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/endian.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/time_chrono.ssa -t $(HARECACHE)/time_chrono.td.tmp -N time::chrono $(time_chrono_ha)

time_date_ha = time/date/date.ha time/date/daydate.ha time/date/daytime.ha time/date/error.ha time/date/format.ha time/date/locality.ha time/date/observe.ha time/date/parithm.ha time/date/parse.ha time/date/period.ha time/date/reckon.ha time/date/tarithm.ha time/date/virtual.ha
$(HARECACHE)/time_date.ssa: $(time_date_ha) $(HARECACHE)/ascii.td $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/memio.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/time_date.ssa -t $(HARECACHE)/time_date.td.tmp -N time::date $(time_date_ha)

hare_module_ha = hare/module/cache.ha hare/module/deps.ha hare/module/format.ha hare/module/srcs.ha hare/module/types.ha hare/module/util.ha
$(HARECACHE)/hare_module.ssa: $(hare_module_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/bytes.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_parse.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/time_chrono.td $(HARECACHE)/time_date.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/hare_module.ssa -t $(HARECACHE)/hare_module.td.tmp -N hare::module $(hare_module_ha)

unix_ha = unix/+linux/getuid.ha unix/+linux/groups.ha unix/+linux/nice.ha unix/+linux/pipe.ha unix/+linux/setuid.ha unix/+linux/umask.ha
$(HARECACHE)/unix.ssa: $(unix_ha) $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/rt.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/unix.ssa -t $(HARECACHE)/unix.td.tmp -N unix $(unix_ha)

unix_signal_ha = unix/signal/+linux.ha unix/signal/types.ha
$(HARECACHE)/unix_signal.ssa: $(unix_signal_ha) $(HARECACHE)/errors.td $(HARECACHE)/io.td $(HARECACHE)/rt.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/unix_signal.ssa -t $(HARECACHE)/unix_signal.td.tmp -N unix::signal $(unix_signal_ha)

os_exec_ha = os/exec/cmd.ha os/exec/exec+linux.ha os/exec/process+linux.ha os/exec/types.ha
$(HARECACHE)/os_exec.ssa: $(os_exec_ha) $(HARECACHE)/ascii.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td $(HARECACHE)/unix.td $(HARECACHE)/unix_signal.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/os_exec.ssa -t $(HARECACHE)/os_exec.td.tmp -N os::exec $(os_exec_ha)

shlex_ha = shlex/escape.ha shlex/split.ha
$(HARECACHE)/shlex.ssa: $(shlex_ha) $(HARECACHE)/ascii.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/shlex.ssa -t $(HARECACHE)/shlex.td.tmp -N shlex $(shlex_ha)

unix_tty_ha = unix/tty/+linux/isatty.ha unix/tty/+linux/open.ha unix/tty/+linux/pty.ha unix/tty/+linux/termios.ha unix/tty/+linux/winsize.ha unix/tty/pty_common.ha unix/tty/types.ha
$(HARECACHE)/unix_tty.ssa: $(unix_tty_ha) $(HARECACHE)/bufio.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/unix_tty.ssa -t $(HARECACHE)/unix_tty.td.tmp -N unix::tty $(unix_tty_ha)

cmd_hare_build_ha = cmd/hare/build/gather.ha cmd/hare/build/queue.ha cmd/hare/build/types.ha cmd/hare/build/util.ha
$(HARECACHE)/cmd_hare_build.ssa: $(cmd_hare_build_ha) $(HARECACHE)/crypto_sha256.td $(HARECACHE)/encoding_hex.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_unparse.td $(HARECACHE)/hash.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/shlex.td $(HARECACHE)/sort.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/cmd_hare_build.ssa -t $(HARECACHE)/cmd_hare_build.td.tmp -N cmd::hare::build $(cmd_hare_build_ha)

dirs_ha = dirs/xdg.ha
$(HARECACHE)/dirs.ssa: $(dirs_ha) $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/os.td $(HARECACHE)/path.td $(HARECACHE)/unix.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/dirs.ssa -t $(HARECACHE)/dirs.td.tmp -N dirs $(dirs_ha)

getopt_ha = getopt/getopts.ha
$(HARECACHE)/getopt.ssa: $(getopt_ha) $(HARECACHE)/fmt.td $(HARECACHE)/io.td $(HARECACHE)/os.td $(HARECACHE)/strings.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/getopt.ssa -t $(HARECACHE)/getopt.td.tmp -N getopt $(getopt_ha)

cmd_hare_ha = cmd/hare/arch.ha cmd/hare/build.ha cmd/hare/cache.ha cmd/hare/deps.ha cmd/hare/error.ha cmd/hare/main.ha cmd/hare/util.ha cmd/hare/version.ha
$(HARECACHE)/cmd_hare.ssa: $(cmd_hare_ha) $(HARECACHE)/ascii.td $(HARECACHE)/bufio.td $(HARECACHE)/cmd_hare_build.td $(HARECACHE)/dirs.td $(HARECACHE)/errors.td $(HARECACHE)/fmt.td $(HARECACHE)/fs.td $(HARECACHE)/getopt.td $(HARECACHE)/hare_ast.td $(HARECACHE)/hare_lex.td $(HARECACHE)/hare_module.td $(HARECACHE)/hare_parse.td $(HARECACHE)/io.td $(HARECACHE)/memio.td $(HARECACHE)/os.td $(HARECACHE)/os_exec.td $(HARECACHE)/path.td $(HARECACHE)/sort.td $(HARECACHE)/strconv.td $(HARECACHE)/strings.td $(HARECACHE)/unix_tty.td
	@mkdir -p -- "$(HARECACHE)"
	@printf 'HAREC\t%s\n' "$@"
	@$(TDENV) $(HAREC) $(HARECFLAGS) -o $(HARECACHE)/cmd_hare.ssa -t $(HARECACHE)/cmd_hare.td.tmp $(HARE_DEFINES)  $(cmd_hare_ha)
diff --git a/scripts/gen-docs.sh b/scripts/gen-docs.sh
deleted file mode 100644
index e12a1fcf..00000000
--- a/scripts/gen-docs.sh
@@ -1,32 +0,0 @@
# Yes, I am entirely aware that this is a hack
srcdir="$(dirname "$0")"
getmods() (
	DOCS=1
	. "$srcdir"/gen-stdlib
	IFS="
"
	for module in $modules; do
		if [ -z "$(echo "$module" | cut -sf1)" ]
		then
			echo "$module"
		else
			module="$(echo "$module" | cut -sf1)"
			echo $module
		fi
	done
	# Not listed in the stdlib for various reasons:
	echo crypto::keystore
	echo mime
)
modules="$(getmods)"

mkdir -p docs/html/

"$BINOUT"/haredoc -Fhtml > docs/html/index.html
for mod in $modules format encoding math crypto hare rt
do
	echo $mod
	path="$(echo $mod | sed -e 's?::?/?g')"
	mkdir -p docs/html/$path
	"$BINOUT"/haredoc -Fhtml $mod > docs/html/$path/index.html
done
diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib
deleted file mode 100755
index b30f4087..00000000
--- a/scripts/gen-stdlib
@@ -1,1775 +0,0 @@
#!/bin/sh
# The purpose of this script is to generate make targets for the Hare standard
# library. If you are adding new modules to the standard library, write a
# function for that module (e.g. encoding_utf8), and call the following helper
# commands:
#
# gen_srcs module::name list.ha of.ha sources.ha
# gen_ssa module::name list of module::names yours depends on
#
# Then add your module to the list of modules at the bottom.
#
# Then run ./scripts/gen-stdlib > stdlib.mk to generate new rules.

srcdir="$(dirname "$0")"
eval ". $srcdir/gen-stdlib.sh"

all_platforms="linux
freebsd"

gensrcs_rt() {
	gen_srcs -plinux rt \
		+linux/platform_abort.ha \
		+linux/env.ha \
		+linux/errno.ha \
		+linux/types.ha \
		+linux/segmalloc.ha \
		+linux/platformstart-libc.ha \
		+linux/prctl.ha \
		+linux/'+$(ARCH)'.ha \
		+linux/syscallno+'$(ARCH)'.ha \
		+linux/syscalls.ha \
		+linux/signal.ha \
		+linux/stat.ha \
		+linux/socket.ha \
		'+$(ARCH)'/arch_jmp.ha \
		'+$(ARCH)'/backtrace.ha \
		fenv_defs.ha \
		'+$(ARCH)'/cpuid.ha \
		ensure.ha \
		jmp.ha \
		malloc.ha \
		memcpy.ha \
		memfunc_ptr.ha \
		memmove.ha \
		memset.ha \
		strcmp.ha \
		unknown_errno.ha \
		u64tos.ha \
		$*
	gen_srcs -pfreebsd rt \
		+freebsd/platform_abort.ha \
		+freebsd/env.ha \
		+freebsd/errno.ha \
		+freebsd/platformstart.ha \
		+freebsd/segmalloc.ha \
		+freebsd/signal.ha \
		+freebsd/socket.ha \
		+freebsd/'+$(ARCH)'.ha \
		+freebsd/syscallno.ha \
		+freebsd/syscalls.ha \
		+freebsd/types.ha \
		+'$(ARCH)'/arch_jmp.ha \
		+'$(ARCH)'/backtrace.ha \
		fenv_defs.ha \
		+'$(ARCH)'/cpuid.ha \
		ensure.ha \
		jmp.ha \
		malloc.ha \
		memcpy.ha \
		memfunc_ptr.ha \
		memmove.ha \
		memset.ha \
		strcmp.ha \
		unknown_errno.ha \
		u64tos.ha \
		$*
}

rt() {
	# This one is complicated, don't use it as a reference for other modules
	if [ $testing -eq 0 ]
	then
		printf '%s\n' 'rtscript = $(STDLIB)/rt/hare.sc'
		gensrcs_rt \
			abort.ha \
			start.ha
	else
		gensrcs_rt \
			abort+test.ha \
			start+test.ha \
			+test/signal_test.ha
	fi
	gen_ssa -plinux rt
	gen_ssa -pfreebsd rt
	cat <<EOF
\$($cache)/rt/start.o: \$(STDLIB)/rt/+\$(PLATFORM)/start+\$(ARCH)-libc.s
	@printf 'AS \t%s\n' "\$@"
	@mkdir -p \$($cache)/rt
	@\$(AS) -o \$@ \$(STDLIB)/rt/+\$(PLATFORM)/start+\$(ARCH)-libc.s

${stdlib}_asm = \$($cache)/rt/syscall.o \\
	\$($cache)/rt/setjmp.o \\
	\$($cache)/rt/longjmp.o \\
	\$($cache)/rt/restore.o \\
	\$($cache)/rt/getfp.o \\
	\$($cache)/rt/fenv.o \\
	\$($cache)/rt/start.o \\
	\$($cache)/rt/cpuid.o

\$($cache)/rt/syscall.o: \$(STDLIB)/rt/+\$(PLATFORM)/syscall+\$(ARCH).s
	@printf 'AS \t%s\n' "\$@"
	@mkdir -p \$($cache)/rt
	@\$(AS) -o \$@ \$(STDLIB)/rt/+\$(PLATFORM)/syscall+\$(ARCH).s

\$($cache)/rt/setjmp.o: \$(STDLIB)/rt/+\$(ARCH)/setjmp.s
	@printf 'AS \t%s\n' "\$@"
	@mkdir -p \$($cache)/rt
	@\$(AS) -o \$@ \$(STDLIB)/rt/+\$(ARCH)/setjmp.s

\$($cache)/rt/longjmp.o: \$(STDLIB)/rt/+\$(ARCH)/longjmp.s
	@printf 'AS \t%s\n' "\$@"
	@mkdir -p \$($cache)/rt
	@\$(AS) -o \$@ \$(STDLIB)/rt/+\$(ARCH)/longjmp.s

\$($cache)/rt/restore.o: \$(STDLIB)/rt/+\$(ARCH)/restore.s
	@printf 'AS \t%s\n' "\$@"
	@mkdir -p \$($cache)/rt
	@\$(AS) -o \$@ \$(STDLIB)/rt/+\$(ARCH)/restore.s

\$($cache)/rt/fenv.o: \$(STDLIB)/rt/+\$(ARCH)/fenv.s
	@printf 'AS \t%s\n' "\$@"
	@mkdir -p \$($cache)/rt
	@\$(AS) -o \$@ \$(STDLIB)/rt/+\$(ARCH)/fenv.s

\$($cache)/rt/getfp.o: \$(STDLIB)/rt/+\$(ARCH)/getfp.s
	@printf 'AS \t%s\n' "\$@"
	@mkdir -p \$($cache)/rt
	@\$(AS) -o \$@ \$(STDLIB)/rt/+\$(ARCH)/getfp.s

\$($cache)/rt/cpuid.o: \$(STDLIB)/rt/+\$(ARCH)/cpuid.s
	@printf 'AS \t%s\n' "\$@"
	@mkdir -p \$($cache)/rt
	@\$(AS) -o \$@ \$(STDLIB)/rt/+\$(ARCH)/cpuid.s

\$($cache)/rt/rt-linux.a: \$($cache)/rt/rt-linux.o \$(${stdlib}_asm)
	@printf 'AR \t%s\n' "\$@"
	@\$(AR) -csr \$@ \$($cache)/rt/rt-linux.o \$(${stdlib}_asm)

\$($cache)/rt/rt-freebsd.a: \$($cache)/rt/rt-freebsd.o \$(${stdlib}_asm)
	@printf 'AR \t%s\n' "\$@"
	@\$(AR) -csr \$@ \$($cache)/rt/rt-freebsd.o \$(${stdlib}_asm)

${stdlib}_rt = \$($cache)/rt/rt-\$(PLATFORM).a
${stdlib}_env += HARE_TD_rt=\$($cache)/rt/rt.td
${stdlib}_deps_linux += \$(${stdlib}_rt)
${stdlib}_deps_freebsd += \$(${stdlib}_rt)
${stdlib}_deps_any += \$(${stdlib}_rt)

EOF
}

test() {
	if [ $testing -eq 0 ]; then
		gen_srcs test common.ha
		gen_ssa test
	else
		gen_srcs test common.ha +test.ha fail+test.ha
		gen_ssa test bufio encoding::hex encoding::utf8 fmt fnmatch io \
			os rt strings memio time unix::signal
	fi
}

ascii() {
	gen_srcs ascii \
		ctype.ha \
		string.ha \
		valid.ha
	gen_ssa ascii strings
}

bufio() {
	if [ $testing -eq 0 ]; then
		gen_srcs bufio \
			stream.ha \
			scanner.ha
		gen_ssa bufio bytes encoding::utf8 errors io strings types
	else
		gen_srcs bufio \
			stream.ha \
			scanner.ha \
			stream_test+test.ha \
			scanner_test+test.ha
		gen_ssa bufio bytes encoding::utf8 errors io memio strings types
	fi
}

bytes() {
	gen_srcs bytes \
		contains.ha \
		equal.ha \
		index.ha \
		reverse.ha \
		tokenize.ha \
		trim.ha \
		two_way.ha \
		zero.ha
	gen_ssa bytes types
}

cmd_hare_build() {
	gen_srcs cmd::hare::build \
		gather.ha \
		queue.ha \
		types.ha \
		util.ha
	gen_ssa cmd::hare::build encoding::hex crypto::sha256 errors fmt fs \
		hare::ast hare::module hare::unparse hash io memio os os::exec path \
		sort strings shlex unix::tty
}

crypto() {
	if [ $testing -eq 0 ]
	then
		gen_srcs crypto \
			authenc.ha \
			keyderiv.ha
		gen_ssa crypto bytes crypto::argon2 crypto::chachapoly \
			crypto::math endian errors io memio
	else
		gen_srcs crypto \
			authenc.ha \
			keyderiv.ha \
			+test/authenc_test.ha
		gen_ssa crypto bytes crypto::argon2 crypto::chachapoly \
			crypto::math endian errors io memio
	fi
}

gensrcs_crypto_aes() {
	gen_srcs crypto::aes \
		aes.ha \
		aes_ct64.ha \
		block.ha \
		$*
}

crypto_aes() {
	if [ $testing -eq 0 ]
	then
		gensrcs_crypto_aes
		gen_ssa crypto::aes bytes crypto::cipher crypto::math endian \
			rt io
	else
		gensrcs_crypto_aes \
			ct64+test.ha \
			cbc+test.ha \
			ctr+test.ha \
			rt+test.ha \
			+test/gcm.ha
		gen_ssa crypto::aes bytes crypto::cipher crypto::math \
			endian errors io memio rt 
	fi
}

crypto_aes_xts() {
	if [ $testing -eq 0 ]
	then
		gen_srcs crypto::aes::xts xts.ha
	else
		gen_srcs crypto::aes::xts xts.ha +test.ha
	fi
	gen_ssa crypto::aes::xts crypto::aes crypto::cipher bytes
}

crypto_argon2() {
	if [ $testing -eq 0 ]
	then
		gen_srcs crypto::argon2 argon2.ha
		gen_ssa crypto::argon2 bytes crypto::blake2b \
			crypto::math endian errors hash io memio rt types
	else
		gen_srcs crypto::argon2 argon2.ha +test.ha
		gen_ssa crypto::argon2 bytes crypto::blake2b \
			crypto::math encoding::hex endian errors hash io memio \
			rt strings types
	fi
}

crypto_bcrypt() {
	if [ $testing -eq 0 ]
	then
		gen_srcs crypto::bcrypt bcrypt.ha base64.ha
	else
		gen_srcs crypto::bcrypt bcrypt.ha base64.ha +test.ha
	fi
	gen_ssa crypto::bcrypt bytes crypto crypto::blowfish \
		crypto::cipher crypto::random encoding::base64 errors \
		fmt io memio strconv strings
}

gensrcs_crypto_blake2b() {
	gen_srcs crypto::blake2b \
		blake2b.ha \
		$*
}

crypto_blake2b() {
	if [ $testing -eq 0 ]
	then
		gensrcs_crypto_blake2b
		gen_ssa crypto::blake2b bytes crypto::math endian hash io
	else
		gensrcs_crypto_blake2b +test.ha vectors+test.ha
		gen_ssa crypto::blake2b encoding::hex fmt hash io strings \
			memio crypto::math endian bytes
	fi
}

gensrcs_crypto_blowfish() {
	gen_srcs crypto::blowfish \
		blowfish.ha \
		const.ha \
		$*
}

crypto_blowfish() {
	if [ $testing -eq 0 ]
	then
		gensrcs_crypto_blowfish
	else
		gensrcs_crypto_blowfish +test.ha
	fi
	gen_ssa crypto::blowfish bytes crypto::cipher endian
}

gensrcs_crypto_bigint() {
		gen_srcs crypto::bigint arithm.ha encoding.ha monty.ha types.ha \
            util.ha $*
}

crypto_bigint() {
	if [ $testing -eq 0 ]
	then
		gensrcs_crypto_bigint
        gen_ssa crypto::bigint bytes crypto::math
	else
		gensrcs_crypto_bigint +test/arithm_test.ha +test/encoding_test.ha \
            +test/monty_test.ha +test/utils.ha
        gen_ssa crypto::bigint bytes crypto::math encoding::hex
	fi
}

crypto_chacha() {
	if [ $testing -eq 0 ]
	then
		gen_srcs crypto::chacha chacha20.ha
		gen_ssa crypto::chacha bytes crypto::cipher crypto::math \
			endian io
	else
		gen_srcs crypto::chacha chacha20.ha +test.ha
		gen_ssa crypto::chacha bytes crypto::cipher crypto::math \
			endian io memio
	fi
}

crypto_chachapoly() {
	if [ $testing -eq 0 ]
	then
		gen_srcs crypto::chachapoly chachapoly.ha
	else
		gen_srcs crypto::chachapoly chachapoly.ha encryption+test.ha
	fi
	gen_ssa crypto::chachapoly bufio bytes crypto::chacha crypto::mac \
		crypto::math crypto::poly1305 endian errors io types
}

crypto_cipher() {
	gen_srcs crypto::cipher \
		cipher.ha \
		block.ha \
		cbc.ha \
		ctr.ha \
		stream.ha \
		gcm.ha \
		ghash.ha
	gen_ssa crypto::cipher crypto::math bytes endian errors io types
}

crypto_hkdf() {
	if [ $testing -eq 0 ]
	then
		gen_srcs crypto::hkdf hkdf.ha
		gen_ssa crypto::hkdf bytes crypto::hmac crypto::mac hash
	else
		gen_srcs crypto::hkdf hkdf.ha +test.ha
		gen_ssa crypto::hkdf bytes crypto::hmac crypto::mac hash \
			crypto::sha1 crypto::sha256
	fi
}

crypto_hmac() {
	if [ $testing -eq 0 ]
	then
		gen_srcs crypto::hmac \
			hmac.ha \
			sha1.ha \
			sha256.ha
		gen_ssa crypto::hmac crypto::mac crypto::sha1 crypto::sha256 hash io bytes
	else
		gen_srcs crypto::hmac \
			hmac.ha \
			sha1.ha \
			sha256.ha \
			+test.ha
		gen_ssa crypto::hmac bytes crypto::mac hash crypto::sha1 \
			crypto::sha256 encoding::hex io strings
	fi
}

crypto_mac() {
	gen_srcs crypto::mac \
		mac.ha
	gen_ssa crypto::mac io
}

crypto_math() {
	gen_srcs crypto::math \
		arithm.ha bits.ha
	gen_ssa crypto::math
}

crypto_poly1305() {
	if [ $testing -eq 0 ]
	then
		gen_srcs crypto::poly1305 \
			poly1305.ha
		gen_ssa crypto::poly1305 bytes crypto::mac endian io
	else
		gen_srcs crypto::poly1305 \
			poly1305.ha \
			+test.ha
		gen_ssa crypto::poly1305 bytes crypto::mac endian encoding::hex io
	fi
}

crypto_random() {
	gen_srcs -plinux crypto::random \
		+linux.ha \
		random.ha
	gen_ssa -plinux crypto::random rt io errors

	gen_srcs -pfreebsd crypto::random \
		+freebsd.ha \
		random.ha
	gen_ssa -pfreebsd crypto::random rt io errors
}

gensrcs_crypto_rsa() {
	gen_srcs crypto::rsa core.ha  errors.ha  keys.ha  pkcs1.ha $*
}

genssa_crypto_rsa() {
	gen_ssa crypto::rsa bufio bytes crypto::bigint crypto::math \
		crypto::sha1 crypto::sha256 crypto::sha512 endian errors hash \
		io memio types $*
}

crypto_rsa() {
	if [ $testing -eq 0 ]
	then
		gensrcs_crypto_rsa
		genssa_crypto_rsa
	else
		gensrcs_crypto_rsa +test/core_test.ha +test/keys_test.ha \
			+test/pkcs1_test.ha
		genssa_crypto_rsa
	fi
}

crypto_salsa() {
	if [ $testing -eq 0 ]
	then
		gen_srcs crypto::salsa salsa20.ha
		gen_ssa crypto::salsa bytes crypto::cipher crypto::math endian \
			io
	else
		gen_srcs crypto::salsa salsa20.ha +test.ha
		gen_ssa crypto::salsa bytes crypto::cipher crypto::math \
			endian io memio types
	fi
}

gensrcs_crypto_sha256() {
	gen_srcs crypto::sha256 \
		sha256.ha \
		$*
}

genssa_crypto_sha256() {
	gen_ssa crypto::sha256 crypto::math bytes hash io endian $*
}

crypto_sha256() {
	if [ $testing -eq 0 ]
	then
		gensrcs_crypto_sha256
		genssa_crypto_sha256
	else
		gensrcs_crypto_sha256 \
			+test.ha
		genssa_crypto_sha256 fmt strings encoding::hex
	fi
}

crypto_sha1() {
	if [ $testing -eq 0 ]
	then
		gen_srcs crypto::sha1 sha1.ha
		gen_ssa crypto::sha1 crypto::math bytes hash io endian
	else
		gen_srcs crypto::sha1 sha1.ha +test.ha
		gen_ssa crypto::sha1 crypto::math bytes hash endian fmt strings encoding::hex
	fi
}

crypto_sha512() {
	if [ $testing -eq 0 ]
	then
		gen_srcs crypto::sha512 sha512.ha
		gen_ssa crypto::sha512 crypto::math bytes hash io endian
	else
		gen_srcs crypto::sha512 sha512.ha +test.ha
		gen_ssa crypto::sha512 crypto::math bytes hash endian fmt strings encoding::hex
	fi
}

crypto_curve25519() {
	if [ $testing -eq 0 ]
	then
		gen_srcs crypto::curve25519 curve25519.ha
		gen_ssa crypto::curve25519 bytes
	else
		gen_srcs crypto::curve25519 curve25519.ha +test.ha
		gen_ssa crypto::curve25519 bytes fmt io encoding::hex crypto::random
	fi
}

crypto_ed25519() {
	if [ $testing -eq 0 ]
	then
		gen_srcs crypto::ed25519 ed25519.ha edwards25519.ha
		gen_ssa crypto::ed25519 bytes crypto::sha512 hash
	else
		gen_srcs crypto::ed25519 ed25519.ha edwards25519.ha +test.ha
		gen_ssa crypto::ed25519 bytes crypto::sha512 hash encoding::hex strings
	fi
}

crypto_x25519() {
	if [ $testing -eq 0 ]
	then
		gen_srcs crypto::x25519 x25519.ha
		gen_ssa crypto::x25519 crypto::curve25519
	else
		gen_srcs crypto::x25519 x25519.ha +test.ha
		gen_ssa crypto::x25519 bytes crypto::curve25519 encoding::hex \
			crypto::random
	fi
}

datetime() {
	gen_srcs -plinux datetime \
		arithmetic.ha \
		chronology.ha \
		errors.ha \
		date.ha \
		datetime.ha \
		duration.ha \
		format.ha \
		parse.ha \
		period.ha \
		reckon.ha \
		time.ha \
		timezone.ha \
		virtual.ha
	gen_ssa -plinux datetime ascii errors fmt io strconv strings memio \
		time time::chrono
	gen_srcs -pfreebsd datetime \
		arithmetic.ha \
		chronology.ha \
		errors.ha \
		date.ha \
		datetime.ha \
		duration.ha \
		format.ha \
		parse.ha \
		period.ha \
		reckon.ha \
		time.ha \
		timezone.ha \
		virtual.ha
	gen_ssa -pfreebsd datetime ascii errors fmt io strconv strings memio \
		time time::chrono
}

dirs() {
	gen_srcs dirs \
		xdg.ha
	gen_ssa dirs errors fs os path fmt unix
}

encoding_base64() {
	gen_srcs encoding::base64 \
		base64.ha
	gen_ssa encoding::base64 ascii bytes errors io os strings memio
}

encoding_base32() {
	gen_srcs encoding::base32 \
		base32.ha
	gen_ssa encoding::base32 ascii bytes errors io strings os memio
}

encoding_hex() {
	gen_srcs encoding::hex \
		hex.ha
	gen_ssa encoding::hex ascii bytes errors fmt io strconv memio \
		strings
}

encoding_pem() {
	if [ $testing -eq 0 ]
	then
		gen_srcs encoding::pem \
			pem.ha
		gen_ssa encoding::pem strings memio io errors \
			encoding::base64 ascii os fmt
	else
		gen_srcs encoding::pem \
			pem.ha \
			+test.ha
		gen_ssa encoding::pem strings memio io errors \
			encoding::base64 ascii os fmt bytes
	fi
}

encoding_utf8() {
	gen_srcs encoding::utf8 \
		decode.ha \
		decodetable.ha \
		encode.ha \
		rune.ha
	gen_ssa encoding::utf8 types
}

endian() {
	gen_srcs endian \
		big.ha \
		network.ha \
		little.ha \
		endian.ha \
		'host+$(ARCH).ha'
	gen_ssa endian
}

errors() {
	gen_srcs errors \
		common.ha \
		opaque.ha \
		string.ha \
		rt.ha
	gen_ssa errors rt
}

fmt() {
	gen_srcs fmt \
		fmt.ha
	gen_ssa fmt ascii encoding::utf8 io memio os strconv strings types
}

fnmatch() {
	if [ $testing -eq 0 ]
	then
		gen_srcs fnmatch fnmatch.ha
	else
		gen_srcs fnmatch fnmatch.ha +test.ha
	fi
	gen_ssa fnmatch ascii errors strings sort
}

format_elf() {
	gen_srcs format::elf \
		'arch+$(ARCH).ha' \
		'platform+$(PLATFORM).ha' \
		types.ha
	gen_ssa format::elf
}

gensrcs_format_ini() {
	gen_srcs format::ini \
		scan.ha \
		types.ha \
		$*
}

format_ini() {
	if [ $testing -eq 0 ]
	then
		gensrcs_format_ini
	else
		gensrcs_format_ini +test.ha
	fi
	gen_ssa format::ini encoding::utf8 fmt io memio strings
}

format_tar() {
	gen_srcs format::tar \
		types.ha \
		reader.ha
	gen_ssa format::tar bytes endian errors io strconv memio types::c
}

fs() {
	gen_srcs fs \
		types.ha \
		fs.ha \
		util.ha
	gen_ssa fs io strings path time errors
}

getopt() {
	gen_srcs getopt \
		getopts.ha
	gen_ssa getopt encoding::utf8 fmt io os strings
}

glob() {
	if [ $testing -eq 0 ]
	then
		gen_srcs glob glob.ha
	else
		gen_srcs glob glob.ha +test.ha
	fi
	gen_ssa glob fnmatch fs io os sort strings memio
}

hare_ast() {
	gen_srcs hare::ast \
		decl.ha \
		expr.ha \
		ident.ha \
		import.ha \
		type.ha \
		unit.ha
	gen_ssa hare::ast hare::lex strings
}

gensrcs_hare_lex() {
	gen_srcs hare::lex \
		token.ha \
		lex.ha \
		$*
}

hare_lex() {
	if [ $testing -eq 0 ]
	then
		gensrcs_hare_lex
	else
		gensrcs_hare_lex \
			+test.ha
	fi
	gen_ssa hare::lex ascii io encoding::utf8 fmt memio sort \
		strconv strings path
}

hare_module() {
	gen_srcs hare::module \
		cache.ha \
		deps.ha \
		types.ha \
		format.ha \
		srcs.ha \
		util.ha
	gen_ssa hare::module \
		ascii memio bytes datetime encoding::utf8 fmt fs hare::ast hare::lex \
		hare::parse hare::unparse io os path strings time time::chrono \
		time::date types encoding::hex
}

gensrcs_hare_parse() {
	gen_srcs hare::parse \
		decl.ha \
		expr.ha \
		ident.ha \
		import.ha \
		parse.ha \
		type.ha \
		unit.ha \
		$*
}

hare_parse() {
	if [ $testing -eq 0 ]
	then
		gensrcs_hare_parse
		gen_ssa hare::parse ascii hare::ast hare::lex fmt types \
			strings math
	else
		gensrcs_hare_parse \
			+test/expr_test.ha \
			+test/ident_test.ha \
			+test/loc.ha \
			+test/roundtrip.ha \
			+test/types.ha \
			+test/unit_test.ha
		gen_ssa hare::parse ascii memio hare::ast hare::lex \
			hare::unparse io fmt types strings math encoding::utf8
	fi
}

gensrcs_hare_types() {
	gen_srcs hare::types \
		'+$(ARCH)/writesize.ha' \
		arch.ha \
		builtins.ha \
		class.ha \
		hash.ha \
		lookup.ha \
		store.ha \
		types.ha \
		$*
}

hare_types() {
	if [ $testing -eq 1 ]
	then
		gensrcs_hare_types +test.ha
		gen_ssa hare::types hare::ast hash hash::fnv endian strings \
			errors sort fmt hare::lex hare::parse io
	else
		gensrcs_hare_types
		gen_ssa hare::types hare::ast hash hash::fnv endian strings \
			errors memio sort fmt
	fi
}

gensrcs_hare_unit() {
	gen_srcs hare::unit \
		check.ha \
		context.ha \
		errors.ha \
		expr.ha \
		process.ha \
		scan.ha \
		scope.ha \
		unit.ha \
		$*
}

hare_unit() {
	if [ $testing -eq 1 ]
	then
		gensrcs_hare_unit +test.ha
		gen_ssa hare::unit hare::ast hare::types hash hash::fnv \
			strings hare::lex hare::parse memio
	else
		gensrcs_hare_unit
		gen_ssa hare::unit hare::ast hare::types hash hash::fnv \
			strings hare::lex memio
	fi
}

hare_unparse() {
	gen_srcs hare::unparse \
		expr.ha \
		decl.ha \
		ident.ha \
		import.ha \
		type.ha \
		unit.ha \
		util.ha
	gen_ssa hare::unparse fmt io strings memio hare::ast hare::lex
}

hare_parse_doc() {
	gen_srcs hare::parse::doc \
		doc.ha
	gen_ssa hare::parse::doc ascii encoding::utf8 fmt hare::ast hare::parse io strings memio
}

hash() {
	gen_srcs hash \
		hash.ha
	gen_ssa hash crypto::math io fmt
}

hash_adler32() {
	gen_srcs hash::adler32 \
		adler32.ha
	gen_ssa hash::adler32 endian hash io strings
}

hash_crc16() {
	gen_srcs hash::crc16 \
		crc16.ha
	gen_ssa hash::crc16 endian hash io strings
}

hash_crc32() {
	gen_srcs hash::crc32 \
		crc32.ha
	gen_ssa hash::crc32 endian hash io strings
}

hash_crc64() {
	gen_srcs hash::crc64 \
		crc64.ha
	gen_ssa hash::crc64 endian hash io strings
}

hash_fnv() {
	gen_srcs hash::fnv \
		'+$(ARCH).ha' \
		fnv.ha
	gen_ssa hash::fnv endian hash io strings
}

hash_siphash() {
	if [ $testing -eq 0 ]
	then
		gen_srcs hash::siphash siphash.ha
		gen_ssa hash::siphash hash io endian crypto::math
	else
		gen_srcs hash::siphash siphash.ha +test.ha
		gen_ssa hash::siphash hash io endian crypto::math \
			fmt memio strings
	fi
}

gensrcs_io() {
	gen_srcs -plinux io \
		'arch+$(ARCH).ha' \
		+linux/mmap.ha \
		+linux/platform_file.ha \
		+linux/vector.ha \
		copy.ha \
		drain.ha \
		empty.ha \
		file.ha \
		handle.ha \
		limit.ha \
		stream.ha \
		tee.ha \
		types.ha \
		util.ha \
		zero.ha \
		$*
	gen_srcs -pfreebsd io \
		'arch+$(ARCH).ha' \
		+freebsd/mmap.ha \
		+freebsd/platform_file.ha \
		+freebsd/vector.ha \
		copy.ha \
		drain.ha \
		empty.ha \
		file.ha \
		handle.ha \
		limit.ha \
		stream.ha \
		tee.ha \
		types.ha \
		util.ha \
		zero.ha \
		$*
}

io() {
	if [ $testing -eq 0 ]
	then
		gensrcs_io
	else
		gensrcs_io \
			+test/limit_test.ha \
			+test/stream_test.ha
	fi
	gen_ssa -plinux io errors bytes rt
	gen_ssa -pfreebsd io errors bytes rt
}

linux() {
	gen_srcs -plinux linux \
		start.ha \
		env.ha
	gen_ssa -plinux linux format::elf rt
}

linux_keyctl() {
	gen_srcs -plinux linux::keyctl \
		keyctl.ha \
		types.ha
	gen_ssa -plinux linux::keyctl rt errors bytes types::c
}

linux_timerfd() {
	gen_srcs -plinux linux::timerfd \
		timerfd.ha
	gen_ssa -plinux linux::timerfd errors rt time io endian
}

linux_vdso() {
	gen_srcs -plinux linux::vdso \
		vdso.ha
	gen_ssa -plinux linux::vdso linux format::elf types::c
}

log() {
	gen_srcs -plinux log logger.ha global.ha funcs.ha silent.ha
	gen_ssa -plinux log fmt io os time::date
	gen_srcs -pfreebsd log logger.ha global.ha funcs.ha silent.ha
	gen_ssa -pfreebsd log fmt io os time::date
}

gensrcs_math() {
	gen_srcs math \
		math.ha \
		fenv_func.ha \
		'fenv+$(ARCH).ha' \
		floats.ha  \
		ints.ha \
		uints.ha \
		trig.ha \
		$*
}

math() {
	if [ $testing -eq 0 ]; then
		gensrcs_math
	else
		gensrcs_math \
			+test/data.ha \
			+test/math_test.ha \
			+test/floats_test.ha \
			+test/trig_test.ha
	fi
	gen_ssa math types rt
}

math_checked() {
	gen_srcs math::checked checked.ha
	gen_ssa math::checked math
}

mime() {
	# This module is not built by default because gen-stdlib does not do a good
	# job of resolving @init dependency ordering issues
	if [ $testing -eq 0 ]; then
		gen_srcs mime \
			database.ha \
			lookup.ha \
			parse.ha \
			system.ha
	else
		gen_srcs mime \
			database.ha \
			lookup.ha \
			parse.ha \
			system.ha \
			entries+test.ha
	fi
	gen_ssa mime ascii errors strings hash::fnv encoding::utf8 bufio \
		fs io os fmt
}

net() {
	gen_srcs -plinux net \
		+linux.ha \
		errors.ha \
		msg.ha \
		types.ha
	gen_ssa -plinux net io errors rt fmt

	gen_srcs -pfreebsd net \
		+freebsd.ha \
		errors.ha \
		msg.ha \
		types.ha
	gen_ssa -pfreebsd net io errors rt fmt
}

net_dial() {
	gen_srcs net::dial \
		registry.ha \
		dial.ha \
		ip.ha \
		resolve.ha
	gen_ssa net::dial net net::ip net::tcp net::udp net::dns net::uri \
		crypto::random strconv strings unix::hosts
}

net_dns() {
	gen_srcs net::dns \
		decode.ha \
		error.ha \
		encode.ha \
		query.ha \
		strdomain.ha \
		types.ha
	gen_ssa net::dns ascii endian net net::udp net::ip fmt strings \
		unix::resolvconf unix::poll time errors
}

gensrcs_net_ip() {
	gen_srcs -plinux net::ip \
		+linux.ha \
		ip.ha \
		$*
	gen_srcs -pfreebsd net::ip \
		+freebsd.ha \
		ip.ha \
		$*
}

net_ip() {
	if [ $testing -eq 0 ]
	then
		gensrcs_net_ip
	else
		gensrcs_net_ip \
			test+test.ha
	fi
	gen_ssa -plinux net::ip bytes endian io strconv strings memio fmt
	gen_ssa -pfreebsd net::ip bytes endian io strconv strings memio fmt
}

net_tcp() {
	gen_srcs -plinux net::tcp \
		+linux.ha \
		listener.ha \
		options.ha
	gen_ssa -plinux net::tcp errors io net net::ip os rt

	gen_srcs -pfreebsd net::tcp \
		+freebsd.ha \
		listener.ha \
		options.ha
	gen_ssa -pfreebsd net::tcp errors io net net::ip os rt
}

net_udp() {
	gen_srcs -plinux net::udp \
		+linux.ha \
		options.ha
	gen_ssa -plinux net::udp errors net net::ip errors rt os io

	gen_srcs -pfreebsd net::udp \
		+freebsd.ha \
		options.ha
	gen_ssa -pfreebsd net::udp errors net net::ip errors rt os io
}

net_unix() {
	gen_srcs -plinux net::unix \
		+linux.ha \
		addr.ha \
		cmsg.ha \
		dial.ha \
		listener.ha \
		options.ha \
		socketpair.ha
	gen_ssa -plinux net::unix net errors os io strings types fmt \
		net::dial rt

	gen_srcs -pfreebsd net::unix \
		+freebsd.ha \
		addr.ha \
		cmsg.ha \
		dial.ha \
		listener.ha \
		options.ha \
		socketpair.ha
	gen_ssa -pfreebsd net::unix net errors os io strings types fmt \
		net::dial rt
}

gensrcs_net_uri() {
	gen_srcs net::uri \
		fmt.ha \
		parse.ha \
		query.ha \
		uri.ha \
		$*
}

net_uri() {
	if [ $testing -eq 0 ]
	then
		gensrcs_net_uri
	else
		gensrcs_net_uri \
			+test.ha
	fi
	gen_ssa net::uri \
		ascii encoding::utf8 fmt io net::ip strconv strings memio
}

gensrcs_math_complex() {
	gen_srcs math::complex \
		complex.ha \
		$*
}

math_complex() {
	if [ $testing -eq 0 ]
	then
		gensrcs_math_complex
	else
		gensrcs_math_complex \
			+test.ha
	fi
	gen_ssa math::complex math
}

math_random() {
	gen_srcs math::random \
		random.ha
	gen_ssa math::random
}

os() {
	if [ $testing -eq 0 ]
	then
		exit=exit.ha
	else
		exit=exit+test.ha
	fi

	gen_srcs -plinux os \
		+linux/dirfdfs.ha \
		+linux/platform_environ.ha \
		+linux/$exit \
		+linux/fs.ha \
		+linux/memory.ha \
		+linux/status.ha \
		+linux/stdfd.ha \
		environ.ha \
		os.ha
	gen_ssa -plinux os io strings fs encoding::utf8 bufio \
		errors math types::c

	gen_srcs -pfreebsd os \
		+freebsd/platform_environ.ha \
		+freebsd/$exit \
		+freebsd/dirfdfs.ha \
		+freebsd/status.ha \
		+freebsd/stdfd.ha \
		+freebsd/fs.ha \
		environ.ha \
		os.ha
	gen_ssa -pfreebsd os io strings fs encoding::utf8 bufio \
		errors types::c
}

os_exec() {
	gen_srcs -plinux os::exec \
		exec+linux.ha \
		process+linux.ha \
		types.ha \
		cmd.ha
	gen_ssa -plinux os::exec os strings fmt errors unix rt io ascii \
		unix::signal types::c time

	gen_srcs -pfreebsd os::exec \
		exec+freebsd.ha \
		process+freebsd.ha \
		types.ha \
		cmd.ha
	gen_ssa -pfreebsd os::exec os strings fmt errors unix rt io ascii \
		unix::signal types::c time
}

path() {
	gen_srcs path \
		'+$(PLATFORM).ha' \
		buffer.ha \
		error.ha \
		stack.ha \
		ext_stack.ha \
		posix.ha \
		prefix.ha \
		iter.ha
	gen_ssa path strings bytes errors
}

regex() {
	if [ $testing -eq 0 ]; then
		gen_srcs regex regex.ha
		gen_ssa regex ascii bufio encoding::utf8 errors io strconv \
			strings bufio types memio
	else
		gen_srcs regex regex.ha +test.ha
		gen_ssa regex encoding::utf8 errors strconv strings fmt io os \
			bufio types memio
	fi
}

gensrcs_strconv() {
	gen_srcs strconv \
		types.ha \
		itos.ha \
		utos.ha \
		stou.ha \
		stoi.ha \
		numeric.ha \
		ftos.ha \
		stof.ha \
		stof_data.ha \
		$*
}

gensrcs_shlex() {
	gen_srcs shlex \
		escape.ha \
		split.ha \
		$*
}

shlex() {
	if [ $testing -eq 0 ]
	then
		gensrcs_shlex
	else
		gensrcs_shlex \
			+test.ha
	fi
	gen_ssa shlex ascii encoding::utf8 io strings memio
}

gensrcs_sort() {
	gen_srcs sort \
		bisect.ha \
		search.ha \
		sort.ha \
		types.ha \
		$*
}

sort() {
	if [ $testing -eq 0 ]
	then
		gensrcs_sort
		gen_ssa sort math strings types
	else
		gensrcs_sort \
			+test.ha
		gen_ssa sort math math::random strings types
	fi
}

strconv() {
	if [ $testing -eq 0 ]
	then
		gensrcs_strconv
	else
		gensrcs_strconv \
			+test/stou_test.ha \
			+test/stoi_test.ha
	fi
	gen_ssa strconv types strings ascii math bytes encoding::utf8
}

strings() {
	gen_srcs strings \
		concat.ha \
		contains.ha \
		dup.ha \
		iter.ha \
		runes.ha \
		sub.ha \
		suffix.ha \
		tokenize.ha \
		utf8.ha \
		index.ha \
		trim.ha \
		compare.ha \
		pad.ha \
		replace.ha
	gen_ssa strings bytes encoding::utf8 types
}

strings_template() {
	gen_srcs strings::template \
		template.ha
	gen_ssa strings::template ascii errors fmt io strings memio
}

memio() {
	gen_srcs memio \
		stream.ha \
		ops.ha
	gen_ssa memio errors io strings encoding::utf8
}

temp() {
	gen_srcs -plinux temp +linux.ha
	gen_ssa -plinux temp \
		crypto::random encoding::hex errors fs io os path memio fmt

	gen_srcs -pfreebsd temp +freebsd.ha
	gen_ssa -pfreebsd temp \
		crypto::random encoding::hex errors fs io os path memio fmt
}

time() {
	gen_srcs -plinux time \
		+linux/functions.ha \
		+linux/+'$(ARCH)'.ha \
		arithm.ha \
		conv.ha \
		types.ha
	gen_ssa -plinux time \
		linux::vdso math
	gen_srcs -pfreebsd time \
		+freebsd/functions.ha \
		arithm.ha \
		conv.ha \
		types.ha
	gen_ssa -pfreebsd time \
		math
}

time_chrono() {
	gen_srcs -plinux time::chrono \
		arithmetic.ha \
		+linux.ha \
		chronology.ha \
		error.ha \
		leapsec.ha \
		timescale.ha \
		timezone.ha \
		tzdb.ha
	gen_ssa -plinux time::chrono \
		bufio bytes encoding::utf8 endian errors fmt fs io os strconv strings time path
	gen_srcs -pfreebsd time::chrono \
		arithmetic.ha \
		+freebsd.ha \
		chronology.ha \
		error.ha \
		leapsec.ha \
		timescale.ha \
		timezone.ha \
		tzdb.ha
	gen_ssa -pfreebsd time::chrono \
		bufio bytes encoding::utf8 endian errors fmt fs io os strconv strings time path
}

time_date() {
	gen_srcs -plinux time::date \
		date.ha \
		daydate.ha \
		daytime.ha \
		error.ha \
		format.ha \
		locality.ha \
		observe.ha \
		parithm.ha \
		parse.ha \
		period.ha \
		reckon.ha \
		tarithm.ha \
		virtual.ha
	gen_ssa -plinux time::date \
		ascii errors fmt io strconv strings memio time time::chrono
	gen_srcs -pfreebsd time::date \
		date.ha \
		daydate.ha \
		daytime.ha \
		error.ha \
		format.ha \
		locality.ha \
		observe.ha \
		parithm.ha \
		parse.ha \
		period.ha \
		reckon.ha \
		tarithm.ha \
		virtual.ha
	gen_ssa -pfreebsd time::date \
		ascii errors fmt io strconv strings memio time time::chrono
}

types() {
	gen_srcs types \
		limits.ha \
		classes.ha \
		'arch+$(ARCH).ha'
	gen_ssa types
}

types_c() {
	if [ $testing -eq 1 ]
	then
		gen_srcs types::c +test.ha strings.ha types.ha 'arch+$(ARCH).ha'
	else
		gen_srcs types::c strings.ha types.ha 'arch+$(ARCH).ha'
	fi
	gen_ssa types::c encoding::utf8 types
}

unix() {
	gen_srcs -plinux unix \
		+linux/nice.ha \
		+linux/pipe.ha \
		+linux/umask.ha \
		+linux/getuid.ha \
		+linux/setuid.ha \
		+linux/groups.ha
	gen_ssa -plinux unix errors fs io

	gen_srcs -pfreebsd unix \
		+freebsd/nice.ha \
		+freebsd/pipe.ha \
		+freebsd/umask.ha \
		+freebsd/getuid.ha \
		+freebsd/setuid.ha \
		+freebsd/groups.ha
	gen_ssa -pfreebsd unix errors fs io
}

unix_hosts() {
	if [ $testing -eq 0 ]
	then
    		gen_srcs -plinux unix::hosts \
    			+linux.ha \
    			hosts.ha
    		gen_ssa -plinux unix::hosts bufio encoding::utf8 fs io \
    			net::ip os strings memio

    		gen_srcs -pfreebsd unix::hosts \
    			+freebsd.ha \
    			hosts.ha
    		gen_ssa -pfreebsd unix::hosts bufio encoding::utf8 fs io \
    			net::ip os strings memio
	else
    		gen_srcs -plinux unix::hosts \
    			+linux.ha \
    			test+test.ha \
    			hosts.ha
    		gen_ssa -plinux unix::hosts bufio encoding::utf8 fs io \
    			net::ip os strings memio

    		gen_srcs -pfreebsd unix::hosts \
    			+freebsd.ha \
    			test+test.ha \
    			hosts.ha
    		gen_ssa -pfreebsd unix::hosts bufio encoding::utf8 fs io \
    			net::ip os strings memio
	fi
}

unix_passwd() {
	gen_srcs unix::passwd \
		group.ha \
		passwd.ha \
		types.ha
	gen_ssa unix::passwd bufio io os strconv strings memio
}

unix_poll() {
	gen_srcs -plinux unix::poll +linux.ha types.ha
	gen_ssa -plinux unix::poll rt errors time io

	gen_srcs -pfreebsd unix::poll +freebsd.ha types.ha
	gen_ssa -pfreebsd unix::poll rt errors time io
}

unix_resolvconf() {
	gen_srcs -plinux unix::resolvconf \
		+linux.ha \
		load.ha
	gen_ssa -plinux unix::resolvconf os io bufio memio net::ip strings

	gen_srcs -pfreebsd unix::resolvconf \
		+freebsd.ha \
		load.ha
	gen_ssa -pfreebsd unix::resolvconf os io bufio memio net::ip strings
}

unix_signal() {
	gen_srcs -plinux unix::signal \
		types.ha \
		+linux.ha
	gen_ssa -plinux unix::signal io errors rt

	gen_srcs -pfreebsd unix::signal \
		types.ha \
		+freebsd.ha
	gen_ssa -pfreebsd unix::signal io errors rt
}

unix_tty() {
	gen_srcs -plinux unix::tty \
		types.ha \
		pty_common.ha \
		+linux/isatty.ha \
		+linux/open.ha \
		+linux/pty.ha \
		+linux/termios.ha \
		+linux/winsize.ha
	gen_ssa -plinux unix::tty bufio errors fmt fs io os rt strings

	gen_srcs -pfreebsd unix::tty \
		types.ha \
		pty_common.ha \
		+freebsd/isatty.ha \
		+freebsd/open.ha \
		+freebsd/pty.ha \
		+freebsd/winsize.ha
	gen_ssa -pfreebsd unix::tty bufio errors fmt fs io os rt strings \
		types::c
}

uuid() {
	gen_srcs uuid \
		uuid.ha
	gen_ssa uuid crypto::random fmt endian io bytes memio strings strconv
}

# List of modules and their supported platforms. Place a tab between the module
# and its platform list, and spaces between each supported platform. Omitting
# the platform list implies all platforms are supported.
modules="ascii
bufio
bytes
cmd::hare::build
crypto
crypto::aes
crypto::aes::xts
crypto::argon2
crypto::bcrypt
crypto::blake2b
crypto::blowfish
crypto::bigint
crypto::chacha
crypto::chachapoly
crypto::cipher
crypto::hkdf
crypto::hmac
crypto::mac
crypto::math
crypto::random	linux freebsd
crypto::rsa
crypto::poly1305
crypto::salsa
crypto::sha1
crypto::sha256
crypto::sha512
crypto::curve25519
crypto::ed25519
crypto::x25519
dirs
encoding::base64
encoding::base32
encoding::hex
encoding::pem
encoding::utf8
endian
errors
fmt
fnmatch
format::elf
format::ini
format::tar
fs
getopt
glob
hare::ast
hare::lex
hare::module
hare::parse
hare::parse::doc
hare::types
hare::unit
hare::unparse
hash
hash::adler32
hash::crc16
hash::crc32
hash::crc64
hash::fnv
hash::siphash
io			linux freebsd
linux			linux
linux::keyctl		linux
linux::timerfd	linux
linux::vdso		linux
log	linux freebsd
math
math::checked
math::complex
math::random
memio
net			linux freebsd
net::dial
net::dns
net::ip			linux freebsd
net::tcp		linux freebsd
net::udp		linux freebsd
net::unix		linux freebsd
net::uri
os			linux freebsd
os::exec		linux freebsd
path
regex
shlex
sort
strconv
strings
strings::template
temp			linux freebsd
test
time			linux freebsd
time::chrono	linux freebsd
time::date	linux freebsd
types
types::c
unix			linux freebsd
unix::hosts	linux freebsd
unix::passwd
unix::poll		linux freebsd
unix::resolvconf	linux freebsd
unix::signal		linux freebsd
unix::tty		linux freebsd
uuid"
stdlib() {
	rt
	IFS="
"
	for module in $modules; do
		unset IFS
		if [ -z "$(echo "$module" | cut -sf1)" ]
		then
			gen_lib "$module"
		else
			platforms="$(echo "$module" | cut -sf2-)"
			module="$(echo "$module" | cut -sf1)"
			for platform in $platforms
			do
				gen_lib -p "$platform" "$module"
			done
		fi
		IFS="
"
	done
	IFS="
"
	for module in $modules; do
		unset IFS
		if [ -n "$(echo "$module" | cut -sf1)" ]
		then
			module="$(echo "$module" | cut -sf1)"
		fi
		"$(mod_file "$module")"
		IFS="
"
	done
	unset IFS
}

if [ ${DOCS:-0} -ne 1 ]
then
	printf '# This file is generated by the gen-stdlib script, do not edit it by hand\n\n'
	genrules
	genrules test
fi
diff --git a/scripts/gen-stdlib.sh b/scripts/gen-stdlib.sh
deleted file mode 100644
index ec431943..00000000
--- a/scripts/gen-stdlib.sh
@@ -1,138 +0,0 @@
mod_path() {
	printf '%s\n' "$1" | tr -s '::' '/'
}
mod_file() {
	printf '%s\n' "$1" | tr -s '::' '_'
}
mod_var() {
	printf '%s_%s_%s\n' "$stdlib" "$1" "$2" | tr -s '::' '_'
}

gen_srcs() {
	platform=any
	OPTIND=1
	while getopts p: name
	do
		case $name in
		p)
			platform="$OPTARG"
			;;
		?)
			printf 'Invalid use of gen_srcs' >&2
			exit 1
			;;
		esac
	done
	shift $(($OPTIND - 1))

	mod="$1"
	shift

	path="$(mod_path "$mod")"
	var="$(mod_var "$mod" "$platform")"

	printf '# %s (+%s)\n' "$mod" "$platform"
	printf '%s_srcs = \\\n' "$var"
	while [ $# -ne 0 ]
	do
		if [ $# -eq 1 ]
		then
			printf '\t$(STDLIB)/%s/%s\n\n' "$path" "$1"
		else
			printf '\t$(STDLIB)/%s/%s \\\n' "$path" "$1"
		fi
		shift
	done
}

gen_ssa() {
	platform=any
	OPTIND=1
	while getopts p: name
	do
		case $name in
		p)
			platform="$OPTARG"
			;;
		?)
			printf 'Invalid use of gen_ssa' >&2
			exit 1
			;;
		esac
	done
	shift $(($OPTIND - 1))

	mod="$1"
	shift

	path=$(mod_path "$mod")
	file=$(mod_file "$mod")
	var=$(mod_var "$mod" "$platform")

	printf "\$($cache)/$path/$file-$platform.ssa: \$(${var}_srcs) \$(${stdlib}_rt)"
	for dep in $*
	do
		printf ' $(%s)' "$(mod_var "$dep" \$"(PLATFORM)")"
	done
	printf '\n'

	cat <<EOF
	@printf 'HAREC \t\$@\n'
	@mkdir -p \$($cache)/$path
	@\$(${stdlib}_env) \$(HAREC) \$($flags) -o \$@ -N$mod \\
		-t\$($cache)/$path/$file.td \$(${var}_srcs)

EOF
}

gen_lib() {
	platform=any
	OPTIND=1
	while getopts p: name
	do
		case $name in
		p)
			platform="$OPTARG"
			;;
		?)
			printf 'Invalid use of gen_lib' >&2
			exit 1
			;;
		esac
	done
	shift $(($OPTIND - 1))

	printf "# gen_lib $1 ($platform)\n"

	mod="$1"
	path=$(mod_path "$mod")
	file=$(mod_file "$mod")
	var=$(mod_var "$mod" "$platform")
	printf "%s = \$(%s)/%s/%s-%s.o\n" "$var" "$cache" "$path" "$file" "$platform"
	printf "%s_env += HARE_TD_%s=\$(%s)/%s/%s.td\n" "$stdlib" "$mod" "$cache" "$path" "$file"
	printf '%s_deps_%s += $(%s)\n' "$stdlib" "$platform" "$var"
	if [ "$platform" = "any" ]
	then
		for p in $all_platforms
		do
			printf '%s = $(%s)\n' "$(mod_var "$mod" "$p")" "$var"
		done
	fi
	printf '\n'
}

genrules() {
	if [ $# -gt 0 ] && [ "$1" = "test" ]
	then
		cache=TESTCACHE
		flags=TESTHARECFLAGS
		testing=1
		stdlib=testlib
	else
		cache=HARECACHE
		flags=HARECFLAGS
		testing=0
		stdlib=stdlib
	fi
	stdlib
}
diff --git a/scripts/genbootstrap b/scripts/genbootstrap
new file mode 100755
index 00000000..f814b494
--- /dev/null
+++ b/scripts/genbootstrap
@@ -0,0 +1,11 @@
#!/bin/sh -eu

cd "$(dirname "$0")/.."
mkdir -p "${BINOUT:-.bin}" makefiles/
hare build -o ${BINOUT:-.bin}/genbootstrap cmd/genbootstrap
for platform in linux freebsd; do
	for arch in x86_64 aarch64 riscv64; do
		echo makefiles/$platform.$arch.mk
		${BINOUT:-.bin}/genbootstrap $platform $arch >makefiles/$platform.$arch.mk
	done
done
diff --git a/scripts/install-mods b/scripts/install-mods
deleted file mode 100755
index 7afe866b..00000000
--- a/scripts/install-mods
@@ -1,45 +0,0 @@
#!/bin/sh
modules="ascii
bufio
bytes
crypto
dirs
encoding
endian
errors
fmt
fnmatch
format
fs
getopt
glob
hare
hash
io
linux
log
math
memio
mime
net
os
path
regex
rt
shlex
sort
strconv
strings
temp
test
time
types
unix
uuid"
IFS="
"
for mod in $modules
do
	printf 'install %s\n' "$mod"
	cp -R $mod $1
done
diff --git a/scripts/moddirs b/scripts/moddirs
new file mode 100755
index 00000000..58b2d743
--- /dev/null
+++ b/scripts/moddirs
@@ -0,0 +1,4 @@
#!/bin/sh
find . -type d -maxdepth 1 \
| cut -d/ -f2 \
| sed -E '/^(\..*|cmd|contrib|docs|makefiles|scripts)$/d'
diff --git a/scripts/modules b/scripts/modules
deleted file mode 100755
index d0e80ee9..00000000
--- a/scripts/modules
@@ -1,27 +0,0 @@
#!/bin/sh
set -e

lookup() {
	for i in "$1"/*
	do
		i="${i#./}"
		[ -d "$i" ] || continue
		case "$i" in
			.*|*+*|cmd|contrib|docs|scripts)
				continue
				;;
			*)
				for j in "$i"/*.ha
				do
					[ -e "$j" ] || break
					i="$(printf '%s\n' "${i%/}" | sed 's|/|::|g')"
					printf 'use %s;\n' "$i"
					break
				done
				lookup "$i"
				;;
		esac
	done
}

lookup .
diff --git a/stdlib.mk b/stdlib.mk
deleted file mode 100644
index 90626961..00000000
--- a/stdlib.mk
@@ -1,4962 +0,0 @@
# This file is generated by the gen-stdlib script, do not edit it by hand

rtscript = $(STDLIB)/rt/hare.sc
# rt (+linux)
stdlib_rt_linux_srcs = \
	$(STDLIB)/rt/+linux/platform_abort.ha \
	$(STDLIB)/rt/+linux/env.ha \
	$(STDLIB)/rt/+linux/errno.ha \
	$(STDLIB)/rt/+linux/types.ha \
	$(STDLIB)/rt/+linux/segmalloc.ha \
	$(STDLIB)/rt/+linux/platformstart-libc.ha \
	$(STDLIB)/rt/+linux/prctl.ha \
	$(STDLIB)/rt/+linux/+$(ARCH).ha \
	$(STDLIB)/rt/+linux/syscallno+$(ARCH).ha \
	$(STDLIB)/rt/+linux/syscalls.ha \
	$(STDLIB)/rt/+linux/signal.ha \
	$(STDLIB)/rt/+linux/stat.ha \
	$(STDLIB)/rt/+linux/socket.ha \
	$(STDLIB)/rt/+$(ARCH)/arch_jmp.ha \
	$(STDLIB)/rt/+$(ARCH)/backtrace.ha \
	$(STDLIB)/rt/fenv_defs.ha \
	$(STDLIB)/rt/+$(ARCH)/cpuid.ha \
	$(STDLIB)/rt/ensure.ha \
	$(STDLIB)/rt/jmp.ha \
	$(STDLIB)/rt/malloc.ha \
	$(STDLIB)/rt/memcpy.ha \
	$(STDLIB)/rt/memfunc_ptr.ha \
	$(STDLIB)/rt/memmove.ha \
	$(STDLIB)/rt/memset.ha \
	$(STDLIB)/rt/strcmp.ha \
	$(STDLIB)/rt/unknown_errno.ha \
	$(STDLIB)/rt/u64tos.ha \
	$(STDLIB)/rt/abort.ha \
	$(STDLIB)/rt/start.ha

# rt (+freebsd)
stdlib_rt_freebsd_srcs = \
	$(STDLIB)/rt/+freebsd/platform_abort.ha \
	$(STDLIB)/rt/+freebsd/env.ha \
	$(STDLIB)/rt/+freebsd/errno.ha \
	$(STDLIB)/rt/+freebsd/platformstart.ha \
	$(STDLIB)/rt/+freebsd/segmalloc.ha \
	$(STDLIB)/rt/+freebsd/signal.ha \
	$(STDLIB)/rt/+freebsd/socket.ha \
	$(STDLIB)/rt/+freebsd/+$(ARCH).ha \
	$(STDLIB)/rt/+freebsd/syscallno.ha \
	$(STDLIB)/rt/+freebsd/syscalls.ha \
	$(STDLIB)/rt/+freebsd/types.ha \
	$(STDLIB)/rt/+$(ARCH)/arch_jmp.ha \
	$(STDLIB)/rt/+$(ARCH)/backtrace.ha \
	$(STDLIB)/rt/fenv_defs.ha \
	$(STDLIB)/rt/+$(ARCH)/cpuid.ha \
	$(STDLIB)/rt/ensure.ha \
	$(STDLIB)/rt/jmp.ha \
	$(STDLIB)/rt/malloc.ha \
	$(STDLIB)/rt/memcpy.ha \
	$(STDLIB)/rt/memfunc_ptr.ha \
	$(STDLIB)/rt/memmove.ha \
	$(STDLIB)/rt/memset.ha \
	$(STDLIB)/rt/strcmp.ha \
	$(STDLIB)/rt/unknown_errno.ha \
	$(STDLIB)/rt/u64tos.ha \
	$(STDLIB)/rt/abort.ha \
	$(STDLIB)/rt/start.ha

$(HARECACHE)/rt/rt-linux.ssa: $(stdlib_rt_linux_srcs) $(stdlib_rt)
	@printf 'HAREC \t$@\n'
	@mkdir -p $(HARECACHE)/rt
	@$(stdlib_env) $(HAREC) $(HARECFLAGS) -o $@ -Nrt \
		-t$(HARECACHE)/rt/rt.td $(stdlib_rt_linux_srcs)

$(HARECACHE)/rt/rt-freebsd.ssa: $(stdlib_rt_freebsd_srcs) $(stdlib_rt)
	@printf 'HAREC \t$@\n'
	@mkdir -p $(HARECACHE)/rt
	@$(stdlib_env) $(HAREC) $(HARECFLAGS) -o $@ -Nrt \
		-t$(HARECACHE)/rt/rt.td $(stdlib_rt_freebsd_srcs)

$(HARECACHE)/rt/start.o: $(STDLIB)/rt/+$(PLATFORM)/start+$(ARCH)-libc.s
	@printf 'AS \t%s\n' "$@"
	@mkdir -p $(HARECACHE)/rt
	@$(AS) -o $@ $(STDLIB)/rt/+$(PLATFORM)/start+$(ARCH)-libc.s

stdlib_asm = $(HARECACHE)/rt/syscall.o \
	$(HARECACHE)/rt/setjmp.o \
	$(HARECACHE)/rt/longjmp.o \
	$(HARECACHE)/rt/restore.o \
	$(HARECACHE)/rt/getfp.o \
	$(HARECACHE)/rt/fenv.o \
	$(HARECACHE)/rt/start.o \
	$(HARECACHE)/rt/cpuid.o

$(HARECACHE)/rt/syscall.o: $(STDLIB)/rt/+$(PLATFORM)/syscall+$(ARCH).s
	@printf 'AS \t%s\n' "$@"
	@mkdir -p $(HARECACHE)/rt
	@$(AS) -o $@ $(STDLIB)/rt/+$(PLATFORM)/syscall+$(ARCH).s

$(HARECACHE)/rt/setjmp.o: $(STDLIB)/rt/+$(ARCH)/setjmp.s
	@printf 'AS \t%s\n' "$@"
	@mkdir -p $(HARECACHE)/rt
	@$(AS) -o $@ $(STDLIB)/rt/+$(ARCH)/setjmp.s

$(HARECACHE)/rt/longjmp.o: $(STDLIB)/rt/+$(ARCH)/longjmp.s
	@printf 'AS \t%s\n' "$@"
	@mkdir -p $(HARECACHE)/rt
	@$(AS) -o $@ $(STDLIB)/rt/+$(ARCH)/longjmp.s

$(HARECACHE)/rt/restore.o: $(STDLIB)/rt/+$(ARCH)/restore.s
	@printf 'AS \t%s\n' "$@"
	@mkdir -p $(HARECACHE)/rt
	@$(AS) -o $@ $(STDLIB)/rt/+$(ARCH)/restore.s

$(HARECACHE)/rt/fenv.o: $(STDLIB)/rt/+$(ARCH)/fenv.s
	@printf 'AS \t%s\n' "$@"
	@mkdir -p $(HARECACHE)/rt
	@$(AS) -o $@ $(STDLIB)/rt/+$(ARCH)/fenv.s

$(HARECACHE)/rt/getfp.o: $(STDLIB)/rt/+$(ARCH)/getfp.s
	@printf 'AS \t%s\n' "$@"
	@mkdir -p $(HARECACHE)/rt
	@$(AS) -o $@ $(STDLIB)/rt/+$(ARCH)/getfp.s

$(HARECACHE)/rt/cpuid.o: $(STDLIB)/rt/+$(ARCH)/cpuid.s
	@printf 'AS \t%s\n' "$@"
	@mkdir -p $(HARECACHE)/rt
	@$(AS) -o $@ $(STDLIB)/rt/+$(ARCH)/cpuid.s

$(HARECACHE)/rt/rt-linux.a: $(HARECACHE)/rt/rt-linux.o $(stdlib_asm)
	@printf 'AR \t%s\n' "$@"
	@$(AR) -csr $@ $(HARECACHE)/rt/rt-linux.o $(stdlib_asm)

$(HARECACHE)/rt/rt-freebsd.a: $(HARECACHE)/rt/rt-freebsd.o $(stdlib_asm)
	@printf 'AR \t%s\n' "$@"
	@$(AR) -csr $@ $(HARECACHE)/rt/rt-freebsd.o $(stdlib_asm)

stdlib_rt = $(HARECACHE)/rt/rt-$(PLATFORM).a
stdlib_env += HARE_TD_rt=$(HARECACHE)/rt/rt.td
stdlib_deps_linux += $(stdlib_rt)
stdlib_deps_freebsd += $(stdlib_rt)
stdlib_deps_any += $(stdlib_rt)

# gen_lib ascii (any)
stdlib_ascii_any = $(HARECACHE)/ascii/ascii-any.o
stdlib_env += HARE_TD_ascii=$(HARECACHE)/ascii/ascii.td
stdlib_deps_any += $(stdlib_ascii_any)
stdlib_ascii_linux = $(stdlib_ascii_any)
stdlib_ascii_freebsd = $(stdlib_ascii_any)

# gen_lib bufio (any)
stdlib_bufio_any = $(HARECACHE)/bufio/bufio-any.o
stdlib_env += HARE_TD_bufio=$(HARECACHE)/bufio/bufio.td
stdlib_deps_any += $(stdlib_bufio_any)
stdlib_bufio_linux = $(stdlib_bufio_any)
stdlib_bufio_freebsd = $(stdlib_bufio_any)

# gen_lib bytes (any)
stdlib_bytes_any = $(HARECACHE)/bytes/bytes-any.o
stdlib_env += HARE_TD_bytes=$(HARECACHE)/bytes/bytes.td
stdlib_deps_any += $(stdlib_bytes_any)
stdlib_bytes_linux = $(stdlib_bytes_any)
stdlib_bytes_freebsd = $(stdlib_bytes_any)

# gen_lib cmd::hare::build (any)
stdlib_cmd_hare_build_any = $(HARECACHE)/cmd/hare/build/cmd_hare_build-any.o
stdlib_env += HARE_TD_cmd::hare::build=$(HARECACHE)/cmd/hare/build/cmd_hare_build.td
stdlib_deps_any += $(stdlib_cmd_hare_build_any)
stdlib_cmd_hare_build_linux = $(stdlib_cmd_hare_build_any)
stdlib_cmd_hare_build_freebsd = $(stdlib_cmd_hare_build_any)

# gen_lib crypto (any)
stdlib_crypto_any = $(HARECACHE)/crypto/crypto-any.o
stdlib_env += HARE_TD_crypto=$(HARECACHE)/crypto/crypto.td
stdlib_deps_any += $(stdlib_crypto_any)
stdlib_crypto_linux = $(stdlib_crypto_any)
stdlib_crypto_freebsd = $(stdlib_crypto_any)

# gen_lib crypto::aes (any)
stdlib_crypto_aes_any = $(HARECACHE)/crypto/aes/crypto_aes-any.o
stdlib_env += HARE_TD_crypto::aes=$(HARECACHE)/crypto/aes/crypto_aes.td
stdlib_deps_any += $(stdlib_crypto_aes_any)
stdlib_crypto_aes_linux = $(stdlib_crypto_aes_any)
stdlib_crypto_aes_freebsd = $(stdlib_crypto_aes_any)

# gen_lib crypto::aes::xts (any)
stdlib_crypto_aes_xts_any = $(HARECACHE)/crypto/aes/xts/crypto_aes_xts-any.o
stdlib_env += HARE_TD_crypto::aes::xts=$(HARECACHE)/crypto/aes/xts/crypto_aes_xts.td
stdlib_deps_any += $(stdlib_crypto_aes_xts_any)
stdlib_crypto_aes_xts_linux = $(stdlib_crypto_aes_xts_any)
stdlib_crypto_aes_xts_freebsd = $(stdlib_crypto_aes_xts_any)

# gen_lib crypto::argon2 (any)
stdlib_crypto_argon2_any = $(HARECACHE)/crypto/argon2/crypto_argon2-any.o
stdlib_env += HARE_TD_crypto::argon2=$(HARECACHE)/crypto/argon2/crypto_argon2.td
stdlib_deps_any += $(stdlib_crypto_argon2_any)
stdlib_crypto_argon2_linux = $(stdlib_crypto_argon2_any)
stdlib_crypto_argon2_freebsd = $(stdlib_crypto_argon2_any)

# gen_lib crypto::bcrypt (any)
stdlib_crypto_bcrypt_any = $(HARECACHE)/crypto/bcrypt/crypto_bcrypt-any.o
stdlib_env += HARE_TD_crypto::bcrypt=$(HARECACHE)/crypto/bcrypt/crypto_bcrypt.td
stdlib_deps_any += $(stdlib_crypto_bcrypt_any)
stdlib_crypto_bcrypt_linux = $(stdlib_crypto_bcrypt_any)
stdlib_crypto_bcrypt_freebsd = $(stdlib_crypto_bcrypt_any)

# gen_lib crypto::blake2b (any)
stdlib_crypto_blake2b_any = $(HARECACHE)/crypto/blake2b/crypto_blake2b-any.o
stdlib_env += HARE_TD_crypto::blake2b=$(HARECACHE)/crypto/blake2b/crypto_blake2b.td
stdlib_deps_any += $(stdlib_crypto_blake2b_any)
stdlib_crypto_blake2b_linux = $(stdlib_crypto_blake2b_any)
stdlib_crypto_blake2b_freebsd = $(stdlib_crypto_blake2b_any)

# gen_lib crypto::blowfish (any)
stdlib_crypto_blowfish_any = $(HARECACHE)/crypto/blowfish/crypto_blowfish-any.o
stdlib_env += HARE_TD_crypto::blowfish=$(HARECACHE)/crypto/blowfish/crypto_blowfish.td
stdlib_deps_any += $(stdlib_crypto_blowfish_any)
stdlib_crypto_blowfish_linux = $(stdlib_crypto_blowfish_any)
stdlib_crypto_blowfish_freebsd = $(stdlib_crypto_blowfish_any)

# gen_lib crypto::bigint (any)
stdlib_crypto_bigint_any = $(HARECACHE)/crypto/bigint/crypto_bigint-any.o
stdlib_env += HARE_TD_crypto::bigint=$(HARECACHE)/crypto/bigint/crypto_bigint.td
stdlib_deps_any += $(stdlib_crypto_bigint_any)
stdlib_crypto_bigint_linux = $(stdlib_crypto_bigint_any)
stdlib_crypto_bigint_freebsd = $(stdlib_crypto_bigint_any)

# gen_lib crypto::chacha (any)
stdlib_crypto_chacha_any = $(HARECACHE)/crypto/chacha/crypto_chacha-any.o
stdlib_env += HARE_TD_crypto::chacha=$(HARECACHE)/crypto/chacha/crypto_chacha.td
stdlib_deps_any += $(stdlib_crypto_chacha_any)
stdlib_crypto_chacha_linux = $(stdlib_crypto_chacha_any)
stdlib_crypto_chacha_freebsd = $(stdlib_crypto_chacha_any)

# gen_lib crypto::chachapoly (any)
stdlib_crypto_chachapoly_any = $(HARECACHE)/crypto/chachapoly/crypto_chachapoly-any.o
stdlib_env += HARE_TD_crypto::chachapoly=$(HARECACHE)/crypto/chachapoly/crypto_chachapoly.td
stdlib_deps_any += $(stdlib_crypto_chachapoly_any)
stdlib_crypto_chachapoly_linux = $(stdlib_crypto_chachapoly_any)
stdlib_crypto_chachapoly_freebsd = $(stdlib_crypto_chachapoly_any)

# gen_lib crypto::cipher (any)
stdlib_crypto_cipher_any = $(HARECACHE)/crypto/cipher/crypto_cipher-any.o
stdlib_env += HARE_TD_crypto::cipher=$(HARECACHE)/crypto/cipher/crypto_cipher.td
stdlib_deps_any += $(stdlib_crypto_cipher_any)
stdlib_crypto_cipher_linux = $(stdlib_crypto_cipher_any)
stdlib_crypto_cipher_freebsd = $(stdlib_crypto_cipher_any)

# gen_lib crypto::hkdf (any)
stdlib_crypto_hkdf_any = $(HARECACHE)/crypto/hkdf/crypto_hkdf-any.o
stdlib_env += HARE_TD_crypto::hkdf=$(HARECACHE)/crypto/hkdf/crypto_hkdf.td
stdlib_deps_any += $(stdlib_crypto_hkdf_any)
stdlib_crypto_hkdf_linux = $(stdlib_crypto_hkdf_any)
stdlib_crypto_hkdf_freebsd = $(stdlib_crypto_hkdf_any)

# gen_lib crypto::hmac (any)
stdlib_crypto_hmac_any = $(HARECACHE)/crypto/hmac/crypto_hmac-any.o
stdlib_env += HARE_TD_crypto::hmac=$(HARECACHE)/crypto/hmac/crypto_hmac.td
stdlib_deps_any += $(stdlib_crypto_hmac_any)
stdlib_crypto_hmac_linux = $(stdlib_crypto_hmac_any)