# Clang 22 compiler torture test — build system.
#
# Pipeline:
#   generator -> GiBs of real C++ -> template instantiation ->
#   constexpr evaluation -> constraint/overload analysis -> large LLVM IR ->
#   -O3 + full LTO -> tiny executable -> return 0.
#
# Full LTO (-flto=full) with -O3 is mandatory for both compilation and
# linking. Do NOT weaken these flags.

# Gentoo: CXX is ?= so Portage can override via tc-getCXX/MAKE variable.
# Manual builds default to clang++ and still validate Clang 22 via require-clang22.
CXX      ?= clang++
STD      := -std=c++20
# Mandatory aggressive configuration, used for compile AND link.
OPT      := -O3 -flto=full
WARN     := -Wall -Wextra
CXXFLAGS := $(STD) $(OPT) $(WARN) -DNDEBUG -fno-plt
# Linker: keep -O3 -flto=full mandatory; use lld if available, else fall back
# to the system linker via LLVMgold.so (works with GNU ld).
LLD_CHECK := $(shell $(CXX) -fuse-ld=lld -Wl,--version >/dev/null 2>&1 && echo yes)
ifeq ($(LLD_CHECK),yes)
  LDFLAGS := $(OPT) -fuse-ld=lld -Wl,--no-keep-memory -Wl,--reduce-memory-overheads
else
  LDFLAGS := $(OPT)
endif
LDLIBS   :=

GEN          := python3 generator.py
# Default target: 8 GiB. Recommended: `make generate TARGET_GIB=17`.
TARGET_GIB   ?= 8
OUT_DIR      := generated
SRC_MAIN     := src/main.cpp
BIN          := torture

# All generated shards + main. Recursive wildcard evaluated at build time.
SHARDS = $(sort $(wildcard $(OUT_DIR)/tu_*.cpp))
OBJS   = $(SHARDS:.cpp=.o) src/main.o

.PHONY: all generate build check size clean distclean require-clang22 help

all: build

help:
	@echo "targets:"
	@echo "  make generate [TARGET_GIB=8]  - generate >=TARGET_GIB GiB of C++ into $(OUT_DIR)/"
	@echo "  make build                    - full -O3 -flto=full LTO build of ./$(BIN)"
	@echo "  make check                    - run ./$(BIN); expect exit 0, no output"
	@echo "  make size                     - report generated source size + binary size"
	@echo "  make clean                    - remove objects + binary (keep generated sources)"
	@echo "  make distclean                - also remove generated sources"

require-clang22:
	@ver="$$($(CXX) --version 2>/dev/null | head -n1)"; \
	echo "compiler: $$ver"; \
	case "$$ver" in \
	  *"clang version 22."*) ;; \
	  *) echo "ERROR: Clang 22 required (got: $$ver)" >&2; exit 1;; \
	esac

generate:
	$(GEN) --target-gib $(TARGET_GIB) --out-dir $(OUT_DIR)

# --- compilation: same -O3 -flto=full for every TU ---------------------------
$(OUT_DIR)/%.o: $(OUT_DIR)/%.cpp
	$(CXX) $(CXXFLAGS) -c $< -o $@

src/main.o: $(SRC_MAIN)
	$(CXX) $(CXXFLAGS) -c $< -o $@

# --- link: same -O3 -flto=full (full LTO mandatory) ---------------------------
$(BIN): require-clang22 $(OBJS)
	$(CXX) $(LDFLAGS) $(OBJS) -o $@ $(LDLIBS)

build: $(BIN)

check: $(BIN)
	@out="$$(./$(BIN))"; code=$$?; \
	if [ $$code -ne 0 ]; then echo "FAIL: exit code $$code (expected 0)" >&2; exit 1; fi; \
	if [ -n "$$out" ]; then echo "FAIL: unexpected output: $$out" >&2; exit 1; fi; \
	echo "PASS: ./$(BIN) exited 0 with no output"

size:
	@echo "generated sources:"; \
	if ls $(OUT_DIR)/tu_*.cpp >/dev/null 2>&1; then \
	  du -sh $(OUT_DIR); du -sb $(OUT_DIR) | awk '{printf "total bytes: %d (%.4f GiB)\n", $$1, $$1/1073741824}'; \
	  ls $(OUT_DIR)/tu_*.cpp | wc -l | awk '{print "shard count: " $$1}'; \
	else echo "  (none yet — run make generate)"; fi; \
	echo "binary:"; \
	if [ -f $(BIN) ]; then ls -lh $(BIN); else echo "  (not built)"; fi

clean:
	rm -f $(OBJS) $(BIN)

distclean: clean
	rm -f $(OUT_DIR)/tu_*.cpp
