fix(wasm): Fix Emscripten empty callback functions for pthreads builds
Emscripten with pthreads generates empty arrow functions `{}` for callback
paths it assumes won't be used. However, when registering HTML5 events from
the main browser thread, targetThread is 0 and the direct call path IS taken.
This fix post-processes the generated JS to replace empty callbacks with
actual dynCall invocations for:
- HTML5 event callbacks (dynCall_iiii) - 7 instances
- pthread entry points (dynCall_ii) - 1 instance
- Signal handlers (dynCall_vi) - 1 instance
- Async timers (dynCall_vi) - 1 instance
Also improves build logging to show completion status and exit code.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
c04d5f9845
commit
014816b7a5
2 changed files with 74 additions and 2 deletions
|
|
@ -112,3 +112,65 @@ mv "${JS_FILE}.tmp" "$JS_FILE"
|
|||
rm "$SHIM_FILE"
|
||||
|
||||
echo "Successfully injected $SIG_COUNT dynCall shims into $JS_FILE"
|
||||
|
||||
# Fix empty callback arrow functions generated by Emscripten with pthreads
|
||||
# When pthreads is enabled, Emscripten generates empty {} for some direct-call paths
|
||||
# because it assumes they won't be used. But they ARE used in certain cases.
|
||||
# The dynCall_* functions exist (generated above), we just need to call them.
|
||||
echo "Fixing empty callback arrow functions..."
|
||||
|
||||
TOTAL_FIXED=0
|
||||
|
||||
# Fix 1: HTML5 event callbacks (3 args) - signature iiii
|
||||
# Pattern: ((a1, a2, a3) => {})(eventTypeId, ...
|
||||
# Function pointer is 'callbackfunc' in these contexts
|
||||
COUNT_BEFORE=$(grep -c '((a1, a2, a3) => {})(eventTypeId,' "$JS_FILE" || true)
|
||||
if [ "$COUNT_BEFORE" -gt 0 ]; then
|
||||
sed -i '' 's/((a1, a2, a3) => {})(eventTypeId,/((a1, a2, a3) => dynCall_iiii(callbackfunc, a1, a2, a3))(eventTypeId,/g' "$JS_FILE"
|
||||
COUNT_AFTER=$(grep -c '((a1, a2, a3) => {})(eventTypeId,' "$JS_FILE" || true)
|
||||
FIXED=$((COUNT_BEFORE - COUNT_AFTER))
|
||||
echo " Fixed $FIXED HTML5 event callback(s) (dynCall_iiii)"
|
||||
TOTAL_FIXED=$((TOTAL_FIXED + FIXED))
|
||||
fi
|
||||
|
||||
# Fix 2: invokeEntryPoint pthread entry (1 arg) - signature ii (returns pointer)
|
||||
# Pattern in invokeEntryPoint: var result = (a1 => {})(arg);
|
||||
# Function pointer is 'ptr'
|
||||
COUNT_BEFORE=$(grep -c 'var result = (a1 => {})(arg);' "$JS_FILE" || true)
|
||||
if [ "$COUNT_BEFORE" -gt 0 ]; then
|
||||
sed -i '' 's/var result = (a1 => {})(arg);/var result = dynCall_ii(ptr, arg);/g' "$JS_FILE"
|
||||
COUNT_AFTER=$(grep -c 'var result = (a1 => {})(arg);' "$JS_FILE" || true)
|
||||
FIXED=$((COUNT_BEFORE - COUNT_AFTER))
|
||||
echo " Fixed $FIXED pthread entry callback(s) (dynCall_ii)"
|
||||
TOTAL_FIXED=$((TOTAL_FIXED + FIXED))
|
||||
fi
|
||||
|
||||
# Fix 3: ___call_sighandler (1 arg) - signature vi (void return)
|
||||
# Pattern: return (a1 => {})(sig);
|
||||
# Function pointer is 'fp'
|
||||
COUNT_BEFORE=$(grep -c 'return (a1 => {})(sig);' "$JS_FILE" || true)
|
||||
if [ "$COUNT_BEFORE" -gt 0 ]; then
|
||||
sed -i '' 's/return (a1 => {})(sig);/return dynCall_vi(fp, sig);/g' "$JS_FILE"
|
||||
COUNT_AFTER=$(grep -c 'return (a1 => {})(sig);' "$JS_FILE" || true)
|
||||
FIXED=$((COUNT_BEFORE - COUNT_AFTER))
|
||||
echo " Fixed $FIXED signal handler callback(s) (dynCall_vi)"
|
||||
TOTAL_FIXED=$((TOTAL_FIXED + FIXED))
|
||||
fi
|
||||
|
||||
# Fix 4: _emscripten_async_call timer (1 arg) - signature vi (void return)
|
||||
# Pattern: var wrapper = () => (a1 => {})(arg);
|
||||
# Function pointer is 'func'
|
||||
COUNT_BEFORE=$(grep -c 'var wrapper = () => (a1 => {})(arg);' "$JS_FILE" || true)
|
||||
if [ "$COUNT_BEFORE" -gt 0 ]; then
|
||||
sed -i '' 's/var wrapper = () => (a1 => {})(arg);/var wrapper = () => dynCall_vi(func, arg);/g' "$JS_FILE"
|
||||
COUNT_AFTER=$(grep -c 'var wrapper = () => (a1 => {})(arg);' "$JS_FILE" || true)
|
||||
FIXED=$((COUNT_BEFORE - COUNT_AFTER))
|
||||
echo " Fixed $FIXED async timer callback(s) (dynCall_vi)"
|
||||
TOTAL_FIXED=$((TOTAL_FIXED + FIXED))
|
||||
fi
|
||||
|
||||
if [ "$TOTAL_FIXED" -gt 0 ]; then
|
||||
echo "Total: Fixed $TOTAL_FIXED empty callback(s)"
|
||||
else
|
||||
echo "No empty callbacks found - nothing to fix"
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -41,8 +41,18 @@ mkdir -p "${_LOGS_DIR}"
|
|||
# Show log path before re-exec
|
||||
echo "Logging to: ${_LOG_FILE}"
|
||||
|
||||
# Re-exec the calling script with output redirected
|
||||
# Run the calling script with output redirected
|
||||
# This is equivalent to: ./script.sh > logfile 2>&1
|
||||
# and reliably captures ALL output including docker compose TTY messages
|
||||
export KICAD_LOG_NESTED=1
|
||||
exec "${_CALLER_SCRIPT}" "$@" > "${_LOG_FILE}" 2>&1
|
||||
"${_CALLER_SCRIPT}" "$@" > "${_LOG_FILE}" 2>&1
|
||||
_EXIT_CODE=$?
|
||||
|
||||
# Print completion message (this runs AFTER the script finishes)
|
||||
if [[ ${_EXIT_CODE} -eq 0 ]]; then
|
||||
echo "Done. Log: ${_LOG_FILE}"
|
||||
else
|
||||
echo "Failed (exit ${_EXIT_CODE}). Log: ${_LOG_FILE}"
|
||||
fi
|
||||
|
||||
exit ${_EXIT_CODE}
|
||||
|
|
|
|||
Loading…
Reference in a new issue