# Build lib/sprinter.lib + lib/sprinter_safe.lib — the Sprinter libc. # # libc/ — ядро библиотеки (БЕЗ графики; графика вынесена в libbgi/). # Каждый .c под libc// — отдельный .rel в архиве (1 публичная # функция = 1 модуль); линкер тянет только нужные .rel → DCE на уровне # файлов. Плюс runtime-хелперы, которые автотянутся кодогеном SDCC # (heap для malloc). crt0-семейство НЕ в архиве — оно всегда явно # линкуется, не DCE-eligible. См. docs/libc-split-asm-cases.md. # # Две версии (симметрично libbgi: bgi256.lib / bgi256_safe.lib): # sprinter.lib = fast: -DLIBC_NOCHECK — параметр-валидации # (NULL fp/buf, EBADF на неверное направление # потока) ВЫРЕЗАНЫ; дефолт sprinter-cc. # sprinter_safe.lib = safe: валидации включены; линкуется по --safe. # КРИТИЧНЫЕ гарды (например _fd_guard — 9-й OPEN вешает DSS) живут в # ОБЕИХ версиях и под LIBC_NOCHECK не попадают. # # make build обе библиотеки # make fast только lib/sprinter.lib # make safe только lib/sprinter_safe.lib # make clean remove build/ + обе библиотеки PROJ_ROOT := $(abspath $(CURDIR)/..) SDCC_BIN := $(PROJ_ROOT)/third_party/sdcc/bin SDCC := $(SDCC_BIN)/sdcc SDAR := $(SDCC_BIN)/sdar SDASZ80 := $(SDCC_BIN)/sdasz80 INC := -I$(CURDIR)/include CC_FLAGS := -mz80 --no-std-crt0 --std-c99 --opt-code-size $(INC) BUILD := $(CURDIR)/build # All libc C modules — every .c under libc// becomes its own .rel. # `libc/*/*.c` — ровно ОДИН уровень вложенности; графика (gfx/bgi) сюда # не попадает (вынесена в libbgi/). Один PUBLIC-символ на файл. LIBC_C := $(wildcard $(CURDIR)/*/*.c) # Runtime modules to bundle (pulled by symbol references from libc-using # code). bank.s НЕ bundled — его трамплин зависит от banking-окна (W1 # для BIG, W3 для HUGE), что решается per-build в sprinter-cc; он # ассемблирует bank.s с нужным BANK_W1 флагом на каждый banked-build. RUNTIME_S := $(PROJ_ROOT)/runtime/heap.s FAST_RELS := $(patsubst $(CURDIR)/%.c,$(BUILD)/fast/%.rel,$(LIBC_C)) \ $(patsubst $(PROJ_ROOT)/runtime/%.s,$(BUILD)/fast/%.rel,$(RUNTIME_S)) SAFE_RELS := $(patsubst $(CURDIR)/%.c,$(BUILD)/safe/%.rel,$(LIBC_C)) \ $(patsubst $(PROJ_ROOT)/runtime/%.s,$(BUILD)/safe/%.rel,$(RUNTIME_S)) KNOWN_RELS := $(FAST_RELS) $(SAFE_RELS) # Штамп списка модулей: обновляется при любом изменении состава # (добавление/удаление/переименование исходника) — иначе удаление # исходника не триггерит перелинковку и stale .rel остаётся в архиве. # Сразу сносим и архивы: на exFAT (SAM8) гранулярность mtime грубая, # и «список изменился» через сравнение времён можно проглядеть. MODLIST := $(BUILD)/.modules ifneq ($(shell cat $(MODLIST) 2>/dev/null),$(KNOWN_RELS)) _ := $(shell mkdir -p $(BUILD); echo "$(KNOWN_RELS)" > $(MODLIST); rm -f $(LIB_FAST) $(LIB_SAFE)) endif LIB_DIR := $(PROJ_ROOT)/lib LIB_FAST := $(LIB_DIR)/sprinter.lib LIB_SAFE := $(LIB_DIR)/sprinter_safe.lib all: fast safe fast: $(LIB_FAST) safe: $(LIB_SAFE) # --- Fast: -DLIBC_NOCHECK (параметр-валидации выключены) ------------ $(BUILD)/fast/%.rel: $(CURDIR)/%.c @mkdir -p $(dir $@) $(SDCC) $(CC_FLAGS) -DLIBC_NOCHECK --max-allocs-per-node 100000 -c -o $@ $< $(BUILD)/fast/%.rel: $(PROJ_ROOT)/runtime/%.s @mkdir -p $(dir $@) $(SDASZ80) -o $@ $< # --- Safe: валидации включены ---------------------------------------- $(BUILD)/safe/%.rel: $(CURDIR)/%.c @mkdir -p $(dir $@) $(SDCC) $(CC_FLAGS) -c -o $@ $< $(BUILD)/safe/%.rel: $(PROJ_ROOT)/runtime/%.s @mkdir -p $(dir $@) $(SDASZ80) -o $@ $< # Archive — sdar rcs = replace/create/symtab. Перед упаковкой удаляем # stale .rel: wildcard не знает об удалённых/переименованных исходниках, # и осиротевший .rel из build/ иначе жил бы вечно. define PACK_LIB @find $(BUILD)/$(1) -name '*.rel' -print | sort > $(BUILD)/.have_$(1) @printf '%s\n' $(2) | sort > $(BUILD)/.want_$(1) @comm -23 $(BUILD)/.have_$(1) $(BUILD)/.want_$(1) | while read f; do \ echo " stale: $$f (исходник удалён) — rm"; \ rm -f "$$f" "$${f%.rel}.asm" "$${f%.rel}.lst" "$${f%.rel}.sym"; \ done rm -f $@ $(SDAR) -rcs $@ $(2) @echo " Built $@ with $(words $(2)) modules." endef $(LIB_FAST): $(FAST_RELS) $(MODLIST) $(call PACK_LIB,fast,$(FAST_RELS)) $(LIB_SAFE): $(SAFE_RELS) $(MODLIST) $(call PACK_LIB,safe,$(SAFE_RELS)) clean: rm -rf $(BUILD) $(LIB_FAST) $(LIB_SAFE) .PHONY: all fast safe clean