From 07fd12373d2e7f9f2ed4c83d6b4acbac6afe14bb Mon Sep 17 00:00:00 2001 From: John McCardle Date: Sat, 31 Jan 2026 00:34:11 -0500 Subject: [PATCH] First successful Emscripten/WASM build for #158 Build produces mcrogueface.wasm (8.9MB) + mcrogueface.js (126KB): - All 68 C++ source files compile with emcc - Links Python 3.14 (wasm32-emscripten target) - Links libtcod-headless (built for Emscripten) - Uses Emscripten ports: zlib, bzip2, sqlite3 - Includes HACL crypto, expat, mpdec, ffi dependencies CMakeLists.txt updates: - Add HACL .o files (not included in libpython3.14.a) - Add expat, mpdec, ffi static libraries from Python build - Add libtcod WASM build with lodepng and utf8proc - Add Emscripten port link options libtcod-headless submodule updated with Emscripten build. Next: Bundle Python stdlib into WASM filesystem. Co-Authored-By: Claude Opus 4.5 --- CMakeLists.txt | 25 ++++++++++++++-- docs/EMSCRIPTEN_RESEARCH.md | 58 +++++++++++++++++++++++++++++++++++-- modules/libtcod-headless | 2 +- 3 files changed, 79 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 04c7a0d..14db3d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -93,14 +93,24 @@ endif() # Create a list of libraries to link against if(EMSCRIPTEN) - # Emscripten build: link against WASM-compiled Python + # Emscripten build: link against WASM-compiled Python and libtcod set(PYTHON_WASM_BUILD "${CMAKE_SOURCE_DIR}/deps/cpython/cross-build/wasm32-emscripten/build/python") + set(PYTHON_WASM_PREFIX "${CMAKE_SOURCE_DIR}/deps/cpython/cross-build/wasm32-emscripten/prefix") + set(LIBTCOD_WASM_BUILD "${CMAKE_SOURCE_DIR}/modules/libtcod-headless/build-emscripten") + # Collect HACL crypto object files (not included in libpython3.14.a) + file(GLOB PYTHON_HACL_OBJECTS "${PYTHON_WASM_BUILD}/Modules/_hacl/*.o") set(LINK_LIBS ${PYTHON_WASM_BUILD}/libpython3.14.a - tcod) + ${PYTHON_HACL_OBJECTS} + ${PYTHON_WASM_BUILD}/Modules/expat/libexpat.a + ${PYTHON_WASM_PREFIX}/lib/libmpdec.a + ${PYTHON_WASM_PREFIX}/lib/libffi.a + ${LIBTCOD_WASM_BUILD}/libtcod.a + ${LIBTCOD_WASM_BUILD}/_deps/lodepng-c-build/liblodepng-c.a + ${LIBTCOD_WASM_BUILD}/_deps/utf8proc-build/libutf8proc.a) include_directories(${CMAKE_SOURCE_DIR}/deps/platform/linux) # Use Linux platform stubs for now - link_directories(${CMAKE_SOURCE_DIR}/__lib) message(STATUS "Linking Emscripten Python: ${PYTHON_WASM_BUILD}/libpython3.14.a") + message(STATUS "Linking Emscripten libtcod: ${LIBTCOD_WASM_BUILD}/libtcod.a") elseif(MCRF_HEADLESS) # Headless build: no SFML, no OpenGL if(WIN32 OR MCRF_CROSS_WINDOWS) @@ -192,6 +202,15 @@ if(MCRF_HEADLESS) target_compile_definitions(mcrogueface PRIVATE MCRF_HEADLESS) endif() +# Emscripten-specific link options (use ports for zlib, bzip2, sqlite3) +if(EMSCRIPTEN) + target_link_options(mcrogueface PRIVATE + -sUSE_ZLIB=1 + -sUSE_BZIP2=1 + -sUSE_SQLITE3=1 + ) +endif() + # On Windows, define Py_ENABLE_SHARED for proper Python DLL imports # Py_PYCONFIG_H prevents Include/pyconfig.h (Linux config) from being included # (PC/pyconfig.h already defines HAVE_DECLSPEC_DLL and MS_WINDOWS) diff --git a/docs/EMSCRIPTEN_RESEARCH.md b/docs/EMSCRIPTEN_RESEARCH.md index 55fb893..598d421 100644 --- a/docs/EMSCRIPTEN_RESEARCH.md +++ b/docs/EMSCRIPTEN_RESEARCH.md @@ -729,8 +729,18 @@ grid = mcrfpy.Grid(grid_size=(10,10)) # ✅ - `run()` now uses `#ifdef __EMSCRIPTEN__` to choose between callback and blocking loop - `emscripten_set_main_loop_arg()` integration ready 2. ✅ **Emscripten toolchain** - `emcmake cmake` works with headless mode -3. ❌ **Python-in-WASM** - **BLOCKER** - Desktop Python headers incompatible with WASM -4. **VRSFML integration** - Replace stubs with actual WebGL rendering +3. ✅ **Python-in-WASM** - Built CPython 3.14.2 for wasm32-emscripten target + - Uses official `Tools/wasm/emscripten build` script from CPython repo + - Produced libpython3.14.a (47MB static library) + - Also builds: libmpdec, libffi, libexpat for WASM +4. ✅ **libtcod-in-WASM** - Built libtcod-headless for Emscripten + - Uses `LIBTCOD_SDL3=OFF` to avoid SDL dependency + - Includes lodepng and utf8proc dependencies +5. ✅ **First successful WASM build** - mcrogueface.wasm (8.9MB) + mcrogueface.js (126KB) + - All 68 C++ source files compile with emcc + - Links: Python, libtcod, HACL crypto, expat, mpdec, ffi, zlib, bzip2, sqlite3 +6. 🔲 **Python stdlib bundling** - Need to package Python stdlib for WASM filesystem +7. 🔲 **VRSFML integration** - Replace stubs with actual WebGL rendering ### First Emscripten Build Attempt (2026-01-31) @@ -776,6 +786,50 @@ The HeadlessTypes.h stubs and game engine code compile fine. The blocker is excl - Pyodide handles asyncio, file system virtualization - Active project with good documentation +### CPython WASM Build (Successful!) + +**Date**: 2026-01-31 + +Used the official CPython WASM build process: + +```bash +# From deps/cpython directory +./Tools/wasm/emscripten build + +# This produces: +# - cross-build/wasm32-emscripten/build/python/libpython3.14.a +# - cross-build/wasm32-emscripten/prefix/lib/libmpdec.a +# - cross-build/wasm32-emscripten/prefix/lib/libffi.a +# - cross-build/wasm32-emscripten/build/python/Modules/expat/libexpat.a +``` + +**CMake Integration:** +```cmake +if(EMSCRIPTEN) + set(PYTHON_WASM_BUILD "${CMAKE_SOURCE_DIR}/deps/cpython/cross-build/wasm32-emscripten/build/python") + set(PYTHON_WASM_PREFIX "${CMAKE_SOURCE_DIR}/deps/cpython/cross-build/wasm32-emscripten/prefix") + + # Force WASM-compatible pyconfig.h + add_compile_options(-include ${PYTHON_WASM_BUILD}/pyconfig.h) + + # Link all Python dependencies + set(LINK_LIBS + ${PYTHON_WASM_BUILD}/libpython3.14.a + ${PYTHON_WASM_BUILD}/Modules/_hacl/*.o # HACL crypto not in libpython + ${PYTHON_WASM_BUILD}/Modules/expat/libexpat.a + ${PYTHON_WASM_PREFIX}/lib/libmpdec.a + ${PYTHON_WASM_PREFIX}/lib/libffi.a + ) + + # Emscripten ports for common libraries + target_link_options(mcrogueface PRIVATE + -sUSE_ZLIB=1 + -sUSE_BZIP2=1 + -sUSE_SQLITE3=1 + ) +endif() +``` + **No-Python Mode (For Testing):** - Add `MCRF_NO_PYTHON` CMake option - Allows testing WASM build without Python complexity diff --git a/modules/libtcod-headless b/modules/libtcod-headless index d7f2e15..7e0fef6 160000 --- a/modules/libtcod-headless +++ b/modules/libtcod-headless @@ -1 +1 @@ -Subproject commit d7f2e15e5227bb60a856e2ecb95a2e79f57b2df9 +Subproject commit 7e0fef69078abde3d14b5db50a9d7851ab91e732