Repository navigation
Expand file tree
/
Copy pathMakefile.substrate
More file actions
182 lines (154 loc) · 8.04 KB
/
Copy pathMakefile.substrate
File metadata and controls
182 lines (154 loc) · 8.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# Stage 1 canary build (v1.3 §2.1): link-checks the substrate boundary.
# libforkrun.so must carry ZERO bash linkage — enforced by
# -Wl,--no-undefined plus an explicit allowed-dependency set.
# The canary compiles the engine TU against stub bash symbols and fails
# the build if any new bash-internal reference is introduced.
#
# Usage:
# make -f Makefile.substrate canary # link check only
# make -f Makefile.substrate check # canary + Stage-0 python tests
# make -f Makefile.substrate canary CC=aarch64-linux-gnu-gcc OUT=libforkrun.aarch64.so
# make -f Makefile.substrate python-substrate # libforkrun_python.so for ctypes
#
# FALSE-GREEN GUARD: make tracks timestamps, not command lines, so switching CC
# between invocations used to leave the previous arch's objects AND output in
# place while this target (whose recipe is only an echo) still printed
# "canary OK" — reporting success for a stale artifact of the wrong arch. Two
# defenses: the CCSTAMP prerequisite forces a full rebuild whenever the
# compiler identity changes, and the arch check below refuses to report OK
# when the artifact's ELF machine doesn't match the requested compiler.
CC ?= gcc
CFLAGS ?= -O1 -fPIC -Wall -Wextra
INCLUDES = -I/usr/include/bash -I/usr/include/bash/include -I/usr/include/bash/builtins
# W-PY23 reproducible builds: same source + same compiler must yield
# byte-identical outputs. Three inputs defeat that by default:
# - __FILE__ embeds the compile-time path (varies with the checkout
# directory) -> -ffile-prefix-map pins it to ".".
# - __DATE__/__TIME__ in forkrun_ring.c (version/debug output, engine
# frozen — cannot remove) embed the wall clock -> predefined-macro
# override pins them (standard reproducible-builds practice; no
# source change, the strings are informational only).
# - the GNU build-id hashes link inputs incl. the above -> none.
# These append (never replace) so a CC/CFLAGS override keeps working;
# setup.py's fallback gcc line mirrors them (kept in sync by
# inspection, same rule as the INCLUDES above).
CFLAGS += -ffile-prefix-map=$(CURDIR)=.
CFLAGS += -Wno-builtin-macro-redefined '-D__DATE__="Sep 1 2026"' '-D__TIME__="00:00:00"'
LDFLAGS_REPRO = -Wl,--build-id=none
OUT ?= libforkrun.so
CCSTAMP = .canary-cc
# Allowed shared deps for the standalone substrate (explicit set).
ALLOWED_DEPS = -ldl -lrt
CANARY_STUBS = substratestubs.o
# W-PY1 Python frontend substrate (Stage 4 Phase 1): python/forkrun/_shim.c
# textually includes forkrun_ring.c (same TU, so the engine's statics and
# TLS are visible) and ADDS non-static fr_py_* entry points for ctypes.
# forkrun_ring.c itself is unmodified. Same flags/hygiene as the canary:
# no -D_GNU_SOURCE on the CLI (the TU sets its own FTMs first).
PY_OUT ?= python/forkrun/libforkrun_python.so
PY_SHIM_OBJ = forkrun_python_shim.o
# W-CR1: the cleanroom launcher. Standalone C program that owns the
# WHOLE pipeline (init, spill, memfds, fork fallow/workers/scanner,
# drain) so the hot path crosses exec() instead of inheriting a large
# Python address space. It dlopens $(PY_OUT) at runtime, so it does NOT
# link the engine -- building it needs no engine objects, only -ldl.
# Shipped next to the .so; forkrun.run locates it relative to that.
CR_OUT ?= python/forkrun/_forkrun_cleanroom
CR_SRC = forkrun_cleanroom.c
all: canary
.PHONY: cleanroom-launcher
cleanroom-launcher: $(CR_OUT)
.PHONY: all canary canary-versions check clean python-substrate FORCE bench bench-small bench-large bench-csv reproducibility-check clean-python
# Rewritten only when the compiler identity/options actually change, so its
# mtime bumps exactly when dependent objects must rebuild.
$(CCSTAMP): FORCE
@printf '%s\n' '$(CC) :: $(CFLAGS)' | cmp -s - $@ || \
printf '%s\n' '$(CC) :: $(CFLAGS)' > $@
FORCE:
substratestubs.o: substratestubs.c forkrun_substrate.h $(CCSTAMP)
$(CC) $(CFLAGS) -c substratestubs.c -o $@
forkrun_ring_canary.o: forkrun_ring.c forkrun_substrate.h $(CCSTAMP)
# NOTE: no -D_GNU_SOURCE here — the TU must set its own FTMs (before any
# libc include). A CLI define would mask exactly the include-order bug
# class the canary exists to catch.
$(CC) $(CFLAGS) -DSHELL -DHAVE_CONFIG_H $(INCLUDES) -c forkrun_ring.c -o $@
$(OUT): forkrun_ring_canary.o $(CANARY_STUBS)
$(CC) -shared -o $@ forkrun_ring_canary.o $(CANARY_STUBS) \
-Wl,--no-undefined $(ALLOWED_DEPS) $(LDFLAGS_REPRO)
forkrun_python_shim.o: python/forkrun/_shim.c forkrun_ring.c forkrun_substrate.h ring_loadables/forkrun_plugin.h $(CCSTAMP)
# NOTE: same FTM hygiene as the canary — no -D_GNU_SOURCE on the CLI.
# _shim.c's first directive includes forkrun_ring.c, so the engine's
# FTM block still precedes the first libc include in this TU.
$(CC) $(CFLAGS) -DSHELL -DHAVE_CONFIG_H $(INCLUDES) -c python/forkrun/_shim.c -o $@
$(PY_OUT): $(PY_SHIM_OBJ) $(CANARY_STUBS)
$(CC) -shared -o $@ $(PY_SHIM_OBJ) $(CANARY_STUBS) \
-Wl,--no-undefined $(ALLOWED_DEPS) $(LDFLAGS_REPRO)
python-substrate: $(PY_OUT) $(CR_OUT)
@file $(PY_OUT) | sed 's/^/python substrate artifact: /'
@echo "python-substrate OK: $(PY_OUT)"
# W-CR1: launcher build. -O2 -D_GNU_SOURCE for memfd_create/
# copy_file_range; -ldl for dlopen. No engine linkage on purpose --
# it resolves every fr_py_* symbol from the .so at runtime.
$(CR_OUT): $(CR_SRC) $(PY_OUT)
$(CC) -O2 -D_GNU_SOURCE -o $@ $(CR_SRC) -ldl -lrt
@echo "cleanroom launcher OK: $@"
# W-PY23: two consecutive builds must be byte-identical (same
# source + same compiler). Touches the shim so both builds
# recompile+relink fully (make would otherwise no-op the second).
reproducibility-check: python-substrate
@echo "=== Reproducibility check ($(PY_OUT)) ==="
@sha256sum $(PY_OUT) > /tmp/fr_build1.sha
@touch python/forkrun/_shim.c
@$(MAKE) -f Makefile.substrate python-substrate > /dev/null
@sha256sum $(PY_OUT) > /tmp/fr_build2.sha
@if diff /tmp/fr_build1.sha /tmp/fr_build2.sha > /dev/null 2>&1; then \
echo "REPRODUCIBLE: consecutive $(PY_OUT) builds are byte-identical"; \
else \
echo "NOT REPRODUCIBLE: builds differ:"; \
cat /tmp/fr_build1.sha /tmp/fr_build2.sha; \
exit 1; \
fi
@rm -f /tmp/fr_build1.sha /tmp/fr_build2.sha
clean-python:
rm -f $(PY_SHIM_OBJ) $(PY_OUT) $(CCSTAMP)
bench: python-substrate
python3 python/benchmarks/run_all.py --scale medium --trials 3
bench-small: python-substrate
python3 python/benchmarks/run_all.py --scale small --trials 2
bench-large: python-substrate
python3 python/benchmarks/run_all.py --scale large --trials 5
bench-csv: python-substrate
python3 python/benchmarks/run_all.py --scale medium --trials 5 \
--csv python/benchmarks/results/pybench.csv
canary: $(OUT)
@file $(OUT) | sed 's/^/canary artifact: /'
# ARCH ASSERTION uses the compiler's own TARGET TRIPLE, not its NAME:
# pattern-matching on $(CC) false-REDs on a native aarch64 host running
# plain `gcc` (the old *gcc* arm grepped for x86-64 and failed a correct
# artifact). `$(CC) -dumpmachine` is the correct identity source.
# Arches with no mapping below (ppc64le / s390x / riscv64) get the link
# check only: on those the canary's job is -Wl,--no-undefined, not an
# ELF-machine assertion.
@trip="$$($(CC) -dumpmachine 2>/dev/null)"; \
case "$$trip" in \
*aarch64*) want=aarch64 ;; \
*x86_64*) want=x86-64 ;; \
*) want="" ;; \
esac; \
echo "canary compiler: $(CC) -> $${trip:-unknown} (expecting ELF machine: $${want:-<link-check only>})"; \
if [ -n "$$want" ] && ! file $(OUT) | grep -q "$$want"; then \
echo "canary FAIL: $(CC) targets '$$trip' but $(OUT) is not '$$want' (stale/wrong-arch artifact)" >&2; \
exit 1; \
fi
@echo "canary OK: $(OUT) links with no undefined symbols"
# W-BASHCOMPAT-BC5: version-floor gate over the canary closure. Every
# bash-internal stub carries its first-export version (or an explicit
# unexported marker); the checker fails on missing annotations,
# post-floor versions, and stub-matched undefined symbols above the
# floor in the shipped prebuilts. Run wherever the canary runs.
canary-versions:
python3 tools/check_canary_versions.py
check: canary
python3 -m unittest discover -s python/tests
clean:
rm -f *.o *.so $(CCSTAMP) $(PY_SHIM_OBJ) $(PY_OUT)