Fix Asyncify and improve build process
Build system improvements: - Add wasm-opt stub for Docker build to bypass asyncify in container - Add apply-asyncify.sh script for host-side asyncify transformation - Update build-pcbnew.sh to install wasm-opt stub and add EXPORTED_RUNTIME_METHODS - Add --with-zlib=sys to wxWidgets configure for proper zlib linking - Improve update-baseline-screenshots.sh to only copy new/significantly changed files wxWidgets submodule update: - Fix EM_JS to EM_ASYNC_JS for proper Asyncify registration Test updates: - Add new baseline screenshots for bitmapbuttons, dnd, gridrenderers, printpreview, specialized tests - Add kicad-pcbnew initial screenshot - Fix wxgrid-controls.png and wxgrid-dedicated-page.png (were showing errors) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
|
@ -11,11 +11,6 @@ set -e
|
|||
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
# Get wasm-opt (downloads Binaryen v121 if not cached)
|
||||
echo "Checking wasm-opt..."
|
||||
WASM_OPT=$(./scripts/common/get-wasm-opt.sh)
|
||||
echo "Using: ${WASM_OPT}"
|
||||
|
||||
# Start container if not running
|
||||
docker compose -f docker/docker-compose.yml up -d
|
||||
|
||||
|
|
@ -29,21 +24,8 @@ docker compose -f docker/docker-compose.yml exec kicad-wasm-builder \
|
|||
bash -c "mkdir -p /workspace/output && cp /workspace/build-wasm/kicad-pcbnew/pcbnew/pcbnew.{js,wasm,wasm.map,worker.js} /workspace/output/ 2>/dev/null || cp /workspace/build-wasm/kicad-pcbnew/pcbnew/pcbnew.{js,wasm} /workspace/output/"
|
||||
|
||||
# Apply asyncify transformation on host
|
||||
# This is done on the host because wasm-opt --asyncify needs 50GB+ RAM for KiCad,
|
||||
# which exceeds typical Docker memory limits
|
||||
echo ""
|
||||
echo "Applying asyncify transformation on host..."
|
||||
echo "This may take several minutes and use significant RAM..."
|
||||
|
||||
# Asyncify import patterns (functions that trigger async suspension)
|
||||
# - env.invoke_* : Exception handling trampolines
|
||||
# - env.__asyncjs__* : EM_ASYNC_JS functions
|
||||
ASYNCIFY_IMPORTS="env.invoke_*,env.__asyncjs__*"
|
||||
|
||||
"${WASM_OPT}" --asyncify \
|
||||
--pass-arg=asyncify-imports@${ASYNCIFY_IMPORTS} \
|
||||
--pass-arg=asyncify-propagate-addlist \
|
||||
output/pcbnew.wasm -o output/pcbnew.wasm
|
||||
# This is done on the host because wasm-opt --asyncify needs significant RAM
|
||||
./scripts/common/apply-asyncify.sh output/pcbnew.wasm output/pcbnew.wasm
|
||||
|
||||
echo ""
|
||||
echo "Build complete. Output files in ./output/"
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ emconfigure "$WX_SOURCE/configure" \
|
|||
--disable-xlocale \
|
||||
--with-cxx=17 \
|
||||
--enable-utf8 \
|
||||
--with-zlib=sys \
|
||||
${WX_CONFIGURE_DEBUG}
|
||||
|
||||
# Build PCRE first to avoid race condition with parallel builds
|
||||
|
|
|
|||
60
scripts/common/apply-asyncify.sh
Executable file
|
|
@ -0,0 +1,60 @@
|
|||
#!/bin/bash
|
||||
# Apply asyncify transformation to KiCad WASM
|
||||
#
|
||||
# Usage: ./scripts/common/apply-asyncify.sh <input.wasm> <output.wasm>
|
||||
#
|
||||
# This script is called by docker/build.sh but can also be run standalone
|
||||
# for debugging asyncify issues.
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
||||
|
||||
# Get wasm-opt path
|
||||
WASM_OPT=$("${SCRIPT_DIR}/get-wasm-opt.sh")
|
||||
|
||||
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 asyncify transformation..."
|
||||
echo " Input: ${INPUT_WASM}"
|
||||
echo " Output: ${OUTPUT_WASM}"
|
||||
echo " Tool: ${WASM_OPT}"
|
||||
|
||||
# Asyncify import patterns (functions that trigger async suspension)
|
||||
# - env.invoke_* : Exception handling trampolines
|
||||
# - env.__asyncjs__* : EM_ASYNC_JS functions (like startModal())
|
||||
ASYNCIFY_IMPORTS="env.invoke_*,env.__asyncjs__*"
|
||||
|
||||
# Functions to exclude from asyncify instrumentation
|
||||
# These are large functions that inflate beyond V8's 7.65MB function limit
|
||||
# The names must match exactly as they appear in the WASM (C++ mangled names)
|
||||
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
|
||||
REMOVELIST
|
||||
)
|
||||
|
||||
# Convert newlines to commas for the removelist
|
||||
ASYNCIFY_REMOVE_ARG=$(echo "${ASYNCIFY_REMOVE}" | tr '\n' ',' | sed 's/,$//')
|
||||
|
||||
echo ""
|
||||
echo "Running wasm-opt --asyncify..."
|
||||
echo "This may take several minutes and use significant RAM..."
|
||||
|
||||
"${WASM_OPT}" --asyncify \
|
||||
"--pass-arg=asyncify-imports@${ASYNCIFY_IMPORTS}" \
|
||||
"--pass-arg=asyncify-removelist@${ASYNCIFY_REMOVE_ARG}" \
|
||||
--pass-arg=asyncify-propagate-addlist \
|
||||
"${INPUT_WASM}" -o "${OUTPUT_WASM}"
|
||||
|
||||
echo ""
|
||||
echo "Asyncify complete: ${OUTPUT_WASM}"
|
||||
ls -lh "${OUTPUT_WASM}"
|
||||
|
|
@ -157,6 +157,19 @@ emar rcs "${STUBS_BUILD}/libcurl_stub.a" "${STUBS_BUILD}/curl_stub.o"
|
|||
|
||||
log_info "Stub libraries built"
|
||||
|
||||
# Step 6.2: Replace Emscripten's wasm-opt with stub to bypass asyncify transformation
|
||||
# This allows Emscripten to generate JS with Asyncify runtime, but we run the real
|
||||
# wasm-opt --asyncify on the host where more RAM is available (needs 50GB+ for KiCad)
|
||||
EMSDK_WASM_OPT="/emsdk/upstream/bin/wasm-opt"
|
||||
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)"
|
||||
|
||||
# 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"
|
||||
|
|
@ -184,7 +197,7 @@ emcmake cmake "${KICAD_DIR}" \
|
|||
-DCMAKE_POLICY_VERSION_MINIMUM=3.5 \
|
||||
-DCMAKE_CXX_FLAGS="${EXTRA_FLAGS} -pthread -sUSE_ZLIB=1 -DKICAD_USE_PLATFORM_WASM=1 -I${SYSROOT}/include" \
|
||||
-DCMAKE_C_FLAGS="${EXTRA_FLAGS} -pthread -sUSE_ZLIB=1 -I${SYSROOT}/include" \
|
||||
-DCMAKE_EXE_LINKER_FLAGS="${LINKER_DEBUG_FLAGS} -pthread -sUSE_ZLIB=1 -sUSE_PTHREADS=1 -sPTHREAD_POOL_SIZE=4 -sALLOW_MEMORY_GROWTH=1 -sINITIAL_MEMORY=256MB -sMAXIMUM_MEMORY=4GB -L${SYSROOT}/lib ${STUBS_BUILD}/libgit2_stub.a ${STUBS_BUILD}/libcurl_stub.a" \
|
||||
-DCMAKE_EXE_LINKER_FLAGS="${LINKER_DEBUG_FLAGS} -pthread -sUSE_ZLIB=1 -sASYNCIFY=1 -sASYNCIFY_STACK_SIZE=65536 -sUSE_PTHREADS=1 -sPTHREAD_POOL_SIZE=4 -sALLOW_MEMORY_GROWTH=1 -sINITIAL_MEMORY=256MB -sMAXIMUM_MEMORY=4GB -sEXPORTED_RUNTIME_METHODS=['ccall','cwrap','UTF8ToString','stringToUTF8','lengthBytesUTF8'] -L${SYSROOT}/lib ${STUBS_BUILD}/libgit2_stub.a ${STUBS_BUILD}/libcurl_stub.a" \
|
||||
-DCMAKE_PREFIX_PATH="${SYSROOT};${WX_BUILD}" \
|
||||
-DwxWidgets_CONFIG_EXECUTABLE="${WX_BUILD}/wx-config" \
|
||||
\
|
||||
|
|
|
|||
|
|
@ -1,11 +1,28 @@
|
|||
#!/bin/bash
|
||||
# Update baseline screenshots from test results
|
||||
# Only copies:
|
||||
# - NEW screenshots (not in baseline)
|
||||
# - Screenshots with SIGNIFICANT differences (>5% size change) when --all flag used
|
||||
#
|
||||
# Usage:
|
||||
# ./update-baseline-screenshots.sh # Only copy NEW screenshots
|
||||
# ./update-baseline-screenshots.sh --all # Copy new + significantly different
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
TESTS_DIR="$SCRIPT_DIR/../tests"
|
||||
SOURCE_DIR="$TESTS_DIR/test-results"
|
||||
DEST_DIR="$TESTS_DIR/baseline-screenshots"
|
||||
|
||||
COPY_ALL=0
|
||||
THRESHOLD=5 # Percent threshold for "significant" difference
|
||||
|
||||
if [ "$1" = "--all" ]; then
|
||||
COPY_ALL=1
|
||||
echo "Mode: Copy NEW + SIGNIFICANTLY DIFFERENT screenshots"
|
||||
else
|
||||
echo "Mode: Copy NEW screenshots only (use --all to include significant changes)"
|
||||
fi
|
||||
|
||||
if [ ! -d "$SOURCE_DIR" ]; then
|
||||
echo "Error: test-results directory not found at $SOURCE_DIR"
|
||||
echo "Run 'npm test' first to generate screenshots"
|
||||
|
|
@ -14,15 +31,45 @@ fi
|
|||
|
||||
mkdir -p "$DEST_DIR"
|
||||
|
||||
count=$(ls -1 "$SOURCE_DIR"/*.png 2>/dev/null | wc -l)
|
||||
if [ "$count" -eq 0 ]; then
|
||||
echo "No screenshots found in $SOURCE_DIR"
|
||||
exit 1
|
||||
new_count=0
|
||||
updated_count=0
|
||||
|
||||
for src_file in "$SOURCE_DIR"/*.png; do
|
||||
[ -f "$src_file" ] || continue
|
||||
|
||||
filename=$(basename "$src_file")
|
||||
dest_file="$DEST_DIR/$filename"
|
||||
|
||||
if [ ! -f "$dest_file" ]; then
|
||||
# NEW: Screenshot doesn't exist in baseline
|
||||
echo "NEW: $filename"
|
||||
cp "$src_file" "$dest_file"
|
||||
((new_count++))
|
||||
elif [ $COPY_ALL -eq 1 ]; then
|
||||
# Check if significantly different
|
||||
src_size=$(stat -f%z "$src_file" 2>/dev/null || stat -c%s "$src_file")
|
||||
dest_size=$(stat -f%z "$dest_file" 2>/dev/null || stat -c%s "$dest_file")
|
||||
|
||||
if [ "$dest_size" -eq 0 ]; then
|
||||
diff_pct=100
|
||||
else
|
||||
diff=$((src_size - dest_size))
|
||||
diff=${diff#-} # Absolute value
|
||||
diff_pct=$((diff * 100 / dest_size))
|
||||
fi
|
||||
|
||||
if [ "$diff_pct" -ge "$THRESHOLD" ]; then
|
||||
echo "UPDATED ($diff_pct% diff): $filename"
|
||||
cp "$src_file" "$dest_file"
|
||||
((updated_count++))
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "=== Summary ==="
|
||||
echo "New screenshots added: $new_count"
|
||||
if [ $COPY_ALL -eq 1 ]; then
|
||||
echo "Significantly changed: $updated_count"
|
||||
fi
|
||||
|
||||
echo "Copying $count screenshots to baseline..."
|
||||
cp "$SOURCE_DIR"/*.png "$DEST_DIR/"
|
||||
|
||||
echo "Updated baseline screenshots:"
|
||||
ls -1 "$DEST_DIR"/*.png | wc -l
|
||||
echo "screenshots in $DEST_DIR"
|
||||
echo "Total in baseline: $(ls -1 "$DEST_DIR"/*.png 2>/dev/null | wc -l | tr -d ' ')"
|
||||
|
|
|
|||
BIN
tests/baseline-screenshots/bitmapbuttons-01-loaded.png
Normal file
|
After Width: | Height: | Size: 45 KiB |
BIN
tests/baseline-screenshots/bitmapbuttons-02-toolbar-click.png
Normal file
|
After Width: | Height: | Size: 45 KiB |
BIN
tests/baseline-screenshots/bitmapbuttons-03-toggle.png
Normal file
|
After Width: | Height: | Size: 45 KiB |
BIN
tests/baseline-screenshots/bitmapbuttons-04-multi-toggle.png
Normal file
|
After Width: | Height: | Size: 45 KiB |
BIN
tests/baseline-screenshots/bitmapbuttons-05-enable-toggle.png
Normal file
|
After Width: | Height: | Size: 45 KiB |
BIN
tests/baseline-screenshots/bitmapbuttons-06-shapes.png
Normal file
|
After Width: | Height: | Size: 45 KiB |
BIN
tests/baseline-screenshots/bitmapbuttons-07-artprovider.png
Normal file
|
After Width: | Height: | Size: 45 KiB |
BIN
tests/baseline-screenshots/dnd-01-loaded.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
tests/baseline-screenshots/dnd-02-handlers.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
tests/baseline-screenshots/dnd-03-dragenter.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
tests/baseline-screenshots/dnd-04-dragleave.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
tests/baseline-screenshots/dnd-05-drop.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
tests/baseline-screenshots/dnd-06-file-written.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
tests/baseline-screenshots/dnd-07-event-fired.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
tests/baseline-screenshots/dnd-08-multiple-files.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
tests/baseline-screenshots/dnd-09-with-file.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
tests/baseline-screenshots/gridrenderers-01-loaded.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
tests/baseline-screenshots/gridrenderers-02-color-cells.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
tests/baseline-screenshots/gridrenderers-03-icon-text.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
tests/baseline-screenshots/gridrenderers-04-striped.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
tests/baseline-screenshots/gridrenderers-05-checkbox-toggle.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
tests/baseline-screenshots/kicad-pcbnew-01-initial.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
tests/baseline-screenshots/printpreview-01-loaded.png
Normal file
|
After Width: | Height: | Size: 43 KiB |
BIN
tests/baseline-screenshots/printpreview-02-preview-area.png
Normal file
|
After Width: | Height: | Size: 43 KiB |
BIN
tests/baseline-screenshots/printpreview-03-preview-frame.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
tests/baseline-screenshots/printpreview-04-page-setup.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
tests/baseline-screenshots/printpreview-05-settings.png
Normal file
|
After Width: | Height: | Size: 43 KiB |
BIN
tests/baseline-screenshots/specialized-01-loaded.png
Normal file
|
After Width: | Height: | Size: 54 KiB |
BIN
tests/baseline-screenshots/specialized-02-treebook-initial.png
Normal file
|
After Width: | Height: | Size: 54 KiB |
BIN
tests/baseline-screenshots/specialized-03-treebook-subpage.png
Normal file
|
After Width: | Height: | Size: 54 KiB |
BIN
tests/baseline-screenshots/specialized-04-treebook-expand.png
Normal file
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 54 KiB |
BIN
tests/baseline-screenshots/specialized-06-bitmapcombo-select.png
Normal file
|
After Width: | Height: | Size: 54 KiB |
BIN
tests/baseline-screenshots/specialized-07-rearrange-list.png
Normal file
|
After Width: | Height: | Size: 54 KiB |
BIN
tests/baseline-screenshots/specialized-08-get-order.png
Normal file
|
After Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 36 KiB |
32
wasm/stubs/wasm-opt-stub.sh
Executable file
|
|
@ -0,0 +1,32 @@
|
|||
#!/bin/bash
|
||||
# Stub wasm-opt that does nothing
|
||||
# This allows Emscripten to generate Asyncify JS runtime without running the actual transformation
|
||||
# The real wasm-opt --asyncify is run on the host where more RAM is available
|
||||
|
||||
# Handle --version query from Emscripten
|
||||
if [[ "$1" == "--version" ]]; then
|
||||
echo "wasm-opt version 121 (version_121)"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Find the output file argument (-o)
|
||||
OUTPUT=""
|
||||
INPUT=""
|
||||
PREV_ARG=""
|
||||
|
||||
for arg in "$@"; do
|
||||
if [ "$PREV_ARG" = "-o" ]; then
|
||||
OUTPUT="$arg"
|
||||
elif [[ "$arg" != -* ]] && [ -f "$arg" ]; then
|
||||
INPUT="$arg"
|
||||
fi
|
||||
PREV_ARG="$arg"
|
||||
done
|
||||
|
||||
# If we have both input and output, copy input to output
|
||||
if [ -n "$INPUT" ] && [ -n "$OUTPUT" ] && [ "$INPUT" != "$OUTPUT" ]; then
|
||||
cp "$INPUT" "$OUTPUT"
|
||||
fi
|
||||
|
||||
# Exit successfully so Emscripten thinks wasm-opt ran
|
||||
exit 0
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 40bf50fe4ee6938894464e6039acacb38d55a227
|
||||
Subproject commit 08794a9f579d5fcdc08085e18f25f108446f46f0
|
||||