diff --git a/docker/build.sh b/docker/build.sh index d78f4f1..ea65a2e 100755 --- a/docker/build.sh +++ b/docker/build.sh @@ -14,6 +14,6 @@ docker compose -f docker/docker-compose.yml exec kicad-wasm-builder \ # Copy output to host-accessible directory echo "Copying build output to ./output/..." docker compose -f docker/docker-compose.yml exec kicad-wasm-builder \ - bash -c "mkdir -p /workspace/output && cp -r /workspace/build-wasm/kicad-pcbnew/bin/* /workspace/output/ 2>/dev/null || true" + 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/" echo "Build complete. Output files in ./output/" diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 6e4f34b..4ee37f3 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -13,8 +13,8 @@ services: memory: 32G volumes: - # Source code (read-write for git operations) - - ..:/workspace:cached + # Source code (read-only - all modifications happen in build-wasm volume) + - ..:/workspace:ro # Named volume for build cache (faster than bind mount on macOS) - kicad-build-cache:/workspace/build-wasm # Output directory for easy access to final WASM files diff --git a/scripts/build-wxuniversal-wasm.sh b/scripts/build-wxuniversal-wasm.sh index 8e702ec..8a9629b 100755 --- a/scripts/build-wxuniversal-wasm.sh +++ b/scripts/build-wxuniversal-wasm.sh @@ -59,7 +59,7 @@ cd "$BUILD_DIR" # --enable-universal Use wxUniversal (draws widgets directly) # --disable-shared Build static libraries # --with-opengl Enable OpenGL/WebGL support -# --disable-exceptions Emscripten doesn't support C++ exceptions well +# --enable-exceptions Enable C++ exceptions (needed for KiCad debug builds) # --disable-richtext Not needed for KiCad, simplifies build # --without-libtiff Avoid external dependencies # --disable-xlocale Browser environment handles locale @@ -83,8 +83,8 @@ else echo "Building wxWidgets in RELEASE mode" fi -export CFLAGS="-DZ_HAVE_UNISTD_H=1 ${WX_DEBUG_FLAGS}" -export CXXFLAGS="-DZ_HAVE_UNISTD_H=1 -I$PCRE2_INCLUDE ${WX_DEBUG_FLAGS}" +export CFLAGS="-DZ_HAVE_UNISTD_H=1 ${WX_DEBUG_FLAGS} -fexceptions -pthread -matomics -mbulk-memory" +export CXXFLAGS="-DZ_HAVE_UNISTD_H=1 -I$PCRE2_INCLUDE ${WX_DEBUG_FLAGS} -fexceptions -pthread -matomics -mbulk-memory" emconfigure "$WX_SOURCE/configure" \ --host=emscripten \ @@ -92,7 +92,7 @@ emconfigure "$WX_SOURCE/configure" \ --enable-universal \ --disable-shared \ --with-opengl \ - --disable-exceptions \ + --enable-exceptions \ --disable-richtext \ --without-libtiff \ --disable-xlocale \ diff --git a/scripts/deps/build-all-deps.sh b/scripts/deps/build-all-deps.sh index 581ce10..f4a651e 100755 --- a/scripts/deps/build-all-deps.sh +++ b/scripts/deps/build-all-deps.sh @@ -43,6 +43,7 @@ log_info "=== Phase 1: Header-only libraries ===" log_info "=== Phase 2: Basic compression/serialization ===" "${SCRIPT_DIR}/build-zstd.sh" ${CLEAN} "${SCRIPT_DIR}/build-protobuf.sh" ${CLEAN} +"${SCRIPT_DIR}/build-boost.sh" ${CLEAN} # 3. Font rendering stack log_info "=== Phase 3: Font rendering ===" @@ -54,6 +55,11 @@ log_info "=== Phase 4: Graphics libraries ===" "${SCRIPT_DIR}/build-pixman.sh" ${CLEAN} "${SCRIPT_DIR}/build-cairo.sh" ${CLEAN} +# 4b. Stub headers (needed for KiCad compilation but functionality is stubbed) +log_info "=== Phase 4b: Stub dependencies (headers only) ===" +"${SCRIPT_DIR}/build-curl-headers.sh" ${CLEAN} +"${SCRIPT_DIR}/build-libgit2-headers.sh" ${CLEAN} + # 5. Optional heavy dependencies if [ $WITH_OCC -eq 1 ]; then log_info "=== Phase 5a: OpenCASCADE (3D/STEP support) ===" diff --git a/scripts/deps/build-boost.sh b/scripts/deps/build-boost.sh index 95e1e65..8905e79 100755 --- a/scripts/deps/build-boost.sh +++ b/scripts/deps/build-boost.sh @@ -76,7 +76,7 @@ fi cat > user-config.jam << EOF using clang : emscripten : em++ - : "${BOOST_DEBUG_FLAGS} -pthread" + : "${BOOST_DEBUG_FLAGS} -pthread -matomics -mbulk-memory" "-pthread" ; EOF @@ -94,7 +94,7 @@ log_info "Building Boost.Locale (${BOOST_VARIANT})..." link=static \ threading=multi \ runtime-link=static \ - cxxflags="${BOOST_DEBUG_FLAGS} -pthread" \ + cxxflags="${BOOST_DEBUG_FLAGS} -pthread -matomics -mbulk-memory" \ install create_stamp "${BOOST_STAMP}" diff --git a/scripts/deps/build-cairo.sh b/scripts/deps/build-cairo.sh index e0721c3..fe41133 100755 --- a/scripts/deps/build-cairo.sh +++ b/scripts/deps/build-cairo.sh @@ -82,15 +82,19 @@ cpu = 'wasm32' endian = 'little' [properties] -# Prevent finding system libraries when cross-compiling -sys_root = '${SYSROOT}' +# Don't set sys_root - it gets prepended to pkg-config paths which are already absolute +# Just use pkg_config_libdir to control where we find .pc files pkg_config_libdir = '${SYSROOT}/lib/pkgconfig' [built-in options] default_library = 'static' b_staticpic = false b_pie = false -c_args = [${MESON_DEBUG_FLAGS}, '-pthread', '-I${SYSROOT}/include', '-I${SYSROOT}/include/freetype2', '-I${SYSROOT}/include/pixman-1'] +# Emscripten has these functions but meson checks fail - provide HAVE_ defines +# to prevent Cairo from defining its own conflicting implementations +# Include ft2build.h and ftcolor.h to fix FT_Color forward declaration bug in cairo-ft-private.h +# (the forward declaration is inside HAVE_FT_SVG_DOCUMENT but used in HAVE_FT_COLR_V1) +c_args = [${MESON_DEBUG_FLAGS}, '-pthread', '-matomics', '-mbulk-memory', '-I${SYSROOT}/include', '-I${SYSROOT}/include/freetype2', '-I${SYSROOT}/include/pixman-1', '-DHAVE_CTIME_R=1', '-DHAVE_LOCALTIME_R=1', '-DHAVE_GMTIME_R=1', '-DHAVE_STRNDUP=1', '-include', 'ft2build.h', '-include', 'freetype/ftcolor.h'] c_link_args = ['-pthread', '-L${SYSROOT}/lib'] pkg_config_path = '${SYSROOT}/lib/pkgconfig' EOF @@ -119,8 +123,38 @@ meson setup "${CAIRO_DIR}" \ -Dlibpng:default_library=static # JOBS is set in env.sh (default: 1 for sequential builds, use -j N to override) -ninja -j${JOBS} -ninja install +# Build only the library targets we need - utility executables fail to link and aren't needed +ninja -j${JOBS} src/libcairo.a + +# Manual installation - ninja install tries to build everything including utilities +# which fail due to freetype atomics issues +log_info "Installing Cairo library and headers..." +mkdir -p "${SYSROOT}/lib" "${SYSROOT}/include/cairo" "${SYSROOT}/lib/pkgconfig" +cp src/libcairo.a "${SYSROOT}/lib/" +cp "${CAIRO_DIR}/src/cairo.h" "${SYSROOT}/include/cairo/" +cp "${CAIRO_DIR}/src/cairo-deprecated.h" "${SYSROOT}/include/cairo/" +cp "${CAIRO_DIR}/src/cairo-version.h" "${SYSROOT}/include/cairo/" +# cairo-features.h is generated during configure in the build directory +cp src/cairo-features.h "${SYSROOT}/include/cairo/" +cp "${CAIRO_DIR}/src/cairo-ft.h" "${SYSROOT}/include/cairo/" +cp "${CAIRO_DIR}/src/cairo-pdf.h" "${SYSROOT}/include/cairo/" +cp "${CAIRO_DIR}/src/cairo-ps.h" "${SYSROOT}/include/cairo/" +cp "${CAIRO_DIR}/src/cairo-script.h" "${SYSROOT}/include/cairo/" + +# Create pkg-config file +cat > "${SYSROOT}/lib/pkgconfig/cairo.pc" << PKGEOF +prefix=${SYSROOT} +exec_prefix=\${prefix} +libdir=\${prefix}/lib +includedir=\${prefix}/include + +Name: cairo +Description: Multi-platform 2D graphics library +Version: 1.18.0 +Libs: -L\${libdir} -lcairo +Cflags: -I\${includedir}/cairo +Requires.private: freetype2 pixman-1 +PKGEOF create_stamp "${CAIRO_STAMP}" log_info "Cairo build complete!" diff --git a/scripts/deps/build-freetype.sh b/scripts/deps/build-freetype.sh index 6a433bc..4a459a5 100755 --- a/scripts/deps/build-freetype.sh +++ b/scripts/deps/build-freetype.sh @@ -56,8 +56,8 @@ emcmake cmake "${FREETYPE_DIR}" \ -DCMAKE_BUILD_TYPE=${BUILD_TYPE:-Debug} \ -DCMAKE_INSTALL_PREFIX="${SYSROOT}" \ -DCMAKE_POLICY_VERSION_MINIMUM=3.5 \ - -DCMAKE_C_FLAGS="${DEBUG_CFLAGS:--g -O0}" \ - -DCMAKE_CXX_FLAGS="${DEBUG_CFLAGS:--g -O0}" \ + -DCMAKE_C_FLAGS="${DEBUG_CFLAGS:--g -O0} -pthread -matomics -mbulk-memory" \ + -DCMAKE_CXX_FLAGS="${DEBUG_CFLAGS:--g -O0} -pthread -matomics -mbulk-memory" \ -DFT_DISABLE_BZIP2=ON \ -DFT_DISABLE_BROTLI=ON \ -DFT_DISABLE_HARFBUZZ=ON \ @@ -68,5 +68,12 @@ emcmake cmake "${FREETYPE_DIR}" \ emmake make -j${JOBS} emmake make install +# Create symlink without debug suffix for pkg-config compatibility +# FreeType CMake adds 'd' suffix for Debug builds but pkg-config expects 'libfreetype' +if [ -f "${SYSROOT}/lib/libfreetyped.a" ] && [ ! -f "${SYSROOT}/lib/libfreetype.a" ]; then + ln -sf libfreetyped.a "${SYSROOT}/lib/libfreetype.a" + log_info "Created libfreetype.a symlink for pkg-config" +fi + create_stamp "${FREETYPE_STAMP}" log_info "FreeType build complete!" diff --git a/scripts/deps/build-harfbuzz.sh b/scripts/deps/build-harfbuzz.sh index 165116d..02ddba3 100755 --- a/scripts/deps/build-harfbuzz.sh +++ b/scripts/deps/build-harfbuzz.sh @@ -60,8 +60,8 @@ emcmake cmake "${HARFBUZZ_DIR}" \ -DCMAKE_BUILD_TYPE=${BUILD_TYPE:-Debug} \ -DCMAKE_INSTALL_PREFIX="${SYSROOT}" \ -DCMAKE_POLICY_VERSION_MINIMUM=3.5 \ - -DCMAKE_C_FLAGS="${DEBUG_CFLAGS:--g -O0}" \ - -DCMAKE_CXX_FLAGS="${DEBUG_CFLAGS:--g -O0}" \ + -DCMAKE_C_FLAGS="${DEBUG_CFLAGS:--g -O0} -pthread -matomics -mbulk-memory" \ + -DCMAKE_CXX_FLAGS="${DEBUG_CFLAGS:--g -O0} -pthread -matomics -mbulk-memory" \ -DHB_HAVE_FREETYPE=ON \ -DHB_HAVE_GLIB=OFF \ -DHB_HAVE_ICU=OFF \ diff --git a/scripts/deps/build-opencascade.sh b/scripts/deps/build-opencascade.sh index fa6dec8..d35b78a 100755 --- a/scripts/deps/build-opencascade.sh +++ b/scripts/deps/build-opencascade.sh @@ -63,8 +63,8 @@ emcmake cmake "${OCC_DIR}" \ -DCMAKE_POLICY_VERSION_MINIMUM=3.5 \ -DCMAKE_BUILD_TYPE=${BUILD_TYPE:-Debug} \ -DCMAKE_INSTALL_PREFIX="${SYSROOT}" \ - -DCMAKE_CXX_FLAGS="${DEBUG_CFLAGS:--g -O0} -pthread" \ - -DCMAKE_C_FLAGS="${DEBUG_CFLAGS:--g -O0} -pthread" \ + -DCMAKE_CXX_FLAGS="${DEBUG_CFLAGS:--g -O0} -pthread -matomics -mbulk-memory" \ + -DCMAKE_C_FLAGS="${DEBUG_CFLAGS:--g -O0} -pthread -matomics -mbulk-memory" \ -DBUILD_LIBRARY_TYPE=Static \ -DBUILD_MODULE_ApplicationFramework=OFF \ -DBUILD_MODULE_Draw=OFF \ diff --git a/scripts/deps/build-pixman.sh b/scripts/deps/build-pixman.sh index 06e9c60..e079525 100755 --- a/scripts/deps/build-pixman.sh +++ b/scripts/deps/build-pixman.sh @@ -77,7 +77,7 @@ cpu = 'wasm32' endian = 'little' [built-in options] -c_args = [${MESON_DEBUG_FLAGS}, '-pthread'] +c_args = [${MESON_DEBUG_FLAGS}, '-pthread', '-matomics', '-mbulk-memory'] c_link_args = ['-pthread'] EOF diff --git a/scripts/deps/build-protobuf.sh b/scripts/deps/build-protobuf.sh index 85cf856..0094aa7 100755 --- a/scripts/deps/build-protobuf.sh +++ b/scripts/deps/build-protobuf.sh @@ -57,8 +57,8 @@ cd "${PROTOBUF_BUILD}" emcmake cmake "${PROTOBUF_DIR}" \ -DCMAKE_BUILD_TYPE=${BUILD_TYPE:-Debug} \ -DCMAKE_INSTALL_PREFIX="${SYSROOT}" \ - -DCMAKE_C_FLAGS="${DEBUG_CFLAGS:--g -O0} -pthread" \ - -DCMAKE_CXX_FLAGS="${DEBUG_CFLAGS:--g -O0} -pthread" \ + -DCMAKE_C_FLAGS="${DEBUG_CFLAGS:--g -O0} -pthread -matomics -mbulk-memory" \ + -DCMAKE_CXX_FLAGS="${DEBUG_CFLAGS:--g -O0} -pthread -matomics -mbulk-memory" \ -Dprotobuf_BUILD_TESTS=OFF \ -Dprotobuf_BUILD_EXAMPLES=OFF \ -Dprotobuf_BUILD_PROTOC_BINARIES=OFF \ @@ -68,5 +68,16 @@ emcmake cmake "${PROTOBUF_DIR}" \ emmake make -j${JOBS} emmake make install +# Create symlinks without debug suffix for pkg-config compatibility +# Protobuf CMake adds 'd' suffix for Debug builds but pkg-config expects 'libprotobuf' +if [ -f "${SYSROOT}/lib/libprotobufd.a" ] && [ ! -f "${SYSROOT}/lib/libprotobuf.a" ]; then + ln -sf libprotobufd.a "${SYSROOT}/lib/libprotobuf.a" + log_info "Created libprotobuf.a symlink for pkg-config" +fi +if [ -f "${SYSROOT}/lib/libprotobuf-lited.a" ] && [ ! -f "${SYSROOT}/lib/libprotobuf-lite.a" ]; then + ln -sf libprotobuf-lited.a "${SYSROOT}/lib/libprotobuf-lite.a" + log_info "Created libprotobuf-lite.a symlink for pkg-config" +fi + create_stamp "${PROTOBUF_STAMP}" log_info "Protobuf build complete!" diff --git a/scripts/deps/build-zstd.sh b/scripts/deps/build-zstd.sh index 0c1d4f5..79b4fc9 100755 --- a/scripts/deps/build-zstd.sh +++ b/scripts/deps/build-zstd.sh @@ -62,8 +62,8 @@ emcmake cmake "${ZSTD_DIR}/build/cmake" \ -DZSTD_BUILD_SHARED=OFF \ -DZSTD_BUILD_STATIC=ON \ -DZSTD_MULTITHREAD_SUPPORT=ON \ - -DCMAKE_C_FLAGS="${DEBUG_CFLAGS:--g -O0} -pthread" \ - -DCMAKE_CXX_FLAGS="${DEBUG_CFLAGS:--g -O0} -pthread" + -DCMAKE_C_FLAGS="${DEBUG_CFLAGS:--g -O0} -pthread -matomics -mbulk-memory" \ + -DCMAKE_CXX_FLAGS="${DEBUG_CFLAGS:--g -O0} -pthread -matomics -mbulk-memory" emmake make -j${JOBS} emmake make install diff --git a/scripts/kicad/build-pcbnew.sh b/scripts/kicad/build-pcbnew.sh index b7fff72..e9083d0 100755 --- a/scripts/kicad/build-pcbnew.sh +++ b/scripts/kicad/build-pcbnew.sh @@ -87,9 +87,10 @@ else fi # Step 2: Build dependencies +# Note: --with-occ for OpenCASCADE, but NOT ngspice since KICAD_SPICE=OFF if [ $SKIP_DEPS -eq 0 ]; then log_info "Building dependencies..." - "${SCRIPT_DIR}/../deps/build-all-deps.sh" --all + "${SCRIPT_DIR}/../deps/build-all-deps.sh" --with-occ else log_info "Skipping dependencies (--skip-deps specified)" fi @@ -100,26 +101,33 @@ if [ $NO_CLEAN -eq 1 ] && check_stamp "${KICAD_STAMP}"; then exit 0 fi -# Step 4: Verify wxWidgets is built +# Step 4: Build wxWidgets if not present +WXWIDGETS_STAMP="${BUILD_ROOT}/stamps/wxwidgets.stamp" if [ ! -f "${WX_BUILD}/lib/libwx_baseu-3.2.a" ]; then - log_error "wxWidgets not found. Please build wxWidgets first with:" - log_error " ./scripts/build-wxuniversal-wasm.sh" - exit 1 + log_info "Building wxWidgets..." + "${SCRIPT_DIR}/../build-wxuniversal-wasm.sh" --no-clean + # Create stamp after successful build + touch "${WXWIDGETS_STAMP}" +elif [ ! -f "${WXWIDGETS_STAMP}" ]; then + # Library exists but no stamp - create one + touch "${WXWIDGETS_STAMP}" fi log_info "Building KiCad PCBnew ${KICAD_VERSION} for WASM..." # Step 5: Set build type # Use environment DEBUG_BUILD if set, otherwise check local --debug flag +# -fexceptions is required because wxWidgets is built with exceptions enabled +# -matomics -mbulk-memory are required for shared memory (pthreads) if [ "${DEBUG_BUILD:-0}" = "1" ] || [ $DEBUG -eq 1 ]; then BUILD_TYPE="Debug" - EXTRA_FLAGS="-g -O0" - LINKER_DEBUG_FLAGS="-g -gsource-map" + EXTRA_FLAGS="-g -O0 -fexceptions -matomics -mbulk-memory" + LINKER_DEBUG_FLAGS="-g -gsource-map -fexceptions" log_info "Building KiCad in DEBUG mode (with source maps)" else BUILD_TYPE="Release" - EXTRA_FLAGS="-O2" - LINKER_DEBUG_FLAGS="" + EXTRA_FLAGS="-O2 -fexceptions -matomics -mbulk-memory" + LINKER_DEBUG_FLAGS="-fexceptions" log_info "Building KiCad in RELEASE mode" fi