Makefile raw

   1  MOXIE    ?= $(CURDIR)/../moxie/moxie
   2  MOXIEJS  ?= $(CURDIR)/../moxie/moxiejs
   3  # An inherited MOXIEROOT is ignored on purpose: `?=` cannot tell an exported
   4  # stale root from an intended one, and a stale root silently compiles a
   5  # different tree's src/ and pkg/ (that is how `make build-app-wasm` failed
   6  # with "'err' shadows declaration in enclosing scope" from an old checkout,
   7  # while the same build with the repo root succeeds). Pass it on the command
   8  # line to build against another tree: make MOXIEROOT=/path/to/moxie ...
   9  ifeq ($(origin MOXIEROOT),environment)
  10  MOXIEROOT := $(CURDIR)/../moxie
  11  endif
  12  MOXIEROOT ?= $(CURDIR)/../moxie
  13  JSRUNTIME ?= $(CURDIR)/../moxie/jsruntime
  14  ISKRA    ?= $(HOME)/.local/bin/moxie-iskra
  15  # relay-proxy builds from source with the tree compiler. The earlier workaround
  16  # of using an installed moxie (its cached bitcode "avoided too much recursion
  17  # during _start()") was a symptom of a compiler bug: taking the address of a
  18  # frame local stored a stack pointer into the receiver's arena. Fixed in
  19  # _mxc_stage4 (markAddrEscaping mirrors the legacy compiler's Alloc.Heap), and
  20  # a fresh build now produces the same 430KB module the installed compiler did.
  21  MOXIE_RELAY_PROXY ?= $(MOXIE)
  22  
  23  # Moxie closures do not capture: a closure receives what it needs through its
  24  # parameters, and the legacy compiler rejects a capturing one. stage4 enforces
  25  # the same rule by default. This app predates that enforcement and registers
  26  # hundreds of handlers that close over the enclosing frame (286 sites in
  27  # web/wasm/app alone), so every build here opts out explicitly. Porting them to
  28  # explicit parameters or to holder types with the callback as an interface is
  29  # tracked with the app, not the compiler; until it lands, the debt is declared
  30  # here rather than silently relying on stage4's old acceptance.
  31  CAPTURES ?= -allow-closure-captures
  32  
  33  # === Relay (native) ===
  34  build-relay:
  35  	MOXIEROOT=$(MOXIEROOT) $(MOXIE) build $(CAPTURES) -o smesh .
  36  
  37  # === Frontend (WASM) ===
  38  build-app-wasm:
  39  	MOXIEROOT=$(MOXIEROOT) GOWORK=off $(MOXIE) build $(CAPTURES) -target wasm -o $(CURDIR)/web/static/app.wasm ./web/wasm/app/
  40  
  41  build-relay-proxy-wasm:
  42  	MOXIEROOT=$(MOXIEROOT) GOWORK=off $(MOXIE_RELAY_PROXY) build $(CAPTURES) -target wasm -o $(CURDIR)/web/static/relay-proxy.wasm ./web/wasm/relay-proxy/
  43  
  44  build-store-wasm:
  45  	MOXIEROOT=$(MOXIEROOT) GOWORK=off $(MOXIE) build $(CAPTURES) -target wasm -o $(CURDIR)/web/static/store.wasm ./web/wasm/store/
  46  
  47  build-verify-wasm:
  48  	MOXIEROOT=$(MOXIEROOT) GOWORK=off $(MOXIE) build $(CAPTURES) -target wasm -o $(CURDIR)/web/static/verify.wasm ./web/wasm/verify/
  49  
  50  build-profile-wasm:
  51  	MOXIEROOT=$(MOXIEROOT) GOWORK=off $(MOXIE) build $(CAPTURES) -target wasm -o $(CURDIR)/web/static/profile.wasm ./web/wasm/profile/
  52  
  53  build-feed-wasm:
  54  	MOXIEROOT=$(MOXIEROOT) GOWORK=off $(MOXIE) build $(CAPTURES) -target wasm -o $(CURDIR)/web/static/feed.wasm ./web/wasm/feed/
  55  
  56  build-mls-wasm:
  57  	MOXIEROOT=$(MOXIEROOT) GOWORK=off $(MOXIE) build $(CAPTURES) -target wasm -o $(CURDIR)/web/static/mls.wasm ./web/wasm/mls/
  58  
  59  
  60  build-notif-wasm:
  61  	MOXIEROOT=$(MOXIEROOT) GOWORK=off $(MOXIE) build $(CAPTURES) -target wasm -o $(CURDIR)/web/static/notif.wasm ./web/wasm/notif/
  62  
  63  build-sw:
  64  	MOXIEROOT=$(MOXIEROOT) GOWORK=off $(MOXIE) build $(CAPTURES) -target wasm -o $(CURDIR)/web/static/\$$sw/sw.wasm ./web/wasm/sw/
  65  
  66  # === Signer WASM (page-embedded worker) ===
  67  # The web app uses signer.wasm directly via signer-wasm-host.mjs.
  68  # No browser extension is required for normal operation.
  69  build-signer:
  70  	MOXIEROOT=$(MOXIEROOT) GOWORK=off $(MOXIE) build $(CAPTURES) -target wasm -o $(CURDIR)/web/static/signer.wasm ./web/wasm/signer/
  71  
  72  # Extension build (optional, not part of default build).
  73  build-ext-firefox: build-signer
  74  	cp $(CURDIR)/web/static/signer.wasm $(CURDIR)/web/ext/bg/signer.wasm
  75  	bash scripts/pack-ext.sh firefox
  76  	cp dist/smesh-signer-firefox.xpi web/static/smesh-signer.xpi
  77  
  78  build-ext: build-ext-firefox
  79  
  80  # === All ===
  81  # Direct messaging (MLS/Marmot) is parked again: the wasm worker panics in
  82  # Moxie's codec while generating its first KeyPackage (an invalid type
  83  # descriptor, kind=0), so its worker is not built or served and the app has no
  84  # /msg route. The mls code, host plumbing and worker all stay in the tree;
  85  # re-enable by restoring the sidebar entry, the router cases, the mlsWorkerTypes
  86  # branch and build-mls-wasm in `build`/`dev` (see docs/relay-test-coverage.md).
  87  build: build-relay build-app-wasm build-relay-proxy-wasm build-store-wasm build-verify-wasm build-profile-wasm build-feed-wasm build-notif-wasm build-signer build-sw
  88  
  89  # === Test ===
  90  build-test-relay:
  91  	MOXIEROOT=$(MOXIEROOT) $(MOXIE) build $(CAPTURES) -o smesh-test .
  92  
  93  # Unit tests: every package carrying a *_test.mx, run by the compiler's own test
  94  # harness. Nothing ran these before - the files sat in the tree, and the ones
  95  # that had stopped compiling or passing were invisible until they were run.
  96  #
  97  # UNIT_SKIP names the packages whose tests are known not to build or pass yet.
  98  # Each one is recorded in docs/relay-test-coverage.md with its reason: declared
  99  # debt, not silence.
 100  #
 101  # pkg/crawler came off the list once stage4 rejected `push` on a non-slice
 102  # (the same error legacy gives) instead of emitting IR for it; its test helper
 103  # pushed onto a *tag.S instead of onto its T slice, which is what the old
 104  # "IR-emit bug" report was.
 105  #
 106  # web/common/marmot came off the list once its closure compiled: the mls
 107  # test-support files shadowed the named `err` return from nested blocks, and
 108  # the test's `wantN int` is a type this compiler no longer defines (stage4
 109  # emits a ptr where the fmt interface slot needs {i64,ptr}, and clang refuses
 110  # the module). Both are fixed in place; the test is int32 and uses explicit
 111  # return after Fatal, and 6 tests pass.
 112  #
 113  # pkg/nostr/ws came off the list once stage4 boxed a concrete operand
 114  # (syscall.Errno sentinels, errors.Const) into the interface representation
 115  # before comparing it against an error value, the way legacy already did
 116  # through go/ssa. The loopback WebSocket tests now connect and pass.
 117  #
 118  # pkg/lol came off the list once stage4 stopped printing a phantom
 119  # `%!(NOVERB)` after every formatted value: its 9 tests pass.
 120  UNIT_SKIP ?=
 121  test-unit:
 122  	@set -e ; for f in $$( { [ -f main_test.mx ] && echo main_test.mx ; find pkg web -name '*_test.mx' ; } | sort ) ; do \
 123  		d=$$(dirname $$f) ; \
 124  		case " $(UNIT_SKIP) " in *" $$d "*) echo "=== unit: $$d (skipped: see docs/relay-test-coverage.md)" ; continue ;; esac ; \
 125  		echo "=== unit: $$d" ; \
 126  		MOXIEROOT=$(MOXIEROOT) $(MOXIE) test $(CAPTURES) ./$$d || exit 1 ; \
 127  	done
 128  
 129  test-signer: build-signer
 130  	node web/_test/signertest/run.mjs web/ext/bg/signer.wasm
 131  
 132  # Unit coverage: the same package loop with the harness's own report. `moxie
 133  # test -cover` writes the site table, starts the instrumented test binary and
 134  # prints the per-file table itself, so nothing external joins the halves.
 135  unit-cover:
 136  	@set -e ; for f in $$( { [ -f main_test.mx ] && echo main_test.mx ; find pkg web -name '*_test.mx' ; } | sort ) ; do \
 137  		d=$$(dirname $$f) ; \
 138  		case " $(UNIT_SKIP) " in *" $$d "*) echo "=== unit-cover: $$d (skipped: see docs/relay-test-coverage.md)" ; continue ;; esac ; \
 139  		echo "=== unit-cover: $$d" ; \
 140  		MOXIEROOT=$(MOXIEROOT) $(MOXIE) test $(CAPTURES) -cover ./$$d || exit 1 ; \
 141  	done
 142  
 143  test: test-unit build-test-relay test-signer
 144  	python3 -m pytest test/ -v --tb=short -x
 145  
 146  # === Coverage ===
 147  #
 148  # `make cover` measures the integration suite's line coverage of this module:
 149  # the relay is built with -cover, which makes the compiler emit a coverage hit
 150  # per statement and write <output>.cover_sites.json (id -> pkg.Func@file:line);
 151  # MOXIE_COVER_OUT makes the instrumented runtime append its counters to one file
 152  # when a domain exits, which the test fixture's SIGTERM triggers; mxcover joins
 153  # the table to the counters and prints the per-file table plus every statement
 154  # that never ran.
 155  #
 156  # The file is appended to, not rewritten, because each test starts a fresh relay
 157  # and the relay is a spawn tree - the store, the ingest workers, the proxy, the
 158  # blossom and broadcast workers each run in a forked domain with a private copy
 159  # of the counter table - so every process and domain contributes its own dump.
 160  # The target deletes the file first, so one run's report is one run's coverage.
 161  #
 162  # The report is the work list. A coverage run rebuilds the whole closure (a
 163  # cached package would have no hits to count) and the instrumented relay is
 164  # slower, so this is not part of `make test`.
 165  #
 166  # test_relay_proxy_high_event_volume runs with a widened post-EOSE window. The
 167  # old poll treated the gap after EOSE as "quiet" and finished 2s later, so a
 168  # slow relay whose first event lands after EOSE read 0 events - which is what
 169  # every `smesh-test` run did, and what the stock relay did in about 1 isolated
 170  # run in 4. The test now waits for the first event up to PROXY_VOLUME_WINDOW_MS,
 171  # so the coverage run widens it (the worker lingers 25s for those stragglers).
 172  COVER_BIN    := $(CURDIR)/smesh-test
 173  COVER_SITES  := $(COVER_BIN).cover_sites.json
 174  COVER_DIR    := $(CURDIR)/tmp
 175  COVER_COUNTS := $(COVER_DIR)/cover.counts
 176  COVER_TOOL   := $(COVER_DIR)/mxcover
 177  # Site names are "module/path/file.mx:line" for both compilers, so the report
 178  # selects this module out of the link set by the module path from moxie.mod.
 179  COVER_PREFIX := $(shell sed -n 's/^module[[:space:]]*//p' $(CURDIR)/moxie.mod)
 180  cover:
 181  	@mkdir -p $(COVER_DIR)
 182  	MOXIEROOT=$(MOXIEROOT) GOWORK=off $(MOXIE) build -cover $(CAPTURES) -o $(COVER_BIN) .
 183  	rm -f $(COVER_COUNTS)
 184  	@rc=0 ; SMESH_RELAY_BIN=$(COVER_BIN) MOXIE_COVER_OUT=$(COVER_COUNTS) \
 185  	 PROXY_VOLUME_WINDOW_MS=180000 \
 186  	 python3 -m pytest test/ -q --tb=short || rc=$$? ; \
 187  	 MOXIEROOT=$(MOXIEROOT) $(MOXIE) build -o $(COVER_TOOL) $(MOXIEROOT)/cmd/mxcover || rc=$$? ; \
 188  	 $(COVER_TOOL) $(COVER_SITES) $(COVER_COUNTS) $(COVER_PREFIX) || rc=$$? ; \
 189  	 exit $$rc
 190  
 191  test-smoke: build-test-relay
 192  	python3 -m pytest test/test_smoke.py -v --tb=short
 193  
 194  # Allocation instrumentation: the app wasm is rebuilt with -tags alloc_trace
 195  # and -print-allocs, which makes src/runtime publish the __moxie_* counters the
 196  # worker host reads in its __mem_query reply. The pattern is anchored to the
 197  # entry package: the compiler names a function by its package path, and the app
 198  # is the root package of its own module, so it is "main.<func>" - the same name
 199  # the legacy compiler reports.
 200  #
 201  # The instrumented module is scratch: the stock app.wasm is put back whether
 202  # the build or the tests fail, so this never leaves an instrumented artifact or
 203  # a stray side file in the tree. An instrumented build recompiles everything
 204  # serially (site ids are numbered in emit order), so it is slower than
 205  # build-app-wasm.
 206  APP_WASM := $(CURDIR)/web/static/app.wasm
 207  test-memory: build-test-relay
 208  	@if [ -f "$(APP_WASM)" ]; then cp "$(APP_WASM)" "$(APP_WASM).stock"; fi ; \
 209  	 MOXIEROOT=$(MOXIEROOT) GOWORK=off $(MOXIE) build $(CAPTURES) -target wasm -tags alloc_trace \
 210  		-print-allocs '^main\.' -o $(APP_WASM) ./web/wasm/app/ ; \
 211  	 rc=$$? ; \
 212  	 rm -f "$(APP_WASM).alloc_sites.json" ; \
 213  	 if [ $$rc -eq 0 ]; then \
 214  		python3 -m pytest test/test_memory_profile.py -v --tb=short -m memory ; rc=$$? ; \
 215  	 fi ; \
 216  	 if [ -f "$(APP_WASM).stock" ]; then mv "$(APP_WASM).stock" "$(APP_WASM)"; fi ; \
 217  	 exit $$rc
 218  
 219  # === Dev (frontend only, relay already running) ===
 220  dev: build-app-wasm build-relay-proxy-wasm build-store-wasm build-verify-wasm build-profile-wasm build-feed-wasm build-notif-wasm build-sw
 221  
 222  .PHONY: build-relay build-app-wasm build-relay-proxy-wasm build-store-wasm build-verify-wasm build-profile-wasm build-feed-wasm build-mls-wasm build-notif-wasm build-sw build-signer build-ext-firefox build-ext-chrome build-ext build dev build-test-relay test-signer test-unit test cover test-smoke test-memory unit-cover
 223