make package icon
icedcoffee/make
Public
wasmer run icedcoffee/make

make — GNU Make for WASIX

GNU make 4.4.1 (Debian trixie's version), built for WASIX. Recipes run in a real shell, -j really runs jobs in parallel, and recursive make works.

wasmer run icedcoffee/make -- -j4
wasmer run icedcoffee/make -- -C src all
wasmer run icedcoffee/make -- -f build.mk -B

What is in the package

make and gmake. Everything GNU make 4.4.1 does: explicit, implicit, pattern and static pattern rules, suffix rules, order-only prerequisites, double-colon rules, .PHONY/.SECONDARY/.INTERMEDIATE/.DELETE_ON_ERROR, $(shell …), $(wildcard …), $(call …), $(foreach …), $(eval …), $(file …), define/endef, conditionals, include/-include, vpath, target-specific and pattern-specific variables, private/exported/unexported variables, automatic variables ($@ $< $^ $+ $* $? $|), MAKEFLAGS and the jobserver, -j, -k, -i, -n, -s, -B, -C, -W, -o, -q, -p, -r/-R, --trace, .ONESHELL, and exit status 2 on a failed recipe.

--sync (file locking between make instances) is accepted but does nothing — WASIX has no POSIX record locking. -l (load average) is accepted and ignored.

Verified

$ make -j4                 # four one-second targets
parallel=1s                (serial run of the same Makefile: 4s)
$ make                     # all: -> $(MAKE) -C sub
make[1]: Entering directory '/tmp/rec/sub'
sub-make ok
make[1]: Leaving directory '/tmp/rec/sub'
$ make -f M2               # X := $(shell echo from-shell)
X=from-shell
$ make -f M3 a.o           # pattern rule
cc a.c - a.o
$ make -f bad x            # recipe fails
make: *** [bad:2: x] Error 1     (exit 2)

$(wildcard), include, -C, -B, -q and stdin-driven makefiles (make -f -) behave as upstream.

Three patches needed

  • src/dir.c. The glob interface wants a struct dirent it can grow, so make computes sizeof (*d) - sizeof (d->d_name) + len. wasi-libc declares d_name as a flexible array member (char d_name[]), so sizeof (d->d_name) cannot compile. Replaced with offsetof (struct dirent, d_name) + len, which is the same number for both layouts.
  • src/main.c, two-argument main. clang only maps the standard main(int, char **) to __main_argc_argv, which is the symbol the wasi crt calls. make uses main(int, char **, char **envp), which stays a symbol named main — and clang gives it hidden visibility, so the crt cannot resolve it and the link fails with __main_void.o: undefined symbol: main. The _AMIGA two-argument form is now used on __wasi__ too, with envp = environ where the environment block is read.
  • src/main.c, getlogin(). wasi-libc has none, but both src/read.c (~user expansion) and gnulib's glob.c reference it. A stub returning NULL is appended under #ifdef __wasi__.
  • src/posixos.c. osync_acquire()/osync_release() use fcntl (F_SETLKW), which wasi-libc does not declare. Both become no-ops under #ifdef __wasi__, which only costs the --sync option.
  • asyncify. Recipes and $(shell …) fork and exec, and make longjmps out of its own error paths; on WASIX both are driven through the module's asyncify exports. Without it every run exits 45. 300 KiB raw, 1.0 MB asyncified.

Building

./configure --host=wasm32-wasi --build=x86_64-linux-gnu --disable-nls
make
wasm-opt --asyncify --enable-threads --enable-bulk-memory make -o make.wasm

with -matomics -mbulk-memory -mmutable-globals -pthread -mthread-model posix -ftls-model=local-exec, -D_WASI_EMULATED_{MMAN,SIGNAL,PROCESS_CLOCKS,GETPID}, -lwasi-emulated-{mman,process-clocks,getpid}, -Wl,--shared-memory -Wl,--max-memory=4294967296 -Wl,--import-memory, and the __heap_base/__stack_pointer/__wasm_init_tls/__tls_* exports.

License: GPL-3.0-or-later, as upstream.

GNU make 4.4.1 for WASIX - parallel builds, jobserver, $(shell), recursive make


Github