Fix KiCad WASM build and runtime errors
Build improvements: - Change -O0 to -O1 to fix "local count too large" asyncify error - Add wasm-emscripten-finalize to host (Docker OOMs on large WASM) - Use -gseparate-dwarf for smaller main binary with debug info - Build native protoc for code generation - Add more functions to asyncify removelist Runtime fixes: - Add inject-dyncall-shims.sh to fix "dynCall_* is not defined" in Emscripten 4.x - Update wxwidgets with browserInfo.name fix New stubs and bindings: - Add Embind bindings for JavaScript interop - Add stubs for scripting, API plugin, PCB frame, navlib 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
898e079ef2
commit
9c271996c2
17 changed files with 699 additions and 13 deletions
|
|
@ -39,6 +39,13 @@ ASYNCIFY_REMOVE=$(cat << 'REMOVELIST'
|
|||
COLOR_SETTINGS::COLOR_SETTINGS(wxString const&, bool)
|
||||
BuildBitmapInfo(std::__2::unordered_map<BITMAPS, std::__2::vector<BITMAP_INFO, std::__2::allocator<BITMAP_INFO>>, std::__2::hash<BITMAPS>, std::__2::equal_to<BITMAPS>, std::__2::allocator<std::__2::pair<BITMAPS const, std::__2::vector<BITMAP_INFO, std::__2::allocator<BITMAP_INFO>>>>>&)
|
||||
match
|
||||
DIALOG_PAD_PROPERTIES_BASE::DIALOG_PAD_PROPERTIES_BASE(wxWindow*, int, wxString const&, wxPoint const&, wxSize const&, long)
|
||||
buildKicadAboutBanner(EDA_BASE_FRAME*, ABOUT_APP_INFO&)
|
||||
IGESToBRep_CurveAndSurface::TransferGeometry(opencascade::handle<IGESData_IGESEntity> const&, Message_ProgressRange const&)
|
||||
StepAP214_Protocol::StepAP214_Protocol()
|
||||
BRepCheck_ParallelAnalyzer::operator()(int) const
|
||||
ShapeFix_Wire::FixGap3d(int, bool)
|
||||
ShapeFix_Wire::FixGap2d(int, bool)
|
||||
REMOVELIST
|
||||
)
|
||||
|
||||
|
|
|
|||
46
scripts/common/apply-finalize.sh
Executable file
46
scripts/common/apply-finalize.sh
Executable file
|
|
@ -0,0 +1,46 @@
|
|||
#!/bin/bash
|
||||
# Apply wasm-emscripten-finalize transformation on host
|
||||
# Uses the same Binaryen v121 as wasm-opt to ensure version consistency
|
||||
#
|
||||
# Usage: ./scripts/common/apply-finalize.sh <input.wasm> <output.wasm>
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
||||
|
||||
# Get wasm-emscripten-finalize from same Binaryen install as wasm-opt
|
||||
BINARYEN_DIR="${PROJECT_ROOT}/tools/binaryen-121"
|
||||
FINALIZE="${BINARYEN_DIR}/bin/wasm-emscripten-finalize"
|
||||
|
||||
# Ensure Binaryen is downloaded
|
||||
if [ ! -x "${FINALIZE}" ]; then
|
||||
echo "Downloading Binaryen v121..."
|
||||
"${SCRIPT_DIR}/get-wasm-opt.sh" > /dev/null
|
||||
fi
|
||||
|
||||
INPUT_WASM="${1:-output/pcbnew.wasm}"
|
||||
OUTPUT_WASM="${2:-${INPUT_WASM}}"
|
||||
|
||||
if [ ! -f "${INPUT_WASM}" ]; then
|
||||
echo "ERROR: Input file not found: ${INPUT_WASM}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Applying wasm-emscripten-finalize..."
|
||||
echo " Input: ${INPUT_WASM}"
|
||||
echo " Output: ${OUTPUT_WASM}"
|
||||
echo " Tool: ${FINALIZE}"
|
||||
|
||||
# Run finalize with the same flags Emscripten would use
|
||||
# NOTE: --dwarf removed because debug info is in separate .debug.wasm file
|
||||
"${FINALIZE}" \
|
||||
-g \
|
||||
--bigint \
|
||||
--no-legalize-javascript-ffi \
|
||||
--detect-features \
|
||||
"${INPUT_WASM}" \
|
||||
-o "${OUTPUT_WASM}"
|
||||
|
||||
echo "Finalize complete: ${OUTPUT_WASM}"
|
||||
ls -lh "${OUTPUT_WASM}"
|
||||
|
|
@ -40,7 +40,7 @@ DEBUG_BUILD="${DEBUG_BUILD:-1}"
|
|||
|
||||
if [ "$DEBUG_BUILD" = "1" ]; then
|
||||
export BUILD_TYPE="Debug"
|
||||
export DEBUG_CFLAGS="-g -O0"
|
||||
export DEBUG_CFLAGS="-g -O1"
|
||||
export DEBUG_LDFLAGS="-g -gsource-map"
|
||||
else
|
||||
export BUILD_TYPE="Release"
|
||||
|
|
|
|||
114
scripts/common/inject-dyncall-shims.sh
Executable file
114
scripts/common/inject-dyncall-shims.sh
Executable file
|
|
@ -0,0 +1,114 @@
|
|||
#!/bin/bash
|
||||
# Inject dynCall_* shims into Emscripten-generated JS
|
||||
#
|
||||
# Emscripten 4.x no longer generates signature-specific dynCall_* functions,
|
||||
# but the invoke_* wrappers (for C++ exception handling) still call them.
|
||||
# This script auto-generates shims using getWasmTableEntry() which IS defined.
|
||||
#
|
||||
# Usage: inject-dyncall-shims.sh <pcbnew.js>
|
||||
|
||||
set -e
|
||||
|
||||
JS_FILE="$1"
|
||||
|
||||
if [ -z "$JS_FILE" ] || [ ! -f "$JS_FILE" ]; then
|
||||
echo "Error: JS file not found: $JS_FILE"
|
||||
echo "Usage: $0 <path/to/pcbnew.js>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Extracting dynCall signatures from $JS_FILE..."
|
||||
|
||||
# Extract all unique dynCall_* signatures from the file
|
||||
# Matches patterns like: dynCall_i, dynCall_ii, dynCall_viijj, etc.
|
||||
SIGNATURES=$(grep -oE 'dynCall_[a-zA-Z0-9]+' "$JS_FILE" | sort -u | sed 's/dynCall_//')
|
||||
|
||||
if [ -z "$SIGNATURES" ]; then
|
||||
echo "No dynCall signatures found - nothing to inject"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
SIG_COUNT=$(echo "$SIGNATURES" | wc -l | tr -d ' ')
|
||||
echo "Found $SIG_COUNT unique signatures"
|
||||
|
||||
# Generate shim code
|
||||
SHIM_FILE=$(mktemp)
|
||||
cat > "$SHIM_FILE" << 'HEADER'
|
||||
|
||||
// === dynCall shims for Emscripten exception handling ===
|
||||
// Auto-generated: maps dynCall_SIG() calls to getWasmTableEntry()
|
||||
// This fixes "dynCall_* is not defined" errors in Emscripten 4.x
|
||||
HEADER
|
||||
|
||||
for sig in $SIGNATURES; do
|
||||
# Count args: signature length - 1 (first char is return type)
|
||||
argcount=$((${#sig} - 1))
|
||||
|
||||
# Generate argument list: index, a0, a1, a2, ...
|
||||
args="index"
|
||||
call_args=""
|
||||
for ((i=0; i<argcount; i++)); do
|
||||
args="$args, a$i"
|
||||
if [ $i -gt 0 ]; then
|
||||
call_args="$call_args, "
|
||||
fi
|
||||
call_args="${call_args}a$i"
|
||||
done
|
||||
|
||||
echo "var dynCall_$sig = ($args) => getWasmTableEntry(index)($call_args);" >> "$SHIM_FILE"
|
||||
done
|
||||
|
||||
echo "" >> "$SHIM_FILE"
|
||||
echo "// === End dynCall shims ===" >> "$SHIM_FILE"
|
||||
|
||||
# Find the insertion point: after getWasmTableEntry definition
|
||||
# The pattern is:
|
||||
# var getWasmTableEntry = funcPtr => {
|
||||
# ...
|
||||
# };
|
||||
# We insert after the closing `};`
|
||||
|
||||
# Find line number of getWasmTableEntry definition
|
||||
GWTL_LINE=$(grep -n '^var getWasmTableEntry = funcPtr => {' "$JS_FILE" | head -1 | cut -d: -f1)
|
||||
|
||||
if [ -z "$GWTL_LINE" ]; then
|
||||
echo "Warning: Could not find getWasmTableEntry definition"
|
||||
echo "Trying alternate pattern..."
|
||||
GWTL_LINE=$(grep -n 'var getWasmTableEntry' "$JS_FILE" | head -1 | cut -d: -f1)
|
||||
fi
|
||||
|
||||
if [ -z "$GWTL_LINE" ]; then
|
||||
echo "Error: Could not find getWasmTableEntry in $JS_FILE"
|
||||
echo "The shims need to be inserted after getWasmTableEntry is defined"
|
||||
rm "$SHIM_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Find the closing `};` after getWasmTableEntry (within next 10 lines)
|
||||
INSERT_LINE=""
|
||||
for ((i=GWTL_LINE; i<=GWTL_LINE+10; i++)); do
|
||||
LINE_CONTENT=$(sed -n "${i}p" "$JS_FILE")
|
||||
if [[ "$LINE_CONTENT" == "};" ]]; then
|
||||
INSERT_LINE=$i
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -z "$INSERT_LINE" ]; then
|
||||
echo "Warning: Could not find closing }; for getWasmTableEntry"
|
||||
echo "Inserting after line $GWTL_LINE"
|
||||
INSERT_LINE=$GWTL_LINE
|
||||
fi
|
||||
|
||||
echo "Injecting shims after line $INSERT_LINE..."
|
||||
|
||||
# Create output file with shims inserted
|
||||
head -n "$INSERT_LINE" "$JS_FILE" > "${JS_FILE}.tmp"
|
||||
cat "$SHIM_FILE" >> "${JS_FILE}.tmp"
|
||||
tail -n +$((INSERT_LINE + 1)) "$JS_FILE" >> "${JS_FILE}.tmp"
|
||||
|
||||
# Replace original file
|
||||
mv "${JS_FILE}.tmp" "$JS_FILE"
|
||||
rm "$SHIM_FILE"
|
||||
|
||||
echo "Successfully injected $SIG_COUNT dynCall shims into $JS_FILE"
|
||||
Loading…
Reference in a new issue