2026-05-29 06:39:23 +02:00
|
|
|
#!/bin/bash
|
feat: pl_editor WASM port + browser file dialog fixes
Brings up KiCad's pagelayout_editor (drawing-sheet editor) in the
browser, to roughly the same "boots, canvas visible, partially usable
in-session" level as the existing pcbnew/eeschema/calculator ports.
Build:
- docker/build.sh: add pl_editor to the unified app dispatch (case,
subdir map, all-loop).
- scripts/kicad/build-kicad-target.sh: add pl_editor to the case;
upstream target name pl_editor under source subdir pagelayout_editor.
- scripts/kicad/build-pl_editor.sh: 7-line thin wrapper matching the
pcbnew/eeschema/calculator pattern.
- tests/scripts/setup-kicad-wasm.sh: copy_app pl_editor.
App glue:
- wasm/stubs/nl_pl_editor_plugin_stub.cpp: no-op SpaceMouse plugin so
pl_editor_frame.cpp's NL_PL_EDITOR_PLUGIN symbols resolve. Mirrors
nl_pcbnew_plugin_stub.cpp.
- tests/apps/kicad/pl_editor.html: browser shell. preRun creates
/home/kicad and FS.chdir there so file dialogs land somewhere
friendly instead of MEMFS root (/dev/, /proc/, etc.).
E2E coverage:
- tests/kicad/pl_editor.spec.ts: 5 tests — smoke (canvas, no abort),
wizard, File menu has Open/Save As, file-dialog folder-navigation
regression, canvas + toolbar metrics.
- tests/e2e/filedialog-folder-nav.spec.ts: wxWidgets-level twin of
the regression test (exercises the underlying widget directly via
the standalone filedialog_test app).
Submodule bumps:
- kicad → feature/pl-editor (WASM gating in pagelayout_editor's
CMakeLists + navlib stub).
- wxwidgets → feature/pl-editor (wxGenericFileDialog::OnOk navigates
into selected directories; wasm/mouse.cpp emits wxEVT_LEFT_DCLICK
via timestamp-based double-click detection — the latter benefits
every wxWidgets-WASM app).
See features/pl-editor/ for the design doc + per-repo diff patches.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 10:30:56 +02:00
|
|
|
# Build a KiCad app (pcbnew, eeschema, calculator, pl_editor) for WebAssembly.
|
2026-05-29 06:39:23 +02:00
|
|
|
#
|
|
|
|
|
# Usage:
|
|
|
|
|
# ./scripts/kicad/build-kicad-target.sh <app> [options]
|
|
|
|
|
#
|
|
|
|
|
# Args:
|
feat: pl_editor WASM port + browser file dialog fixes
Brings up KiCad's pagelayout_editor (drawing-sheet editor) in the
browser, to roughly the same "boots, canvas visible, partially usable
in-session" level as the existing pcbnew/eeschema/calculator ports.
Build:
- docker/build.sh: add pl_editor to the unified app dispatch (case,
subdir map, all-loop).
- scripts/kicad/build-kicad-target.sh: add pl_editor to the case;
upstream target name pl_editor under source subdir pagelayout_editor.
- scripts/kicad/build-pl_editor.sh: 7-line thin wrapper matching the
pcbnew/eeschema/calculator pattern.
- tests/scripts/setup-kicad-wasm.sh: copy_app pl_editor.
App glue:
- wasm/stubs/nl_pl_editor_plugin_stub.cpp: no-op SpaceMouse plugin so
pl_editor_frame.cpp's NL_PL_EDITOR_PLUGIN symbols resolve. Mirrors
nl_pcbnew_plugin_stub.cpp.
- tests/apps/kicad/pl_editor.html: browser shell. preRun creates
/home/kicad and FS.chdir there so file dialogs land somewhere
friendly instead of MEMFS root (/dev/, /proc/, etc.).
E2E coverage:
- tests/kicad/pl_editor.spec.ts: 5 tests — smoke (canvas, no abort),
wizard, File menu has Open/Save As, file-dialog folder-navigation
regression, canvas + toolbar metrics.
- tests/e2e/filedialog-folder-nav.spec.ts: wxWidgets-level twin of
the regression test (exercises the underlying widget directly via
the standalone filedialog_test app).
Submodule bumps:
- kicad → feature/pl-editor (WASM gating in pagelayout_editor's
CMakeLists + navlib stub).
- wxwidgets → feature/pl-editor (wxGenericFileDialog::OnOk navigates
into selected directories; wasm/mouse.cpp emits wxEVT_LEFT_DCLICK
via timestamp-based double-click detection — the latter benefits
every wxWidgets-WASM app).
See features/pl-editor/ for the design doc + per-repo diff patches.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 10:30:56 +02:00
|
|
|
# <app> pcbnew | eeschema | calculator | pl_editor (required)
|
2026-05-29 06:39:23 +02:00
|
|
|
#
|
|
|
|
|
# Options:
|
|
|
|
|
# --full Full clean rebuild (dependencies + KiCad)
|
|
|
|
|
# --clean-kicad Clean only KiCad build directory (not deps)
|
|
|
|
|
# --build-deps Build dependencies (default: skip)
|
|
|
|
|
# --debug Build with debug symbols (default)
|
|
|
|
|
# --release Build optimized without debug symbols
|
|
|
|
|
# --diag=... Diagnostic preprocessor flags (gal, coroutine, ctor, all)
|
|
|
|
|
# -j N Parallel compilation jobs (default: 1)
|
|
|
|
|
#
|
2026-05-29 12:01:44 +02:00
|
|
|
# Each app builds into its own tree: build-wasm/kicad-<app>/.
|
|
|
|
|
# Per-app extras live alongside generic stubs:
|
2026-05-29 06:39:23 +02:00
|
|
|
# - wasm/bindings/<app>_embind.cpp (optional)
|
|
|
|
|
# - wasm/stubs/<app>_frame_stub.cpp (optional, app-specific stubs)
|
|
|
|
|
# - wasm/stubs/<app>_scripting_stub.cpp (optional, app-specific scripting stubs)
|
2026-05-29 12:01:44 +02:00
|
|
|
#
|
|
|
|
|
# Most apps use the same name for the user-facing app, the CMake target, and
|
|
|
|
|
# the source subdirectory. Calculator is the exception: app=calculator but the
|
|
|
|
|
# upstream target and source subdir are both pcb_calculator (the OUTPUT_NAME
|
|
|
|
|
# property in pcb_calculator/CMakeLists.txt emits calculator.{js,wasm}).
|
feat: pl_editor WASM port + browser file dialog fixes
Brings up KiCad's pagelayout_editor (drawing-sheet editor) in the
browser, to roughly the same "boots, canvas visible, partially usable
in-session" level as the existing pcbnew/eeschema/calculator ports.
Build:
- docker/build.sh: add pl_editor to the unified app dispatch (case,
subdir map, all-loop).
- scripts/kicad/build-kicad-target.sh: add pl_editor to the case;
upstream target name pl_editor under source subdir pagelayout_editor.
- scripts/kicad/build-pl_editor.sh: 7-line thin wrapper matching the
pcbnew/eeschema/calculator pattern.
- tests/scripts/setup-kicad-wasm.sh: copy_app pl_editor.
App glue:
- wasm/stubs/nl_pl_editor_plugin_stub.cpp: no-op SpaceMouse plugin so
pl_editor_frame.cpp's NL_PL_EDITOR_PLUGIN symbols resolve. Mirrors
nl_pcbnew_plugin_stub.cpp.
- tests/apps/kicad/pl_editor.html: browser shell. preRun creates
/home/kicad and FS.chdir there so file dialogs land somewhere
friendly instead of MEMFS root (/dev/, /proc/, etc.).
E2E coverage:
- tests/kicad/pl_editor.spec.ts: 5 tests — smoke (canvas, no abort),
wizard, File menu has Open/Save As, file-dialog folder-navigation
regression, canvas + toolbar metrics.
- tests/e2e/filedialog-folder-nav.spec.ts: wxWidgets-level twin of
the regression test (exercises the underlying widget directly via
the standalone filedialog_test app).
Submodule bumps:
- kicad → feature/pl-editor (WASM gating in pagelayout_editor's
CMakeLists + navlib stub).
- wxwidgets → feature/pl-editor (wxGenericFileDialog::OnOk navigates
into selected directories; wasm/mouse.cpp emits wxEVT_LEFT_DCLICK
via timestamp-based double-click detection — the latter benefits
every wxWidgets-WASM app).
See features/pl-editor/ for the design doc + per-repo diff patches.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 10:30:56 +02:00
|
|
|
# pl_editor is the standard case but its source subdir is pagelayout_editor.
|
2026-05-29 06:39:23 +02:00
|
|
|
|
|
|
|
|
set -e
|
|
|
|
|
|
|
|
|
|
if [ -z "$1" ]; then
|
2026-06-03 14:23:57 +02:00
|
|
|
echo "Error: missing <app> argument (pcbnew | eeschema | calculator | pl_editor | symbol_editor | gerbview)" >&2
|
2026-05-29 06:39:23 +02:00
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
APP_NAME="$1"
|
|
|
|
|
shift
|
|
|
|
|
|
2026-06-02 13:35:37 +02:00
|
|
|
# KICAD_TARGET: the CMake/make target name.
|
|
|
|
|
# KICAD_SUBDIR: the source/build subdirectory the target's artifacts land in.
|
|
|
|
|
# Most apps share all three names; the exceptions:
|
|
|
|
|
# - calculator: target+subdir are both pcb_calculator (OUTPUT_NAME=calculator)
|
|
|
|
|
# - pl_editor: subdir is pagelayout_editor (upstream source dir name)
|
|
|
|
|
# - symbol_editor: served by the eeschema kiface, so it builds in eeschema/
|
2026-05-29 06:39:23 +02:00
|
|
|
case "$APP_NAME" in
|
2026-06-03 14:23:57 +02:00
|
|
|
pcbnew|eeschema|gerbview)
|
2026-05-29 12:01:44 +02:00
|
|
|
KICAD_TARGET="$APP_NAME"
|
2026-06-02 13:35:37 +02:00
|
|
|
KICAD_SUBDIR="$APP_NAME"
|
|
|
|
|
;;
|
|
|
|
|
pl_editor)
|
|
|
|
|
KICAD_TARGET="pl_editor"
|
|
|
|
|
KICAD_SUBDIR="pagelayout_editor"
|
2026-05-29 12:01:44 +02:00
|
|
|
;;
|
|
|
|
|
calculator)
|
|
|
|
|
KICAD_TARGET="pcb_calculator"
|
2026-06-02 13:35:37 +02:00
|
|
|
KICAD_SUBDIR="pcb_calculator"
|
|
|
|
|
;;
|
|
|
|
|
symbol_editor)
|
|
|
|
|
KICAD_TARGET="symbol_editor"
|
|
|
|
|
KICAD_SUBDIR="eeschema"
|
2026-05-29 12:01:44 +02:00
|
|
|
;;
|
2026-06-14 06:22:40 +02:00
|
|
|
footprint_editor)
|
|
|
|
|
# served by the pcbnew kiface, so it builds in pcbnew/ (like symbol_editor in eeschema/)
|
|
|
|
|
KICAD_TARGET="footprint_editor"
|
|
|
|
|
KICAD_SUBDIR="pcbnew"
|
|
|
|
|
;;
|
2026-06-18 12:21:15 +02:00
|
|
|
sym_convert)
|
|
|
|
|
# Standalone .lib -> .kicad_sym converter (node CLI). Its add_executable
|
|
|
|
|
# lives in eeschema/CMakeLists.txt (gated by KICAD_SYM_CONVERTER_WASM), so
|
|
|
|
|
# artifacts land in the eeschema/ subdir of its own kicad-sym_convert tree.
|
|
|
|
|
KICAD_TARGET="sym_convert"
|
|
|
|
|
KICAD_SUBDIR="eeschema"
|
|
|
|
|
;;
|
2026-05-29 06:39:23 +02:00
|
|
|
*)
|
2026-06-18 12:21:15 +02:00
|
|
|
echo "Error: unknown app '$APP_NAME' (expected: pcbnew | eeschema | calculator | pl_editor | symbol_editor | footprint_editor | gerbview | sym_convert)" >&2
|
2026-05-29 06:39:23 +02:00
|
|
|
exit 1
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
|
2026-06-13 11:06:54 +02:00
|
|
|
# Which app's embind bindings to compile + link. Most apps use their own; the
|
|
|
|
|
# symbol_editor is the eeschema kiface launched at a different TOP_FRAME and has
|
|
|
|
|
# no embind of its own, so it reuses eeschema's — whose bindings (kicadCollabOnSave
|
|
|
|
|
# et al.) the shared kiface objects reference. Without this the symbol_editor link
|
|
|
|
|
# fails with "undefined symbol: kicadCollabOnSave" (the placeholder defines nothing).
|
|
|
|
|
case "$APP_NAME" in
|
2026-06-14 06:22:40 +02:00
|
|
|
symbol_editor) EMBIND_APP="eeschema" ;;
|
|
|
|
|
footprint_editor) EMBIND_APP="pcbnew" ;;
|
2026-06-18 12:21:15 +02:00
|
|
|
# sym_convert links the eeschema kiface objects, which reference eeschema's
|
|
|
|
|
# embind symbols (kicadCollabOnSave et al.) — reuse eeschema's embind object.
|
|
|
|
|
sym_convert) EMBIND_APP="eeschema" ;;
|
2026-06-14 06:22:40 +02:00
|
|
|
*) EMBIND_APP="$APP_NAME" ;;
|
|
|
|
|
esac
|
|
|
|
|
|
|
|
|
|
# Which app's WASM stub libraries (scripting/frame placeholders) to link. Like
|
|
|
|
|
# EMBIND_APP, the footprint_editor reuses pcbnew's: it links the pcbnew kiface
|
|
|
|
|
# objects, which reference pcbnew's action-plugin scripting symbols
|
|
|
|
|
# (pcbnewGetScriptsSearchPaths et al., defined in pcbnew_scripting_stub.cpp).
|
|
|
|
|
case "$APP_NAME" in
|
|
|
|
|
footprint_editor) STUB_APP="pcbnew" ;;
|
2026-06-18 12:21:15 +02:00
|
|
|
# sym_convert links the eeschema kiface objects, so it needs eeschema's
|
|
|
|
|
# frame stub (eeschema_frame_stub.cpp) like symbol_editor does.
|
|
|
|
|
sym_convert) STUB_APP="eeschema" ;;
|
2026-06-14 06:22:40 +02:00
|
|
|
*) STUB_APP="$APP_NAME" ;;
|
2026-06-13 11:06:54 +02:00
|
|
|
esac
|
|
|
|
|
|
2026-05-29 06:39:23 +02:00
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
|
|
|
source "${SCRIPT_DIR}/../common/env.sh"
|
|
|
|
|
source "${SCRIPT_DIR}/../common/versions.sh"
|
|
|
|
|
source "${SCRIPT_DIR}/../common/functions.sh"
|
2026-06-01 17:31:03 +02:00
|
|
|
source "${SCRIPT_DIR}/../common/stages.sh"
|
2026-05-29 06:39:23 +02:00
|
|
|
|
|
|
|
|
KICAD_DIR="${PROJECT_ROOT}/kicad"
|
|
|
|
|
WASM_LAYER="${PROJECT_ROOT}/wasm"
|
2026-06-11 00:19:53 +02:00
|
|
|
|
2026-06-12 10:18:16 +02:00
|
|
|
KICAD_BUILD="${BUILD_ROOT}/kicad-${APP_NAME}"
|
|
|
|
|
KICAD_STAMP="${BUILD_ROOT}/stamps/kicad-${APP_NAME}.stamp"
|
|
|
|
|
WX_BUILD="${BUILD_ROOT}/wxwidgets"
|
2026-05-29 06:39:23 +02:00
|
|
|
|
|
|
|
|
# Parse arguments - incremental build by default (optimized for development)
|
|
|
|
|
NO_CLEAN=1
|
|
|
|
|
FULL_CLEAN=0
|
|
|
|
|
SKIP_DEPS=1
|
|
|
|
|
DEBUG=0
|
|
|
|
|
DIAG_LIST=""
|
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
|
|
|
case $1 in
|
|
|
|
|
--full)
|
|
|
|
|
FULL_CLEAN=1
|
|
|
|
|
NO_CLEAN=0
|
|
|
|
|
SKIP_DEPS=0
|
|
|
|
|
shift
|
|
|
|
|
;;
|
|
|
|
|
--clean-kicad)
|
|
|
|
|
NO_CLEAN=0
|
|
|
|
|
shift
|
|
|
|
|
;;
|
|
|
|
|
--build-deps)
|
|
|
|
|
SKIP_DEPS=0
|
|
|
|
|
shift
|
|
|
|
|
;;
|
|
|
|
|
--debug)
|
|
|
|
|
DEBUG=1
|
|
|
|
|
shift
|
|
|
|
|
;;
|
|
|
|
|
--release)
|
|
|
|
|
DEBUG_BUILD=0
|
|
|
|
|
export DEBUG_BUILD
|
|
|
|
|
shift
|
|
|
|
|
;;
|
|
|
|
|
--diag=*)
|
|
|
|
|
DIAG_LIST="${1#--diag=}"
|
|
|
|
|
shift
|
|
|
|
|
;;
|
|
|
|
|
--diag)
|
|
|
|
|
DIAG_LIST="$2"
|
|
|
|
|
shift 2
|
|
|
|
|
;;
|
|
|
|
|
-j)
|
|
|
|
|
export JOBS="$2"
|
|
|
|
|
shift 2
|
|
|
|
|
;;
|
|
|
|
|
-j*)
|
|
|
|
|
export JOBS="${1#-j}"
|
|
|
|
|
shift
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
shift
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
# Diagnostic preprocessor defines from --diag=<csv> (gal, coroutine, ctor, all).
|
|
|
|
|
# These gate the KI_DIAG_* macros in kicad/include/kicad_wasm_diag.h. Output goes
|
|
|
|
|
# to stdout ([KICAD_OUT] logs), never errors. Off by default.
|
|
|
|
|
DIAG_DEFINES=""
|
|
|
|
|
if [ -n "${DIAG_LIST}" ]; then
|
|
|
|
|
IFS=',' read -ra _diag_cats <<< "${DIAG_LIST}"
|
|
|
|
|
for _cat in "${_diag_cats[@]}"; do
|
|
|
|
|
case "${_cat}" in
|
|
|
|
|
gal) DIAG_DEFINES="${DIAG_DEFINES} -DKICAD_DIAG_GAL=1" ;;
|
|
|
|
|
coroutine) DIAG_DEFINES="${DIAG_DEFINES} -DKICAD_DIAG_COROUTINE=1" ;;
|
|
|
|
|
ctor) DIAG_DEFINES="${DIAG_DEFINES} -DKICAD_DIAG_CTOR=1" ;;
|
|
|
|
|
all) DIAG_DEFINES="${DIAG_DEFINES} -DKICAD_DIAG_GAL=1 -DKICAD_DIAG_COROUTINE=1 -DKICAD_DIAG_CTOR=1" ;;
|
|
|
|
|
"") ;;
|
|
|
|
|
*) log_warn "Unknown --diag category: '${_cat}' (valid: gal, coroutine, ctor, all)" ;;
|
|
|
|
|
esac
|
|
|
|
|
done
|
|
|
|
|
log_info "Diagnostic logging enabled:${DIAG_DEFINES}"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
log_info "Building app: ${APP_NAME}"
|
|
|
|
|
log_info "Using ${JOBS} parallel jobs"
|
|
|
|
|
|
|
|
|
|
# Step 1: Clean build directories
|
|
|
|
|
if [ $FULL_CLEAN -eq 1 ]; then
|
|
|
|
|
log_info "Full clean: removing all stamps and build directories..."
|
|
|
|
|
rm -rf "${STAMPS_DIR}"/*
|
|
|
|
|
rm -rf "${BUILD_ROOT}/deps"/*
|
2026-06-12 10:18:16 +02:00
|
|
|
rm -rf "${BUILD_ROOT}/wxwidgets"
|
2026-05-29 06:39:23 +02:00
|
|
|
rm -rf "${BUILD_ROOT}/stubs"
|
|
|
|
|
rm -rf "${KICAD_BUILD}"
|
|
|
|
|
rm -rf "${SYSROOT}"/*
|
|
|
|
|
elif [ $NO_CLEAN -eq 0 ]; then
|
|
|
|
|
log_info "Cleaning KiCad ${APP_NAME} build directory..."
|
|
|
|
|
rm -rf "${KICAD_BUILD}" "${KICAD_STAMP}"
|
|
|
|
|
else
|
|
|
|
|
log_info "Incremental build (use --clean-kicad or --full to clean)"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# Step 2: Build dependencies
|
|
|
|
|
# Note: --with-occ for OpenCASCADE, but NOT ngspice since KICAD_SPICE=OFF
|
|
|
|
|
if [ $SKIP_DEPS -eq 0 ]; then
|
2026-06-01 17:31:03 +02:00
|
|
|
kw_stage deps
|
2026-05-29 06:39:23 +02:00
|
|
|
log_info "Building dependencies..."
|
|
|
|
|
"${SCRIPT_DIR}/../deps/build-all-deps.sh" --with-occ
|
|
|
|
|
else
|
|
|
|
|
log_info "Skipping dependencies (use --build-deps or --full to build)"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# Note: We don't check the KiCad stamp here for incremental builds.
|
|
|
|
|
# CMake handles dependency tracking - it will detect changed source files
|
|
|
|
|
# and only recompile what's needed. The stamp is created at the end for
|
|
|
|
|
# scripts that want to know if KiCad was ever built successfully.
|
|
|
|
|
|
|
|
|
|
# Step 4: Build wxWidgets (incremental - only recompiles changed files)
|
2026-06-01 17:31:03 +02:00
|
|
|
kw_stage wxwidgets
|
2026-05-29 06:39:23 +02:00
|
|
|
log_info "Building wxWidgets..."
|
2026-06-12 10:18:16 +02:00
|
|
|
"${SCRIPT_DIR}/../build-wx-wasm.sh" --no-clean
|
2026-05-29 06:39:23 +02:00
|
|
|
|
|
|
|
|
log_info "Building KiCad ${APP_NAME} ${KICAD_VERSION} for WASM..."
|
|
|
|
|
|
|
|
|
|
# Step 5: Set build type
|
2026-06-29 19:50:18 +02:00
|
|
|
# Exception model: native WebAssembly exceptions (legacy binary encoding) + wasm setjmp/longjmp,
|
|
|
|
|
# single-sourced from scripts/common/env.sh (KiCad and wxWidgets must agree — mixing EH models
|
|
|
|
|
# link-fails / traps; both build with exceptions enabled). -matomics -mbulk-memory are required for
|
|
|
|
|
# shared memory (pthreads).
|
|
|
|
|
KICAD_EH_FLAGS="$DEPS_EH_FLAGS"
|
|
|
|
|
log_info "KiCad EH model flags: ${KICAD_EH_FLAGS}"
|
|
|
|
|
|
2026-05-29 06:39:23 +02:00
|
|
|
# Use environment DEBUG_BUILD if set, otherwise check local --debug flag
|
|
|
|
|
# NOTE: We use -O1 for debug builds because -O0 produces WASM with too many
|
|
|
|
|
# locals for V8/Chrome to compile (error: "local count too large").
|
|
|
|
|
# -O1 keeps debug info but optimizes enough to stay under V8's limits.
|
|
|
|
|
if [ "${DEBUG_BUILD:-0}" = "1" ] || [ $DEBUG -eq 1 ]; then
|
|
|
|
|
BUILD_TYPE="Debug"
|
2026-06-29 19:50:18 +02:00
|
|
|
EXTRA_FLAGS="-g -O1 ${KICAD_EH_FLAGS} -matomics -mbulk-memory"
|
|
|
|
|
# CMake defines DEBUG for Config=Debug (kicad/CMakeLists.txt:351). The embind TU (Step 7) is
|
|
|
|
|
# compiled OUTSIDE CMake, so it must define DEBUG too — otherwise a DEBUG-gated virtual
|
|
|
|
|
# (EDA_ITEM::Show, eda_item.h:471) occupies a vtable slot in the core's emitted vtable that the
|
|
|
|
|
# embind TU doesn't account for, shifting every later slot by one. Then every virtual call made
|
|
|
|
|
# from the embind TU past that slot (SetWidth/GetPosition/...) reads the wrong vtable offset and
|
|
|
|
|
# mis-dispatches at runtime (call_indirect signature-mismatch trap; under native-EH the trap is
|
|
|
|
|
# swallowed by the apply coroutine's catch_all → silent hang). See task #54 root-cause analysis.
|
|
|
|
|
EMBIND_CONFIG_DEFINES="-DDEBUG"
|
2026-05-29 06:39:23 +02:00
|
|
|
# -gseparate-dwarf puts debug info in a separate .debug.wasm file
|
|
|
|
|
# This keeps the main WASM small (~200MB) while preserving full debug info
|
|
|
|
|
# DevTools loads the debug file on-demand when debugging
|
2026-06-29 19:50:18 +02:00
|
|
|
LINKER_DEBUG_FLAGS="-O1 -g -gseparate-dwarf ${KICAD_EH_FLAGS}"
|
2026-05-29 06:39:23 +02:00
|
|
|
log_info "Building KiCad in DEBUG mode (separate DWARF for smaller main binary)"
|
|
|
|
|
else
|
|
|
|
|
BUILD_TYPE="Release"
|
2026-06-29 19:50:18 +02:00
|
|
|
EXTRA_FLAGS="-O2 ${KICAD_EH_FLAGS} -matomics -mbulk-memory"
|
|
|
|
|
EMBIND_CONFIG_DEFINES="" # Release defines no DEBUG in either TU → vtable layouts already match
|
2026-05-29 06:39:23 +02:00
|
|
|
# -O0 at link time skips wasm-opt (which can OOM on large WASM files)
|
|
|
|
|
# Compilation is still -O2 for optimized code, but we skip post-link wasm-opt
|
2026-06-29 19:50:18 +02:00
|
|
|
LINKER_DEBUG_FLAGS="-O0 ${KICAD_EH_FLAGS}"
|
2026-05-29 06:39:23 +02:00
|
|
|
log_info "Building KiCad in RELEASE mode (skipping wasm-opt due to memory limits)"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# Step 6: Create build directory
|
|
|
|
|
mkdir -p "${KICAD_BUILD}"
|
|
|
|
|
cd "${KICAD_BUILD}"
|
|
|
|
|
|
|
|
|
|
# Step 6.1: Build stub libraries for missing symbols
|
|
|
|
|
# Generic stubs (libgit2, curl, nng) are shared across apps and built in BUILD_ROOT/stubs.
|
|
|
|
|
# App-specific stubs (e.g. pcbnew_scripting_stub) build into the same directory but
|
|
|
|
|
# are only linked in when the corresponding source exists.
|
|
|
|
|
STUBS_DIR="${PROJECT_ROOT}/wasm/stubs"
|
|
|
|
|
STUBS_BUILD="${BUILD_ROOT}/stubs"
|
|
|
|
|
mkdir -p "${STUBS_BUILD}"
|
|
|
|
|
|
2026-06-29 19:50:18 +02:00
|
|
|
# ABI-affecting flags shared by EVERY C++ TU compiled OUTSIDE CMake (the embind + the app stubs below).
|
|
|
|
|
# The core CMake TUs get all of these (DEBUG via Config=Debug -> kicad/CMakeLists.txt:351;
|
|
|
|
|
# KICAD_USE_PLATFORM_WASM; the char16_t char_traits force-include). A TU that misses any of them can
|
|
|
|
|
# diverge in vtable layout / ABI from the core — task #54: the embind missing -DDEBUG shifted its vtable
|
|
|
|
|
# slot offsets by one and hung the collab apply (call_indirect signature-mismatch). Keep them in ONE
|
|
|
|
|
# place so no out-of-CMake C++ TU can skew again. (EMBIND_CONFIG_DEFINES holds the build-config -DDEBUG,
|
|
|
|
|
# set in the BUILD_TYPE block above; empty in Release where neither side defines DEBUG.)
|
|
|
|
|
KICAD_TU_ABI_FLAGS="${EMBIND_CONFIG_DEFINES} -DKICAD_USE_PLATFORM_WASM=1 -include ${STUBS_DIR}/char_traits_uint16_workaround.h"
|
|
|
|
|
|
2026-06-01 17:31:03 +02:00
|
|
|
kw_stage kicad-stubs
|
2026-05-29 06:39:23 +02:00
|
|
|
log_info "Building stub libraries..."
|
|
|
|
|
# Compile libgit2 stub
|
|
|
|
|
emcc -c "${STUBS_DIR}/libgit2_stub.c" -o "${STUBS_BUILD}/libgit2_stub.o"
|
|
|
|
|
emar rcs "${STUBS_BUILD}/libgit2_stub.a" "${STUBS_BUILD}/libgit2_stub.o"
|
|
|
|
|
|
|
|
|
|
# Compile curl stub
|
|
|
|
|
emcc -c "${STUBS_DIR}/curl_stub.c" -o "${STUBS_BUILD}/curl_stub.o"
|
|
|
|
|
emar rcs "${STUBS_BUILD}/libcurl_stub.a" "${STUBS_BUILD}/curl_stub.o"
|
|
|
|
|
|
2026-06-05 13:18:24 +02:00
|
|
|
# Note: the GLU tesselator is provided by kicad/libs/kimath/glu_tess/glu_tess_impl.cpp,
|
|
|
|
|
# compiled as part of the GAL library (requires KiCad headers).
|
2026-05-29 06:39:23 +02:00
|
|
|
|
|
|
|
|
# Compile NNG stub (IPC API requires NNG but sockets don't work in WASM)
|
|
|
|
|
emcc -c -I"${STUBS_DIR}" "${STUBS_DIR}/nng_stub.c" -o "${STUBS_BUILD}/nng_stub.o"
|
|
|
|
|
emar rcs "${STUBS_BUILD}/libnng_stub.a" "${STUBS_BUILD}/nng_stub.o"
|
|
|
|
|
|
|
|
|
|
# wx flags for any C++ stubs that include wx headers
|
|
|
|
|
WX_CXXFLAGS=$("${WX_BUILD}/wx-config" --cxxflags 2>/dev/null || echo "-I${WX_BUILD}/lib/wx/include/emscripten-unicode-static-3.2 -I${PROJECT_ROOT}/wxwidgets/include")
|
|
|
|
|
|
|
|
|
|
# App-specific stubs:
|
|
|
|
|
# - pcbnew: pcbnew_scripting_stub.cpp (action-plugin scripting placeholders)
|
|
|
|
|
# - eeschema: eeschema_frame_stub.cpp (placeholder; grows as linker dictates)
|
|
|
|
|
APP_STUB_LINK=""
|
2026-06-14 06:22:40 +02:00
|
|
|
APP_SCRIPTING_STUB_SRC="${STUBS_DIR}/${STUB_APP}_scripting_stub.cpp"
|
2026-05-29 06:39:23 +02:00
|
|
|
if [ -f "${APP_SCRIPTING_STUB_SRC}" ]; then
|
2026-06-14 06:22:40 +02:00
|
|
|
log_info "Building app scripting stub: ${STUB_APP}_scripting_stub.cpp"
|
2026-06-29 19:50:18 +02:00
|
|
|
em++ -c ${KICAD_TU_ABI_FLAGS} ${WX_CXXFLAGS} "${APP_SCRIPTING_STUB_SRC}" -o "${STUBS_BUILD}/${STUB_APP}_scripting_stub.o"
|
2026-06-14 06:22:40 +02:00
|
|
|
emar rcs "${STUBS_BUILD}/lib${STUB_APP}_scripting_stub.a" "${STUBS_BUILD}/${STUB_APP}_scripting_stub.o"
|
|
|
|
|
APP_STUB_LINK="${APP_STUB_LINK} ${STUBS_BUILD}/lib${STUB_APP}_scripting_stub.a"
|
2026-05-29 06:39:23 +02:00
|
|
|
fi
|
|
|
|
|
|
2026-06-14 06:22:40 +02:00
|
|
|
APP_FRAME_STUB_SRC="${STUBS_DIR}/${STUB_APP}_frame_stub.cpp"
|
2026-05-29 06:39:23 +02:00
|
|
|
if [ -f "${APP_FRAME_STUB_SRC}" ] && [ -s "${APP_FRAME_STUB_SRC}" ]; then
|
2026-06-14 06:22:40 +02:00
|
|
|
log_info "Building app frame stub: ${STUB_APP}_frame_stub.cpp"
|
2026-06-29 19:50:18 +02:00
|
|
|
em++ -c ${KICAD_TU_ABI_FLAGS} ${WX_CXXFLAGS} "${APP_FRAME_STUB_SRC}" -o "${STUBS_BUILD}/${STUB_APP}_frame_stub.o"
|
2026-06-14 06:22:40 +02:00
|
|
|
emar rcs "${STUBS_BUILD}/lib${STUB_APP}_frame_stub.a" "${STUBS_BUILD}/${STUB_APP}_frame_stub.o"
|
|
|
|
|
APP_STUB_LINK="${APP_STUB_LINK} ${STUBS_BUILD}/lib${STUB_APP}_frame_stub.a"
|
2026-05-29 06:39:23 +02:00
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
log_info "Stub libraries built"
|
|
|
|
|
|
2026-06-18 12:21:15 +02:00
|
|
|
# Step 6.2/6.3: wasm-opt + wasm-emscripten-finalize handling.
|
|
|
|
|
# For the editor apps these tools OOM on the huge debug wasm, so we stub them in
|
|
|
|
|
# the container and run them on the host (docker/build.sh phase 2). The small,
|
|
|
|
|
# debug-stripped (-g0) converter finalizes fine in-container, so for sym_convert
|
|
|
|
|
# we restore/keep the real tools and skip host post-processing entirely.
|
2026-05-29 06:39:23 +02:00
|
|
|
if [ -z "${EMSDK}" ]; then
|
|
|
|
|
log_error "EMSDK environment variable is not set."
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
EMSDK_WASM_OPT="${EMSDK}/upstream/bin/wasm-opt"
|
|
|
|
|
EMSDK_FINALIZE="${EMSDK}/upstream/bin/wasm-emscripten-finalize"
|
2026-06-18 12:21:15 +02:00
|
|
|
|
|
|
|
|
if [ "${APP_NAME}" = "sym_convert" ]; then
|
|
|
|
|
# Use the real tools so the converter is fully finalized inside the container.
|
|
|
|
|
[ -f "${EMSDK_WASM_OPT}.real" ] && cp "${EMSDK_WASM_OPT}.real" "${EMSDK_WASM_OPT}"
|
|
|
|
|
[ -f "${EMSDK_FINALIZE}.real" ] && cp "${EMSDK_FINALIZE}.real" "${EMSDK_FINALIZE}"
|
|
|
|
|
log_info "Using real wasm-opt/finalize for sym_convert (finalize in-container)"
|
|
|
|
|
else
|
|
|
|
|
if [ -f "${EMSDK_WASM_OPT}" ] && [ ! -f "${EMSDK_WASM_OPT}.real" ]; then
|
|
|
|
|
log_info "Backing up real wasm-opt..."
|
|
|
|
|
mv "${EMSDK_WASM_OPT}" "${EMSDK_WASM_OPT}.real"
|
|
|
|
|
fi
|
|
|
|
|
# Always copy the latest stub (in case it was updated)
|
|
|
|
|
cp "${STUBS_DIR}/wasm-opt-stub.sh" "${EMSDK_WASM_OPT}"
|
|
|
|
|
chmod +x "${EMSDK_WASM_OPT}"
|
|
|
|
|
log_info "wasm-opt stub installed (asyncify will run on host)"
|
|
|
|
|
|
|
|
|
|
if [ -f "${EMSDK_FINALIZE}" ] && [ ! -f "${EMSDK_FINALIZE}.real" ]; then
|
|
|
|
|
log_info "Backing up real wasm-emscripten-finalize..."
|
|
|
|
|
mv "${EMSDK_FINALIZE}" "${EMSDK_FINALIZE}.real"
|
|
|
|
|
fi
|
|
|
|
|
# Always copy the latest stub (in case it was updated)
|
|
|
|
|
cp "${STUBS_DIR}/wasm-emscripten-finalize-stub.sh" "${EMSDK_FINALIZE}"
|
|
|
|
|
chmod +x "${EMSDK_FINALIZE}"
|
|
|
|
|
log_info "wasm-emscripten-finalize stub installed (finalize will run on host)"
|
2026-05-29 06:39:23 +02:00
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# Step 6.5: Verify WASM support is in KiCad fork
|
|
|
|
|
# The kicad submodule should already have WASM port detection and kiplatform support
|
|
|
|
|
KICAD_CMAKE="${KICAD_DIR}/CMakeLists.txt"
|
|
|
|
|
if ! grep -q "msw|qt|gtk|osx|wasm" "${KICAD_CMAKE}"; then
|
|
|
|
|
log_error "KiCad fork is missing WASM port detection support."
|
|
|
|
|
log_error "Please ensure the kicad submodule has WASM modifications."
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
KIPLATFORM_CMAKE="${KICAD_DIR}/libs/kiplatform/CMakeLists.txt"
|
|
|
|
|
if ! grep -q "KICAD_WX_PORT STREQUAL wasm" "${KIPLATFORM_CMAKE}"; then
|
|
|
|
|
log_error "KiCad fork is missing kiplatform WASM support."
|
|
|
|
|
log_error "Please ensure the kicad submodule has WASM modifications."
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
log_info "KiCad WASM support verified"
|
|
|
|
|
|
|
|
|
|
# Embind object — built after CMake configure runs (so config.h exists). The
|
|
|
|
|
# linker line below references "${STUBS_BUILD}/${APP_NAME}_embind.o" so we
|
|
|
|
|
# create an empty placeholder when the source is missing, to keep the link
|
|
|
|
|
# line stable across apps.
|
2026-06-13 11:06:54 +02:00
|
|
|
EMBIND_OBJ="${STUBS_BUILD}/${EMBIND_APP}_embind.o"
|
|
|
|
|
EMBIND_SRC="${PROJECT_ROOT}/wasm/bindings/${EMBIND_APP}_embind.cpp"
|
2026-05-29 06:39:23 +02:00
|
|
|
|
|
|
|
|
# Step 7: Configure KiCad with CMake
|
|
|
|
|
# We use CMAKE_MODULE_PATH to inject our compatibility layer
|
2026-06-01 17:31:03 +02:00
|
|
|
kw_stage kicad-configure
|
2026-05-29 06:39:23 +02:00
|
|
|
log_info "Configuring KiCad with CMake..."
|
|
|
|
|
|
|
|
|
|
# Use ccache if available (CMAKE_*_COMPILER_LAUNCHER is the proper CMake way)
|
|
|
|
|
CCACHE_OPTS=""
|
|
|
|
|
if command -v ccache &> /dev/null; then
|
|
|
|
|
CCACHE_OPTS="-DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache"
|
|
|
|
|
log_info "Using ccache for compilation"
|
|
|
|
|
fi
|
|
|
|
|
|
2026-06-18 12:21:15 +02:00
|
|
|
# The standalone converter is a gated eeschema target; enabling the option also
|
|
|
|
|
# trims the SCH_IO factory to the two KiCad plugins (no pcbjam/http) for this tree.
|
|
|
|
|
SYM_CONVERTER_CMAKE_FLAG=""
|
|
|
|
|
if [ "${APP_NAME}" = "sym_convert" ]; then
|
|
|
|
|
SYM_CONVERTER_CMAKE_FLAG="-DKICAD_SYM_CONVERTER_WASM=ON"
|
|
|
|
|
fi
|
|
|
|
|
|
2026-06-29 19:50:18 +02:00
|
|
|
# 3D viewer: built by DEFAULT (BUILD_3D_VIEWER=ON). Opt out with BUILD_3D_VIEWER=OFF, which links the
|
|
|
|
|
# 3D stubs instead. The 3D viewer renders with the GL-free CPU raytracer (RENDER_3D_RAYTRACE_RAM)
|
|
|
|
|
# blitted to the canvas through a plain WebGL2 textured quad — no -sLEGACY_GL_EMULATION. KiCad's
|
|
|
|
|
# fixed-function OpenGL renderer is still compiled (shared files reference it) but never executed on
|
|
|
|
|
# WASM, so its FFP/GLU entry points are satisfied at link time by no-op stubs (gl_ffp_stub.c). The
|
|
|
|
|
# KiCad CMake option KICAD_BUILD_3D_VIEWER_WASM stays OFF upstream; our build passes it explicitly.
|
|
|
|
|
# See docs/features/fork-cleanup/10-3d-viewer.md.
|
|
|
|
|
BUILD_3D_VIEWER="${BUILD_3D_VIEWER:-ON}"
|
2026-06-17 17:02:25 +02:00
|
|
|
GL3D_LINK_FLAGS=""
|
|
|
|
|
if [ "${BUILD_3D_VIEWER}" = "ON" ]; then
|
|
|
|
|
log_info "3D viewer ENABLED for WASM (BUILD_3D_VIEWER=ON)"
|
2026-06-18 10:43:45 +02:00
|
|
|
emcc -c -I"${STUBS_DIR}" "${STUBS_DIR}/gl_ffp_stub.c" -o "${STUBS_BUILD}/gl_ffp_stub.o"
|
|
|
|
|
GL3D_LINK_FLAGS="${STUBS_BUILD}/gl_ffp_stub.o"
|
2026-06-17 17:02:25 +02:00
|
|
|
fi
|
|
|
|
|
|
2026-06-30 18:17:39 +02:00
|
|
|
# Multi-threaded CPU raytracer (mainline threading restored): link the main-thread
|
|
|
|
|
# nanosleep->Asyncify-yield shim so the raw-thread raytracer joins (sleep_for busy-wait)
|
|
|
|
|
# yield to the JS event loop instead of deadlocking on-demand pthread-Worker creation.
|
|
|
|
|
# Mirrors the gl_ffp_stub pattern (compile to .o, add to the link). Shim:
|
|
|
|
|
# wasm/shims/nanosleep_yield.c; its EM_ASYNC_JS yield is covered by env.__asyncjs__* in
|
|
|
|
|
# scripts/common/asyncify-imports.txt.
|
|
|
|
|
emcc -c -pthread "${PROJECT_ROOT}/wasm/shims/nanosleep_yield.c" -o "${STUBS_BUILD}/nanosleep_yield.o"
|
|
|
|
|
NANOSLEEP_YIELD_LINK="${STUBS_BUILD}/nanosleep_yield.o"
|
|
|
|
|
|
2026-05-29 06:39:23 +02:00
|
|
|
emcmake cmake "${KICAD_DIR}" \
|
|
|
|
|
${CCACHE_OPTS} \
|
2026-06-18 12:21:15 +02:00
|
|
|
${SYM_CONVERTER_CMAKE_FLAG} \
|
2026-05-29 06:39:23 +02:00
|
|
|
-DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
|
|
|
|
|
-DCMAKE_INSTALL_PREFIX="${SYSROOT}" \
|
|
|
|
|
-DCMAKE_MODULE_PATH="${WASM_LAYER}/cmake" \
|
|
|
|
|
-DSYSROOT="${SYSROOT}" \
|
|
|
|
|
-DCMAKE_POLICY_VERSION_MINIMUM=3.5 \
|
2026-06-29 19:50:18 +02:00
|
|
|
-DCMAKE_CXX_FLAGS="${EXTRA_FLAGS} -Xclang -fno-pch-timestamp -pthread -sUSE_ZLIB=1 -DKICAD_USE_PLATFORM_WASM=1${DIAG_DEFINES} -I${SYSROOT}/include -I${STUBS_DIR} -include ${STUBS_DIR}/char_traits_uint16_workaround.h" \
|
2026-05-29 06:39:23 +02:00
|
|
|
-DCMAKE_C_FLAGS="${EXTRA_FLAGS} -pthread -sUSE_ZLIB=1 -I${SYSROOT}/include -I${STUBS_DIR}" \
|
2026-07-01 07:58:30 +02:00
|
|
|
-DCMAKE_EXE_LINKER_FLAGS="${LINKER_DEBUG_FLAGS} -pthread -sUSE_ZLIB=1 -sASYNCIFY=1 -sDYNCALLS=1 -sASYNCIFY_STACK_SIZE=65536 -sUSE_PTHREADS=1 -sMALLOC=mimalloc -sPTHREAD_POOL_SIZE='navigator.hardwareConcurrency' -sPTHREAD_POOL_SIZE_STRICT=0 -sALLOW_MEMORY_GROWTH=1 -sINITIAL_MEMORY=256MB -sMAXIMUM_MEMORY=4GB -sMAX_WEBGL_VERSION=2 ${GL3D_LINK_FLAGS} ${NANOSLEEP_YIELD_LINK} -sEXPORTED_RUNTIME_METHODS=['ccall','cwrap','UTF8ToString','stringToUTF8','lengthBytesUTF8','dynCall'] -sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE=['\$dynCall'] --bind -L${SYSROOT}/lib ${STUBS_BUILD}/libgit2_stub.a ${STUBS_BUILD}/libcurl_stub.a${APP_STUB_LINK} ${STUBS_BUILD}/libnng_stub.a ${EMBIND_OBJ}" \
|
2026-05-29 06:39:23 +02:00
|
|
|
-DCMAKE_PREFIX_PATH="${SYSROOT};${WX_BUILD}" \
|
|
|
|
|
-DwxWidgets_CONFIG_EXECUTABLE="${WX_BUILD}/wx-config" \
|
|
|
|
|
\
|
|
|
|
|
-DKICAD_BUILD_QA_TESTS=OFF \
|
|
|
|
|
-DKICAD_SPICE=OFF \
|
|
|
|
|
-DKICAD_USE_EGL=OFF \
|
|
|
|
|
-DKICAD_USE_BUNDLED_GLEW=ON \
|
2026-06-17 17:02:25 +02:00
|
|
|
-DKICAD_BUILD_3D_VIEWER_WASM=${BUILD_3D_VIEWER} \
|
2026-05-29 06:39:23 +02:00
|
|
|
-DKICAD_IPC_API=ON \
|
|
|
|
|
-DKICAD_USE_PCH=ON \
|
|
|
|
|
\
|
|
|
|
|
-DZSTD_ROOT="${SYSROOT}" \
|
|
|
|
|
-DZSTD_INCLUDE_DIR="${SYSROOT}/include" \
|
|
|
|
|
-DZSTD_LIBRARY="${SYSROOT}/lib/libzstd.a" \
|
|
|
|
|
-DGLM_INCLUDE_DIR="${SYSROOT}/include" \
|
|
|
|
|
-DGLM_VERSION="0.9.9.8" \
|
|
|
|
|
-DBOOST_ROOT="${SYSROOT}" \
|
|
|
|
|
-DBoost_INCLUDE_DIR="${SYSROOT}/include" \
|
|
|
|
|
-DBoost_LIBRARY_DIR="${SYSROOT}/lib" \
|
|
|
|
|
-DBoost_NO_SYSTEM_PATHS=ON \
|
|
|
|
|
-DBoost_NO_BOOST_CMAKE=ON \
|
|
|
|
|
-DFREETYPE_INCLUDE_DIR_ft2build="${SYSROOT}/include/freetype2" \
|
|
|
|
|
-DFREETYPE_INCLUDE_DIR_freetype2="${SYSROOT}/include/freetype2" \
|
|
|
|
|
-DFREETYPE_LIBRARY="${SYSROOT}/lib/libfreetype.a" \
|
|
|
|
|
-DHarfBuzz_INCLUDE_DIR="${SYSROOT}/include/harfbuzz" \
|
|
|
|
|
-DHarfBuzz_LIBRARY="${SYSROOT}/lib/libharfbuzz.a" \
|
|
|
|
|
-DOCC_INCLUDE_DIR="${SYSROOT}/include/opencascade" \
|
|
|
|
|
-DOCC_LIBRARY_DIR="${SYSROOT}/lib" \
|
|
|
|
|
-DProtobuf_INCLUDE_DIR="${SYSROOT}/include" \
|
|
|
|
|
-DProtobuf_LIBRARY="${SYSROOT}/lib/libprotobuf.a" \
|
|
|
|
|
-DProtobuf_LITE_LIBRARY="${SYSROOT}/lib/libprotobuf-lite.a" \
|
|
|
|
|
-DProtobuf_PROTOC_EXECUTABLE="${SYSROOT}/bin/protoc" \
|
|
|
|
|
-DODBC_CONFIG:STRING="stub-for-wasm" \
|
|
|
|
|
-DODBCLIB:STRING="" \
|
|
|
|
|
-DODBC_CFLAGS:STRING="" \
|
|
|
|
|
-DODBC_LINK_FLAGS:STRING="" \
|
|
|
|
|
-DODBC_LIBRARIES:STRING="" \
|
|
|
|
|
\
|
|
|
|
|
-DHAVE_STRCASECMP=1 \
|
|
|
|
|
-DHAVE_STRNCASECMP=1
|
|
|
|
|
|
|
|
|
|
# Step 7.1: Compile Embind bindings (after CMake so config.h exists)
|
|
|
|
|
# Exposes KiCad objects to JavaScript for future Pyodide integration.
|
|
|
|
|
# When no app-specific source exists, build an empty object so the linker line
|
|
|
|
|
# referencing ${APP_NAME}_embind.o doesn't break.
|
|
|
|
|
if [ -f "${EMBIND_SRC}" ]; then
|
2026-06-11 08:57:23 +02:00
|
|
|
# pcbnew's embind TU transitively includes generated lexer headers
|
|
|
|
|
# (kicad_clipboard.h → pcb_io_kicad_sexpr_parser.h → pcb_lexer.h, emitted into
|
|
|
|
|
# ${KICAD_BUILD}/common by make_lexer custom commands on the pcbcommon target).
|
|
|
|
|
# On a fresh build dir they don't exist until make runs — build pcbcommon first.
|
|
|
|
|
# No wasted work: the app target depends on pcbcommon anyway; incremental no-op.
|
2026-06-14 06:22:40 +02:00
|
|
|
# Guard on EMBIND_APP (not APP_NAME) so footprint_editor — whose embind IS
|
|
|
|
|
# pcbnew's — also pre-builds pcbcommon.
|
|
|
|
|
if [ "${EMBIND_APP}" = "pcbnew" ]; then
|
2026-06-11 08:57:23 +02:00
|
|
|
log_info "Pre-building pcbcommon so generated lexer headers exist for the embind compile..."
|
|
|
|
|
emmake make -j${JOBS} pcbcommon
|
|
|
|
|
fi
|
2026-05-29 06:39:23 +02:00
|
|
|
log_info "Compiling Embind bindings (${APP_NAME})..."
|
|
|
|
|
# Use the same includes and flags that KiCad uses
|
2026-06-02 13:35:37 +02:00
|
|
|
KICAD_INCLUDES="-I${KICAD_BUILD} -I${KICAD_DIR}/include -I${KICAD_DIR}/${KICAD_SUBDIR} -I${KICAD_DIR}/common"
|
2026-06-08 11:39:29 +02:00
|
|
|
# Generated DSN-lexer headers (e.g. pcb_lexer.h, used transitively via kicad_clipboard.h →
|
|
|
|
|
# pcb_io_kicad_sexpr_parser.h) are emitted into the common build subdir by make_lexer.
|
|
|
|
|
KICAD_INCLUDES+=" -I${KICAD_BUILD}/common"
|
2026-05-29 06:39:23 +02:00
|
|
|
KICAD_INCLUDES+=" -I${KICAD_DIR}/libs/core/include -I${KICAD_DIR}/libs/kimath/include -I${KICAD_DIR}/libs/kiplatform/include"
|
|
|
|
|
KICAD_INCLUDES+=" -I${KICAD_DIR}/thirdparty/clipper2/Clipper2Lib/include"
|
|
|
|
|
KICAD_INCLUDES+=" -I${KICAD_DIR}/thirdparty/nlohmann_json"
|
2026-06-03 17:49:11 +02:00
|
|
|
KICAD_INCLUDES+=" -I${KICAD_DIR}/thirdparty/expected/include"
|
|
|
|
|
KICAD_INCLUDES+=" -I${KICAD_DIR}/thirdparty/rtree"
|
|
|
|
|
KICAD_INCLUDES+=" -I${KICAD_DIR}/thirdparty/fmt"
|
2026-05-29 06:39:23 +02:00
|
|
|
KICAD_INCLUDES+=" -I${KICAD_DIR}/thirdparty/dynamic_bitset"
|
|
|
|
|
KICAD_INCLUDES+=" -I${KICAD_DIR}/thirdparty/nanodbc"
|
|
|
|
|
KICAD_INCLUDES+=" -I${KICAD_DIR}/thirdparty/picosha2"
|
|
|
|
|
KICAD_INCLUDES+=" -I${KICAD_DIR}/thirdparty"
|
2026-06-05 11:57:10 +02:00
|
|
|
# libcontext.h lives one level deeper; tool/coroutine.h does #include <libcontext.h>
|
|
|
|
|
KICAD_INCLUDES+=" -I${KICAD_DIR}/thirdparty/libcontext"
|
2026-05-29 06:39:23 +02:00
|
|
|
KICAD_INCLUDES+=" -I${SYSROOT}/include"
|
|
|
|
|
# KiCad requires C++20 for concepts
|
2026-06-29 19:50:18 +02:00
|
|
|
em++ -std=c++20 -c ${EXTRA_FLAGS} ${KICAD_TU_ABI_FLAGS} ${WX_CXXFLAGS} ${KICAD_INCLUDES} "${EMBIND_SRC}" -o "${EMBIND_OBJ}"
|
2026-05-29 06:39:23 +02:00
|
|
|
else
|
|
|
|
|
log_info "No embind source for ${APP_NAME} (expected at ${EMBIND_SRC}); using empty placeholder"
|
|
|
|
|
EMPTY_C="${STUBS_BUILD}/${APP_NAME}_embind_empty.c"
|
|
|
|
|
: > "${EMPTY_C}"
|
|
|
|
|
emcc -c "${EMPTY_C}" -o "${EMBIND_OBJ}"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# Step 8: Build the app target
|
2026-06-01 17:31:03 +02:00
|
|
|
kw_stage kicad-compile
|
2026-05-29 12:01:44 +02:00
|
|
|
log_info "Building ${APP_NAME} (CMake target: ${KICAD_TARGET})..."
|
2026-06-03 17:49:11 +02:00
|
|
|
|
|
|
|
|
# The embind object (step 7.1) is injected via linker flags, NOT tracked as a CMake/
|
|
|
|
|
# make dependency — so when ONLY <app>_embind.cpp changes, make sees no changed source,
|
|
|
|
|
# skips the link, and the new bindings silently vanish from the binary. Force a relink
|
|
|
|
|
# whenever the freshly-compiled embind object is newer than the linked output.
|
|
|
|
|
LINK_OUT_JS="${KICAD_BUILD}/${KICAD_SUBDIR}/${APP_NAME}.js"
|
|
|
|
|
LINK_OUT_WASM="${KICAD_BUILD}/${KICAD_SUBDIR}/${APP_NAME}.wasm"
|
|
|
|
|
if [ -f "${EMBIND_OBJ}" ] && [ -f "${LINK_OUT_JS}" ] && [ "${EMBIND_OBJ}" -nt "${LINK_OUT_JS}" ]; then
|
|
|
|
|
log_info "Embind object newer than ${APP_NAME}.js — forcing relink to pick up new bindings"
|
|
|
|
|
rm -f "${LINK_OUT_JS}" "${LINK_OUT_WASM}"
|
|
|
|
|
fi
|
|
|
|
|
|
2026-05-29 12:01:44 +02:00
|
|
|
emmake make -j${JOBS} "${KICAD_TARGET}"
|
2026-05-29 06:39:23 +02:00
|
|
|
|
|
|
|
|
# Step 8.1: Build bitmap resources (images.tar.gz)
|
2026-06-18 12:21:15 +02:00
|
|
|
# This creates the icon archive that KiCad loads at runtime. The headless
|
|
|
|
|
# converter has no GUI/icons, so skip it.
|
|
|
|
|
if [ "${APP_NAME}" != "sym_convert" ]; then
|
|
|
|
|
kw_stage kicad-bitmaps
|
|
|
|
|
log_info "Building bitmap resources..."
|
|
|
|
|
emmake make bitmap_archive_build
|
|
|
|
|
fi
|
2026-05-29 06:39:23 +02:00
|
|
|
|
|
|
|
|
# Step 9: Create stamp file
|
|
|
|
|
create_stamp "${KICAD_STAMP}"
|
|
|
|
|
log_info "KiCad ${APP_NAME} build complete!"
|
2026-06-02 13:35:37 +02:00
|
|
|
log_info "Output: ${KICAD_BUILD}/${KICAD_SUBDIR}/${APP_NAME}.js"
|