The footprint and symbol editors are no longer separate WASM bundles: the frontend loads the parent pcbnew/eeschema bundle and passes --frame=fpedit / --frame=symedit (TOOL_BUNDLE + TOOL_FRAME -> Module.arguments in boot). Drops the two duplicate build+deploy targets and their wrapper scripts + vestigial embind; adds low-level harnesses (footprint_editor.html, symbol_editor.html) and a runtime-frame spec. Bumps the kicad submodule to the runtime --frame launcher. The frame-runtime spec is listed in PCBNEW_FAMILY_SPECS so CI routes it to the chromium-ci (V8) project — its footprint case boots the pcbnew module, which OOMs SpiderMonkey on x86 CI. Includes the editor-unification dossier (research docs 01-04 + the as-built implementation record 05). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
7.1 KiB
01 — Current build structure (the as-built baseline)
What we compile today and why two pairs of apps are duplicates. Evidence from
docker/build.sh,scripts/kicad/build-kicad-target.sh, the per-appCMakeLists.txt, and the on-disk artifact sizes. Read02-kiface-architecture.mdfor why this duplication is avoidable.
The 7 apps
docker/build.sh is the orchestrator. Valid apps (docker/build.sh:69):
pcbnew | eeschema | calculator | pl_editor | symbol_editor | footprint_editor | gerbview | sym_convert | all
all (docker/build.sh:95) expands to the 7 GUI tools (everything above except sym_convert,
which is a headless node CLI .lib → .kicad_sym converter, not an editor). Each app dispatches
to scripts/kicad/build-<app>.sh, a thin wrapper around
scripts/kicad/build-kicad-target.sh <app>, whose case (build-kicad-target.sh:46-79) maps
each app to a CMake target, a source subdir, and — crucially — a FRAME_T:
| app | CMake target | subdir | TOP_FRAME (the baked-in frame) |
|---|---|---|---|
pcbnew |
pcbnew |
pcbnew |
FRAME_PCB_EDITOR (board editor) |
footprint_editor |
footprint_editor |
pcbnew |
FRAME_FOOTPRINT_EDITOR |
eeschema |
eeschema |
eeschema |
FRAME_SCH (schematic editor) |
symbol_editor |
symbol_editor |
eeschema |
FRAME_SCH_SYMBOL_EDITOR |
gerbview |
gerbview |
gerbview |
FRAME_GERBER |
pl_editor |
pl_editor |
pagelayout_editor |
FRAME_PL_EDITOR |
calculator |
pcb_calculator |
pcb_calculator |
(standalone, OUTPUT_NAME=calculator) |
Note that footprint_editor's subdir is pcbnew and symbol_editor's is eeschema — because
they are part of those modules, not separate codebases.
The two duplicate pairs
PCB side: pcbnew and footprint_editor are one kiface, two launchers
The pcbnew module compiles once into an object library pcbnew_kiface_objects
(kicad/pcbnew/CMakeLists.txt:831) that already contains both frame implementations:
pcb_edit_frame.cpp(the board editor,PCB_EDIT_FRAME)footprint_edit_frame.cpp(the footprint editor,FOOTPRINT_EDIT_FRAME)- plus their shared bases
pcb_base_edit_frame.cpp/pcb_base_frame.cpp, and the footprint viewer / chooser / wizard frames.
The footprint_editor executable is added in a WASM-only block
(kicad/pcbnew/CMakeLists.txt:982-1018) whose own comment says it plainly:
"The footprint editor (FRAME_FOOTPRINT_EDITOR) is served by the pcbnew kiface and its sources are already compiled into the pcbnew kiface objects, so we only need a second single_top launcher that opens that frame instead of FRAME_PCB_EDITOR. Mirrors eeschema's symbol_editor target." (
kicad/pcbnew/CMakeLists.txt:983-990)
It links the same ${PCBNEW_KIFACE_LIBRARIES} as pcbnew and differs only in the launcher
define: TOP_FRAME=FRAME_FOOTPRINT_EDITOR (:1001) vs the board editor's
TOP_FRAME=FRAME_PCB_EDITOR (:807/:813). The build script reflects the sharing — the
footprint editor reuses pcbnew's embind and stubs: EMBIND_APP="pcbnew", STUB_APP="pcbnew"
(build-kicad-target.sh:88, :100).
Schematic side: eeschema and symbol_editor, identically
EESCHEMA_LIBEDIT_SRCS (kicad/eeschema/CMakeLists.txt:367-378 — the symbol_editor/*.cpp)
folds into eeschema_kiface_objects (:656). The symbol_editor executable
(kicad/eeschema/CMakeLists.txt:758-788) is a second single_top launcher linking the same
${EESCHEMA_KIFACE_LIBRARIES} with TOP_FRAME=FRAME_SCH_SYMBOL_EDITOR;PGM_DATA_FILE_EXT="kicad_sym"
(:778) vs eeschema's TOP_FRAME=FRAME_SCH (:636/:641). (Symbol carries one extra
define beyond the frame — the data-file extension — which Part 1 must also make runtime;
footprint has no such extra.) See ../symbol-editor/0001-symbol-editor-port.md.
The smoking gun: artifact sizes
A full build populates output/ (sizes from the current tree):
| artifact | size | editor |
|---|---|---|
pcbnew.wasm |
146 MB | board editor |
footprint_editor.wasm |
146 MB | footprint editor |
eeschema.wasm |
82 MB | schematic editor |
symbol_editor.wasm |
82 MB | symbol editor |
gerbview.wasm |
42 MB | gerber viewer |
pl_editor.wasm |
44 MB | drawing-sheet editor |
calculator.wasm |
30 MB | PCB calculator |
146 == 146 and 82 == 82 is the whole story: we are not building four independent
codebases, we are linking two kifaces into four launchers. Debug builds additionally
emit <tool>.wasm.debug.wasm DWARF sidecars (~1.6 GB each for pcbnew/footprint). Shared
runtime files (wx.js, wx-dom.js, images.tar.gz) are copied alongside
(docker/build.sh:236-240).
How the editor is selected: build time, not runtime
The frame is fixed per-binary at compile time. The universal launcher
kicad/common/single_top.cpp opens whatever TOP_FRAME names (:418-420):
// "TOP_FRAME" is a macro that is passed on compiler command line from CMake,
// and is one of the types in FRAME_T.
KIWAY_PLAYER* frame = Kiway.Player( TOP_FRAME, true );
TOP_FRAME is a per-target CMake COMPILE_DEFINITIONS entry (-DTOP_FRAME=FRAME_xxx). The
same single_top.cpp source is compiled once per app; the footprint/symbol launchers
configure_file-copy it to a private TU so each can carry its own TOP_FRAME.
The JS side picks an editor purely by which .wasm/.js bundle it loads — no frame type is
ever passed in. The routing tables:
web/pcbjam-shared/src/schemas.ts:4-12— the canonicalTOOLSenum (the 7 tools).web/pcbjam-shared/src/schemas.ts:28-32—EXTENSION_TOOL(.kicad_pcb→pcbnew,.kicad_sch→eeschema,.kicad_wks→pl_editor).web/pcbjam-shared/src/schemas.ts:39-42—LIB_EXTENSION_TOOL(.kicad_sym→symbol_editor,.kicad_mod→footprint_editor);routes.ts:60routes a footprint/symbol lib to its tool.web/standalone/src/wasm/constants.ts:27-35—TOOL_ARGV0setsModule.thisProgram = /usr/bin/<tool>per tool (this is argv[0] for the WASM's DEBUG/identity check, not a frame selector).web/standalone/src/wasm/wasm-assets.ts/components/WasmTool.tsx— resolve the chosen tool to its CDN bundle (wasm/<tool>/<ver>/) and boot it.scripts/deploy/publish-wasm.mjs:33-41— publishes each of the 7 as a separatewasm/<tool>/<ver>/<tool>.{wasm,js}.
So: JS chooses the editor by loading a different wasm module; the module itself can only ever open its one baked-in frame. That is precisely the constraint Part 1 removes.
Loose ends found
wasm/bindings/symbol_editor_embind.cppandwasm/bindings/footprint_editor_embind.cppexist but are unused — the build forcesEMBIND_APP=eeschema/pcbnewfor those two (build-kicad-target.sh:86-93), and nothing references the files. Vestigial; no per-app embind divergence to reconcile when merging.- All 7 GUI tools are exercised by
tests/web/tools-open.spec.ts:28-34(boots each, asserts title + painted canvas + no abort). The footprint editor has no dedicatedtests/kicad/*.spec.tsbut is covered by the web suite (tests/web/footprint-*-remote.spec.ts) andtools-open.