Bump VERSION to 8.3.645.
magic.wasm can now be built as two variants packaged in the same npm
release: notcl/ (legacy, magic's own parser) and tcl/ (intubun/tcl 9.x
statically linked, commands evaluated by Tcl_EvalEx). The TCL fork is
pinned via npm/tcl.ref and cloned/built by magic itself — the tcl/
checkout is treated as read-only and built out-of-source into
magic/build-tcl-wasm/.
Configure layer:
- New usingTk variable decoupled from usingTcl in scripts/configure.in
+ scripts/configure, so --with-tcl --without-tk is finally a valid
combination. Native Linux Tcl+Tk builds keep their previous behaviour
(both flags default to enabled).
- When usingTk is empty, configure passes -DMAGIC_NO_TK so the small
number of remaining Tk callsites in tcltk/tclmagic.{h,c} compile out,
and TKCOMMON_SRCS / USE_TK_STUBS are omitted from the link.
WASM build orchestration:
- toolchains/emscripten/build-tcl-wasm.sh builds libtcl9.x.a + libtclstub.a
+ tclConfig.sh out-of-source from a pristine intubun/tcl checkout.
- npm/build.sh grew a --variant=<tcl|notcl|both> flag and writes its
outputs into npm/tcl/ and npm/notcl/. It also clones intubun/tcl with
autocrlf=false at the SHA pinned by npm/tcl.ref.
- magic/Makefile (WASM block only): magicWasm.o is now compiled with
DFLAGS_NOSTUB so Tcl_CreateInterp resolves to libtcl9.x directly
before tclStubsPtr is set. magic.js link pulls in LIB_SPECS_NOSTUB
and -ltclstub. After rules.mak include, magic: is a phony alias for
magic.js so the generic ${MODULE} recipe doesn't fight it.
- toolchains/emscripten/defs.mak: add -sUSE_ZLIB=1 (libtcl9 references
zlib), replace -sSTACK_SIZE=N with -Wl,-z,stack-size=N (emcc >=5
rejects the setting form).
- magic/magicWasm.c bootstraps the embedded interp under MAGIC_WRAPPER
(Tcl_CreateInterp -> Tcl_Init -> Tclmagic_Init) and routes
run_command through Tcl_EvalEx.
- magic/magicTop.c: gate MagicVersion/Revision/CompileTime on
!MAGIC_WRAPPER so they don't collide with the copies in
tcltk/tclmagic.c when both objects land in the same wasm binary.
npm package:
- Subpath exports: ".", "./tcl", "./notcl". Default import keeps the
pre-existing non-TCL behaviour for backward compatibility.
- examples/smoke-tcl.mjs exercises the TCL variant.
CI:
- main-wasm.yml clones intubun/tcl at the pinned ref, builds both
variants via npm/build.sh --variant=both, runs the existing notcl
test suite and the new TCL smoke test, and publishes only on a
v<x.y.z>... git tag. Tag name (minus the leading v) becomes the
npm version.
|
||
|---|---|---|
| .. | ||
| README.md | ||
| build-tcl-wasm.sh | ||
| defs.mak | ||
| post-build.sh | ||
README.md
Magic VLSI — Headless WASM Build
This toolchain builds Magic as a headless WebAssembly module using Emscripten.
X11, Tk, OpenGL, and readline are all disabled. The resulting magic.js /
magic.wasm pair can be loaded in Node.js, a browser, or a Web Worker.
Quick start (npm package)
The easiest way to build and use the WASM module is through the npm package:
# Build magic.js + magic.wasm and copy them into npm/
bash npm/build.sh
# Run the test suite (extract, GDS, DRC, CIF)
npm --prefix npm test
See npm/examples/ for usage examples.
Manual build
Prerequisites: an activated emsdk
checkout (emcc, emar, emranlib on PATH), plus standard make and gcc.
# 1. Configure for Emscripten
CFLAGS="--std=c17 -D_DEFAULT_SOURCE=1 -DEMSCRIPTEN=1 -g" \
emconfigure ./configure \
--without-cairo --without-opengl --without-x --without-tk --without-tcl \
--disable-readline --disable-compression \
--host=asmjs-unknown-emscripten \
--target=asmjs-unknown-emscripten
# 2. Append the Emscripten-specific make settings
cat toolchains/emscripten/defs.mak >> defs.mak
# 3. Build
emmake make depend
emmake make -j$(nproc) modules libs
emmake make techs
emmake make mains
The outputs are magic/magic.js and magic/magic.wasm.
Embedded files
The following runtime files are baked directly into the WASM binary via
Emscripten's --embed-file mechanism and are available at startup without
any host filesystem access:
| Host path | VFS path |
|---|---|
scmos/ |
/magic/sys/current/ |
windows/windows7.glyphs |
/magic/sys/windows7.glyphs |
windows/windows7.glyphs |
/magic/sys/bw.glyphs |
To embed a custom technology file, add an --embed-file entry to
TOP_EXTRA_LIBS in defs.mak.
Exported C API
The WASM module exports four functions:
| Function | Description |
|---|---|
magic_wasm_init() |
Initialize Magic (idempotent — safe to call multiple times). Returns 0 on success. |
magic_wasm_run_command(const char *cmd) |
Dispatch one Magic command. Calls magic_wasm_init() automatically if needed. Returns 0 on success. |
magic_wasm_source_file(const char *path) |
Read and execute a command file from the virtual filesystem. |
magic_wasm_update() |
Drive a display-update cycle. No-op in headless builds (null display suspends all redraws). |
JavaScript usage
import createMagic from 'magic-vlsi-wasm';
const { runCommand, FS } = await createMagic();
// Write a layout file into the virtual filesystem
FS.writeFile('/work/inv.mag', layoutBytes);
// Run Magic commands
runCommand('tech load sky130A');
runCommand('load /work/inv');
runCommand('gds write /work/inv');
// Read the result back out
const gdsBytes = FS.readFile('/work/inv.gds');
Notes
CAD_ROOTis automatically set to/so that embedded system files are resolved under/magic/sys/.- The null display driver (
-d null) setsGrDisplayStatus = DISPLAY_SUSPEND, which causesWindUpdateto return immediately without invoking any display callbacks. This is what makes the WASM build safe to run without a screen. - All POSIX signal/timer APIs (
setitimer,SIGALRM,fcntl) are compiled out under__EMSCRIPTEN__; the display progress timer becomes a no-op.