# SPDX-License-Identifier: AGPL-3.0-or-later
# Copyright (C) 2026 David (Corey) Herrera
# Foundry Blackhole backend — Phase 3 host-side conversion tests.
#
# Nothing here touches the card: the block-float comparison runs against the
# committed reference vectors in ../reference/ (regenerate: `make bfp-reference`). Everything builds and runs on the
# Mac, which is also where the real conversion runs (spec §8.4).
#
# `make red` exists because a green test nobody has watched fail is not
# evidence (coding-best-practices.md §9). It rebuilds from scratch: Apple ships
# GNU make 3.81, whose one-second mtime granularity silently skips a rebuild of
# a source edited in the same second as its object, so a mutation loop that
# relies on incremental make can be testing the PREVIOUS binary.

CC      ?= cc
CONVERT := ..
TT      := ../..
BUILD   := build

CFLAGS  := -std=c99 -O1 -g \
           -Wall -Wextra -Werror -pedantic \
           -Wshadow -Wconversion -Wstrict-prototypes -Wformat=2 \
           -fstack-protector-strong \
           -I$(CONVERT) -I$(TT) -I$(CONVERT)/reference

# macOS puts libm inside libSystem, so this suite linked on the Mac without it
# and failed to link on the card host the first time anyone tried — the same shape of
# gap as the MADV_DONTNEED one in ft_gguf_map.c. The converter uses sqrt() for
# every error figure it reports, so this is not optional anywhere.
LDLIBS  := -lm

BFP_SOURCES := $(CONVERT)/ft_bfp.c $(TT)/ft_tt_tilize.c test_bfp.c
BFP_TARGET  := $(BUILD)/test_bfp

CONVERT_SOURCES := $(CONVERT)/ft_bfp.c \
                   $(CONVERT)/ft_float_convert.c \
                   $(CONVERT)/ft_gguf_map.c \
                   $(CONVERT)/ft_gguf_dequant.c \
                   $(CONVERT)/ft_tt_precision_ledger.c \
                   $(CONVERT)/ft_tt_weight_convert.c \
                   $(TT)/ft_tt_tilize.c \
                   test_convert.c
CONVERT_TARGET  := $(BUILD)/test_convert

CACHE_SOURCES := $(CONVERT)/ft_bfp.c \
                 $(CONVERT)/ft_float_convert.c \
                 $(CONVERT)/ft_gguf_map.c \
                 $(CONVERT)/ft_gguf_dequant.c \
                 $(CONVERT)/ft_tt_precision_ledger.c \
                 $(CONVERT)/ft_tt_weight_convert.c \
                 $(CONVERT)/ft_tt_capacity_plan.c \
                 $(CONVERT)/ft_tt_artifact_provenance.c \
                 $(CONVERT)/ft_tt_artifact_cache.c \
                 $(TT)/ft_tt_tilize.c \
                 test_artifact_cache.c
CACHE_TARGET  := $(BUILD)/test_artifact_cache

.PHONY: all check red clean bfp-reference

all: $(BFP_TARGET) $(CONVERT_TARGET) $(CACHE_TARGET)

$(BUILD):
	mkdir -p $(BUILD)

# One direct cc per program on purpose: whole-program builds cannot serve a
# stale object out of the GNU make 3.81 same-second staleness trap.
$(BFP_TARGET): $(BFP_SOURCES) | $(BUILD)
	$(CC) $(CFLAGS) $(BFP_SOURCES) -o $@ $(LDLIBS)

$(CONVERT_TARGET): $(CONVERT_SOURCES) | $(BUILD)
	$(CC) $(CFLAGS) $(CONVERT_SOURCES) -o $@ $(LDLIBS)

$(CACHE_TARGET): $(CACHE_SOURCES) | $(BUILD)
	$(CC) $(CFLAGS) $(CACHE_SOURCES) -o $@ $(LDLIBS)

check: $(BFP_TARGET) $(CONVERT_TARGET) $(CACHE_TARGET)
	./$(BFP_TARGET)
	./$(CONVERT_TARGET)
	./$(CACHE_TARGET)

# Full rebuild, then run. Use this for every red/green pass.
red: clean $(BFP_TARGET) $(CONVERT_TARGET) $(CACHE_TARGET)
	-./$(BFP_TARGET)
	-./$(CONVERT_TARGET)
	-./$(CACHE_TARGET)

# Regenerate ../reference/ft_bfp_reference_vectors.h. The generator refuses to
# write unless its independent reference agrees with ft_bfp.c on every word.
bfp-reference: | $(BUILD)
	$(CC) $(CFLAGS) $(CONVERT)/reference/generate_bfp_reference.c $(CONVERT)/ft_bfp.c -o $(BUILD)/generate_bfp_reference $(LDLIBS)
	./$(BUILD)/generate_bfp_reference $(BUILD)/ft_bfp_reference_vectors.h
	cp $(BUILD)/ft_bfp_reference_vectors.h $(CONVERT)/reference/ft_bfp_reference_vectors.h

clean:
	rm -rf $(BUILD)
