diff --git a/.github/workflows/manifold.yml b/.github/workflows/manifold.yml index 9a81b41ef..7c9d93e47 100644 --- a/.github/workflows/manifold.yml +++ b/.github/workflows/manifold.yml @@ -115,6 +115,9 @@ jobs: build_wasm: timeout-minutes: 30 runs-on: ubuntu-22.04 + strategy: + matrix: + parallelization: [OFF, ON] steps: - name: Install dependencies run: | @@ -126,20 +129,22 @@ jobs: # setup emscripten git clone https://github.com/emscripten-core/emsdk.git cd emsdk - ./emsdk install 3.1.61 - ./emsdk activate 3.1.61 + ./emsdk install 3.1.64 + ./emsdk activate 3.1.64 - uses: jwlawson/actions-setup-cmake@v2 - - name: Build WASM + - name: Build WASM ${{matrix.parallelization}} run: | source ./emsdk/emsdk_env.sh mkdir build cd build - emcmake cmake -DCMAKE_BUILD_TYPE=Release .. && emmake make + emcmake cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DMANIFOLD_PAR=${{matrix.parallelization}} .. && emmake make - name: Test WASM + if: matrix.parallelization == 'OFF' run: | cd build/test node ./manifold_test.js - name: Test examples + if: matrix.parallelization == 'OFF' run: | cd bindings/wasm/examples npm ci @@ -148,7 +153,7 @@ jobs: cp ../manifold.* ./dist/ - name: Upload WASM files uses: actions/upload-artifact@v4 - if: github.event_name == 'push' + if: github.event_name == 'push' && matrix.parallelization == 'OFF' with: name: wasm path: bindings/wasm/examples/dist/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 7dc2af0af..3fdbe9c44 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -123,9 +123,11 @@ if(EMSCRIPTEN) add_compile_options(-pthread) # mimalloc is needed for good performance add_link_options(-sMALLOC=mimalloc) + add_link_options(-sPTHREAD_POOL_SIZE=4) # The default stack size apparently causes problem when parallelization is # enabled. - add_link_options(-sSTACK_SIZE=10MB) + add_link_options(-sSTACK_SIZE=30MB) + add_link_options(-sINITIAL_MEMORY=32MB) endif() if(MANIFOLD_DEBUG) list(APPEND MANIFOLD_FLAGS -fexceptions) diff --git a/README.md b/README.md index 5ff2c02a8..e5d02095d 100644 --- a/README.md +++ b/README.md @@ -137,6 +137,10 @@ The build instructions used by our CI are in [manifold.yml](https://github.com/e ### WASM +> Note: While we support compiling with `MANIFOLD_PAR=ON` in recent emscripten +> versions, this is not recommended as there can potentially be memory +> corruption issues. + To build the JS WASM library, first install NodeJS and set up emscripten: (on Mac): @@ -158,7 +162,7 @@ Then build: cd manifold mkdir buildWASM cd buildWASM -emcmake cmake -DCMAKE_BUILD_TYPE=Release .. && emmake make +emcmake cmake -DCMAKE_BUILD_TYPE=MinSizeRel .. && emmake make node test/manifold_test.js ``` diff --git a/bindings/wasm/CMakeLists.txt b/bindings/wasm/CMakeLists.txt index 2c28acbc0..190e6142a 100644 --- a/bindings/wasm/CMakeLists.txt +++ b/bindings/wasm/CMakeLists.txt @@ -49,10 +49,6 @@ add_custom_target( add_custom_command( TARGET js_deps POST_BUILD - # fix js file - COMMAND - ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/fixup.py - ${CMAKE_CURRENT_BINARY_DIR}/manifold.js # copy WASM build back here for publishing to npm COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/manifold.* diff --git a/bindings/wasm/examples/vite-fixup-plugin.js b/bindings/wasm/examples/vite-fixup-plugin.js new file mode 100644 index 000000000..3c79cae45 --- /dev/null +++ b/bindings/wasm/examples/vite-fixup-plugin.js @@ -0,0 +1,48 @@ +// https://gist.github.com/jamsinclair/6ad148d0590291077a4ce389c2b274ea +import {createFilter} from 'vite'; + +function isEmscriptenFile(code) { + return /var\s+Module\s*=|WebAssembly\.instantiate/.test(code) && + /var\s+workerOptions\s*=/.test(code); +} + +/** + * Vite plugin that replaces Emscripten workerOptions with static object literal + * to fix error with Vite See project issue: + * https://github.com/emscripten-core/emscripten/issues/22394 + * + * Defaults to running for all .js and .ts files. If there are any issues you + * can use the include/exclude options. + * + * @param {Object} options + * @property {string[]} [include] - Glob patterns to include + * @property {string[]} [exclude] - Glob patterns to exclude + * @returns {import('vite').Plugin} + */ +export default function emscriptenStaticWorkerOptions(options = {}) { + const filter = createFilter(options.include || /\.[jt]s$/, options.exclude); + + return { + name: 'emscripten-static-worker-options', + enforce: 'pre', + transform(code, id) { + if (!filter(id)) return null; + + if (!isEmscriptenFile(code)) return null; + + const workerOptionsMatch = + code.match(/var\s+workerOptions\s*=\s*({[^}]+})/); + if (!workerOptionsMatch) return null; + + const optionsObjectStr = workerOptionsMatch[1]; + const optionsDeclarationStr = workerOptionsMatch[0]; + + const modifiedCode = + code.replace(optionsDeclarationStr, '') + .replace( + new RegExp('workerOptions(?![\\w$])', 'g'), optionsObjectStr); + + return {code: modifiedCode, map: null}; + } + }; +} diff --git a/bindings/wasm/examples/vite.config.js b/bindings/wasm/examples/vite.config.js index 9676c2d75..631c0502f 100644 --- a/bindings/wasm/examples/vite.config.js +++ b/bindings/wasm/examples/vite.config.js @@ -2,11 +2,11 @@ import {resolve} from 'path' import {defineConfig} from 'vite' +import emscriptenStaticWorkerOptions from './vite-fixup-plugin.js' + export default defineConfig({ test: {testTimeout: 15000}, - worker: { - format: 'es', - }, + worker: {format: 'es', plugins: [emscriptenStaticWorkerOptions]}, server: { headers: { 'Cross-Origin-Embedder-Policy': 'require-corp', diff --git a/bindings/wasm/fixup.py b/bindings/wasm/fixup.py deleted file mode 100644 index 01d17ffac..000000000 --- a/bindings/wasm/fixup.py +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env python3 -import sys - -if len(sys.argv) != 2: - print("Usage: python fixup.py ") - -filename = sys.argv[1] -with open(filename, "r") as file: - data = file.read() - -data = data.replace( - 'var workerOptions={type:"module",workerData:"em-pthread",name:"em-pthread"};', "" -) -data = data.replace( - "workerOptions", '{type:"module",workerData:"em-pthread",name:"em-pthread"}' -) - -with open(filename, "w") as file: - file.write(data) diff --git a/cmake/manifoldDeps.cmake b/cmake/manifoldDeps.cmake index 552b61638..c4ace570a 100644 --- a/cmake/manifoldDeps.cmake +++ b/cmake/manifoldDeps.cmake @@ -68,7 +68,7 @@ if(MANIFOLD_PAR) FetchContent_Declare( TBB GIT_REPOSITORY https://github.com/oneapi-src/oneTBB.git - GIT_TAG v2021.11.0 + GIT_TAG v2022.0.0 GIT_PROGRESS TRUE EXCLUDE_FROM_ALL ) @@ -112,7 +112,8 @@ if(MANIFOLD_CROSS_SECTION) FetchContent_Declare( Clipper2 GIT_REPOSITORY https://github.com/AngusJohnson/Clipper2.git - GIT_TAG ff378668baae3570e9d8070aa9eb339bdd5a6aba + # Nov 22, 2024 + GIT_TAG a8269cafe92cdbf92572bceda5e9fdacc4684b51 GIT_PROGRESS TRUE SOURCE_SUBDIR CPP EXCLUDE_FROM_ALL @@ -218,10 +219,6 @@ if(MANIFOLD_TEST) endif() endif() -if(EMSCRIPTEN) - find_package(Python REQUIRED) -endif() - if(MANIFOLD_FUZZ) logmissingdep("fuzztest" , "MANIFOLD_FUZZ") FetchContent_Declare( diff --git a/flake.nix b/flake.nix index e24baafb8..3c999ac2b 100644 --- a/flake.nix +++ b/flake.nix @@ -125,7 +125,7 @@ export EM_CACHE=$(pwd)/.emscriptencache mkdir build cd build - emcmake cmake -DCMAKE_BUILD_TYPE=Release \ + emcmake cmake -DCMAKE_BUILD_TYPE=MinSizeRel \ -DMANIFOLD_PAR=${if parallel then "ON" else "OFF"} \ -DFETCHCONTENT_SOURCE_DIR_GOOGLETEST=${gtest-src} \ -DFETCHCONTENT_SOURCE_DIR_TBB=${onetbb-src} \ @@ -134,11 +134,12 @@ buildPhase = '' emmake make -j''${NIX_BUILD_CORES} ''; - checkPhase = if doCheck then '' - cd test - node manifold_test.js - cd ../ - '' else ""; + checkPhase = + if doCheck then '' + cd test + node manifold_test.js + cd ../ + '' else ""; installPhase = '' mkdir -p $out cp bindings/wasm/manifold.* $out/ @@ -150,7 +151,11 @@ manifold-tbb = manifold { }; manifold-none = manifold { parallel = false; }; manifold-js = manifold-emscripten { }; - manifold-js-tbb = manifold-emscripten { parallel = true; }; + manifold-js-tbb = manifold-emscripten { + parallel = true; + doCheck = + false; + }; # but how should we make it work with other python versions? manifold3d = with pkgs.python3Packages; buildPythonPackage { pname = "manifold3d"; diff --git a/test/test_main.cpp b/test/test_main.cpp index dfa78e5f9..aca1ab65e 100644 --- a/test/test_main.cpp +++ b/test/test_main.cpp @@ -18,7 +18,7 @@ #include "test.h" #if (MANIFOLD_PAR == 1) -#include +#include #endif // we need to call some tracy API to establish the connection