Fix Docker macOS timestamp issues and improve build reproducibility

- Add rsync-based source sync for Docker builds to fix macOS VirtioFS
  timestamp inconsistencies that caused autoconf sanity checks to fail
- Add config.sub wrapper (SHELL/CONFIG_SHELL) to support emscripten/wasm32
  targets without modifying submodule files
- Fix protobuf build to use native gcc/g++ for protoc instead of Emscripten
- Add python PATH fix for macOS (Homebrew's python3 symlink) in wxWidgets build

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Viktor Vaczi 2025-12-27 01:07:44 +01:00
commit dafef9c0a1
9 changed files with 1937 additions and 2 deletions

View file

@ -18,6 +18,7 @@ RUN apt-get update && apt-get install -y \
swig \ swig \
unixodbc-dev \ unixodbc-dev \
ccache \ ccache \
rsync \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
# Configure ccache for Emscripten # Configure ccache for Emscripten

View file

@ -20,6 +20,12 @@ fi
# Start container if not running # Start container if not running
docker compose -f docker/docker-compose.yml up -d docker compose -f docker/docker-compose.yml up -d
# Sync source code to container volume (fixes macOS Docker timestamp issues)
# This ensures timestamps are consistent within the container filesystem
echo "Syncing source code to container..."
docker compose -f docker/docker-compose.yml exec kicad-wasm-builder \
rsync -a --delete --exclude='build-wasm' --exclude='output' /workspace-host/ /workspace/
# Run build command (without asyncify - handled on host due to memory requirements) # Run build command (without asyncify - handled on host due to memory requirements)
docker compose -f docker/docker-compose.yml exec kicad-wasm-builder \ docker compose -f docker/docker-compose.yml exec kicad-wasm-builder \
/workspace/scripts/kicad/build-pcbnew.sh "${ARGS[@]}" /workspace/scripts/kicad/build-pcbnew.sh "${ARGS[@]}"

View file

@ -13,8 +13,11 @@ services:
memory: 32G memory: 32G
volumes: volumes:
# Source code (read-only - all modifications happen in build-wasm volume) # Host source mounted read-only at staging location
- ..:/workspace:ro # (rsync'd to /workspace on container start to fix macOS timestamp issues)
- ..:/workspace-host:ro
# Synced source in Docker volume (consistent timestamps)
- workspace-src:/workspace
# Named volume for build cache (faster than bind mount on macOS) # Named volume for build cache (faster than bind mount on macOS)
- kicad-build-cache:/workspace/build-wasm - kicad-build-cache:/workspace/build-wasm
# Output directory for easy access to final WASM files # Output directory for easy access to final WASM files
@ -26,3 +29,4 @@ services:
volumes: volumes:
kicad-build-cache: kicad-build-cache:
workspace-src:

View file

@ -4,5 +4,17 @@ set -e
# Source Emscripten environment # Source Emscripten environment
source /emsdk/emsdk_env.sh 2>/dev/null source /emsdk/emsdk_env.sh 2>/dev/null
# Sync source from host to workspace volume
# This fixes macOS Docker timestamp issues with bind mounts
# (autoconf sanity checks fail when timestamps appear inconsistent)
if [[ -d /workspace-host ]]; then
echo "Syncing source code to container volume..."
rsync -a --delete \
--exclude='build-wasm' \
--exclude='output' \
/workspace-host/ /workspace/
echo "Sync complete."
fi
# Execute command or start shell # Execute command or start shell
exec "$@" exec "$@"

View file

@ -17,11 +17,25 @@
set -e set -e
# Ensure 'python' command is available (macOS only has python3)
# Homebrew's python libexec has the python -> python3 symlink
if [[ -d "/opt/homebrew/opt/python/libexec/bin" ]]; then
export PATH="/opt/homebrew/opt/python/libexec/bin:$PATH"
elif [[ -d "/usr/local/opt/python/libexec/bin" ]]; then
export PATH="/usr/local/opt/python/libexec/bin:$PATH"
fi
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
BUILD_DIR="$PROJECT_ROOT/build-wasm/wxwidgets-universal" BUILD_DIR="$PROJECT_ROOT/build-wasm/wxwidgets-universal"
WX_SOURCE="$PROJECT_ROOT/wxwidgets" WX_SOURCE="$PROJECT_ROOT/wxwidgets"
# Use our config.sub wrapper for autoconf projects
# CONFIG_SHELL is critical: nested configures (pcre, etc.) do SHELL=${CONFIG_SHELL-/bin/sh}
# Without CONFIG_SHELL, nested configures would reset SHELL to /bin/sh and bypass our wrapper
export SHELL="$SCRIPT_DIR/config/config-sub-wrapper.sh"
export CONFIG_SHELL="$SCRIPT_DIR/config/config-sub-wrapper.sh"
# Use JOBS from env.sh if set, otherwise use all available cores # Use JOBS from env.sh if set, otherwise use all available cores
JOBS="${JOBS:-$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4)}" JOBS="${JOBS:-$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4)}"

View file

@ -11,6 +11,12 @@ export PROJECT_ROOT="$_KICAD_WASM_PROJECT_ROOT"
export SCRIPTS_DIR="$_KICAD_WASM_SCRIPTS_DIR" export SCRIPTS_DIR="$_KICAD_WASM_SCRIPTS_DIR"
export COMMON_DIR="$_KICAD_WASM_COMMON_DIR" export COMMON_DIR="$_KICAD_WASM_COMMON_DIR"
# Use our config.sub wrapper for autoconf projects (emconfigure)
# This intercepts config.sub calls to use our version with emscripten/wasm32 support
# CONFIG_SHELL is critical: nested configures do SHELL=${CONFIG_SHELL-/bin/sh}
export SHELL="$SCRIPTS_DIR/config/config-sub-wrapper.sh"
export CONFIG_SHELL="$SCRIPTS_DIR/config/config-sub-wrapper.sh"
# Build output directories (inside the project) # Build output directories (inside the project)
export BUILD_ROOT="$PROJECT_ROOT/build-wasm" export BUILD_ROOT="$PROJECT_ROOT/build-wasm"
export DEPS_ROOT="$BUILD_ROOT/deps" export DEPS_ROOT="$BUILD_ROOT/deps"

View file

@ -0,0 +1,22 @@
#!/bin/bash
# SHELL wrapper that intercepts config.sub calls and uses our updated version
# This allows building with autoconf projects without modifying their config.sub files
#
# How it works:
# - autoconf's configure runs: $SHELL "${ac_aux_dir}config.sub" $host_alias
# - By exporting SHELL to point to this script, we intercept these calls
# - When $1 ends with "config.sub", we use our version instead
# - All other invocations pass through to real bash
WRAPPER_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
OUR_CONFIG_SUB="$WRAPPER_DIR/config.sub"
# Check if we're being asked to execute a config.sub script
# configure calls: $SHELL "path/to/config.sub" <args>
if [[ "$1" == *config.sub ]]; then
# Use our config.sub instead, passing all remaining arguments
exec "$OUR_CONFIG_SUB" "${@:2}"
fi
# For all other invocations, pass through to real bash
exec /bin/bash "$@"

1867
scripts/config/config.sub vendored Executable file

File diff suppressed because it is too large Load diff

View file

@ -62,8 +62,11 @@ if [ ! -f "${PROTOC_NATIVE}" ]; then
cd "${PROTOBUF_HOST_BUILD}" cd "${PROTOBUF_HOST_BUILD}"
# Build native (not cross-compiled) protoc # Build native (not cross-compiled) protoc
# Explicitly use system compilers to avoid Emscripten (which is in PATH)
cmake "${PROTOBUF_DIR}" \ cmake "${PROTOBUF_DIR}" \
-DCMAKE_BUILD_TYPE=Release \ -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_C_COMPILER=/usr/bin/gcc \
-DCMAKE_CXX_COMPILER=/usr/bin/g++ \
-Dprotobuf_BUILD_TESTS=OFF \ -Dprotobuf_BUILD_TESTS=OFF \
-Dprotobuf_BUILD_EXAMPLES=OFF \ -Dprotobuf_BUILD_EXAMPLES=OFF \
-Dprotobuf_BUILD_SHARED_LIBS=OFF \ -Dprotobuf_BUILD_SHARED_LIBS=OFF \