Three coupled changes that unblock the ecdsa quantum-circuit simulator's run on the C tier from neoblanka. 1. c/Makefile autodetects libgc-dev — if /usr/include/gc.h is present, the build links Boehm and defines USE_BOEHM_GC. Without GC, ul_free is a no-op (lumbda.h:35) and every allocation leaks; small REPL snippets work but workloads with thousands of envs OOM the process. Override with USE_GC=0 to force the malloc-only path for diagnostics. 2. c/main.c calls GC_INIT before init_symbols, then GC_disable. GC_INIT registers the stack base for conservative scan — without it some Linux configs miss roots. GC_disable is a deliberate stopgap: lumbda Values are NaN-boxed pointers that conservative Boehm cannot recognize as pointers, so live targets get reclaimed (env binding symbol payloads, SymbolEntry strings) and lookups fail with "undefined: <sym>". Reproducing this without GC_disable on the GC build: any sim.lsp call chain triggers the corruption after ~100 named-let iterations. Until tracing is precise, growing the heap is safer than wrong results. Long-running workloads run under ulimit -v. 3. c/builtins.c gains rename-file and delete-file matching the Python tier (lumbda.py:3468). sim.lsp's write-portal! pattern (write to .tmp, rename) needs rename-file to land cross-tier identical results. 4. tests/regression-named-let-leak.lsp + .sh pin four shapes that blew up ecdsa: the c/TODO-named-let-bytecode.md repro, the F1 shape from foxhop.net's lumbda-c-tier-leak-SP.md (12-line minimum), a 200-iter scaled variant, and a sim.lsp run-ops! mirror. Wired into root Makefile as regression-named-let-leak; added to test-all. Wrapper caps memory at 256 MB virt and 15s per tier so a leak regression fails the run instead of consuming host RAM. Known limits: - --fast JIT still has the named-let + inner user-fn call hang (separate TODO; tree-walker handles this fine). - GC_disable means the heap grows; workloads must bound their work budget. ecdsa's sim runs comfortably in 5 MB. Verified inside a 2G/2vCPU QEMU guest (foxhop.net ecdsa/vm-runner.sh): - test-c (tree-walker) — 35/35 PASS - bench-c (tree-walker) — score 18 matches Python tier byte-identical - F1 probe (tree-walker) — all four steps PASS
46 lines
1.2 KiB
Makefile
46 lines
1.2 KiB
Makefile
# Makefile for lumbda C interpreter
|
|
# Targets: all, test, bench, clean
|
|
|
|
CC = gcc
|
|
CFLAGS = -O2 -Wall -Wextra -Wno-unused-parameter -std=c11 -D_POSIX_C_SOURCE=200809L -D_GNU_SOURCE
|
|
LDFLAGS = -lm
|
|
|
|
# Boehm GC autodetect — enable when /usr/include/gc.h is present.
|
|
# Without GC, every allocation leaks (ul_free is a no-op in our header);
|
|
# small REPL snippets work but anything iterating past a few thousand
|
|
# allocations OOMs the process. The named-let + per-iteration user-fn
|
|
# call pattern in tests/regression/named-let-gc.lsp pins this down.
|
|
# Override with USE_GC=0 to force the malloc-only path for diagnostics.
|
|
USE_GC ?= $(shell test -f /usr/include/gc.h && echo 1 || echo 0)
|
|
ifeq ($(USE_GC),1)
|
|
CFLAGS += -DUSE_BOEHM_GC
|
|
LDFLAGS += -lgc
|
|
endif
|
|
|
|
SRCS = types.c reader.c printer.c eval.c builtins.c vm.c jit.c portal.c
|
|
OBJS = $(SRCS:.c=.o)
|
|
|
|
.PHONY: all clean test bench
|
|
|
|
all: lumbda
|
|
|
|
lumbda: main.o $(OBJS)
|
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
|
|
|
test: test_runner
|
|
./test_runner
|
|
|
|
test_runner: test.c $(OBJS)
|
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
|
|
|
bench: bench_runner lumbda
|
|
ulimit -s 65536 && ./bench_runner
|
|
|
|
bench_runner: bench.c $(OBJS)
|
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
|
|
|
%.o: %.c lumbda.h
|
|
$(CC) $(CFLAGS) -c -o $@ $<
|
|
|
|
clean:
|
|
rm -f *.o lumbda test_runner bench_runner
|