diff --git a/.clang-format b/.clang-format deleted file mode 100644 index cd67ef0..0000000 --- a/.clang-format +++ /dev/null @@ -1,52 +0,0 @@ -BasedOnStyle: Mozilla -AccessModifierOffset: '-4' -AlignAfterOpenBracket: Align -AlignEscapedNewlinesLeft: 'false' -AllowAllParametersOfDeclarationOnNextLine: 'true' -AllowShortBlocksOnASingleLine: 'false' -AllowShortCaseLabelsOnASingleLine: 'false' -AllowShortFunctionsOnASingleLine: 'false' -AllowShortIfStatementsOnASingleLine: 'false' -AllowShortLoopsOnASingleLine: 'false' -AlwaysBreakTemplateDeclarations: 'true' -SpaceAfterTemplateKeyword: 'true' -BreakBeforeBinaryOperators: All -BreakBeforeBraces: Allman -BreakBeforeTernaryOperators: 'true' -BreakConstructorInitializersBeforeComma: 'true' -BreakStringLiterals: 'false' -ColumnLimit: '100' -ConstructorInitializerAllOnOneLineOrOnePerLine: 'false' -ConstructorInitializerIndentWidth: '4' -ContinuationIndentWidth: '4' -Cpp11BracedListStyle: 'false' -DerivePointerAlignment: 'false' -DisableFormat: 'false' -ExperimentalAutoDetectBinPacking: 'true' -IndentCaseLabels: 'true' -IndentWidth: '4' -IndentWrappedFunctionNames: 'false' -JavaScriptQuotes: Single -KeepEmptyLinesAtTheStartOfBlocks: 'false' -Language: Cpp -MaxEmptyLinesToKeep: '2' -NamespaceIndentation: All -ObjCBlockIndentWidth: '4' -ObjCSpaceAfterProperty: 'false' -ObjCSpaceBeforeProtocolList: 'false' -PointerAlignment: Left -ReflowComments: 'true' -SortIncludes: 'false' -SpaceAfterCStyleCast: 'true' -SpaceBeforeAssignmentOperators: 'true' -SpaceBeforeParens: ControlStatements -SpaceInEmptyParentheses: 'false' -SpacesBeforeTrailingComments: '2' -SpacesInAngles: 'false' -SpacesInCStyleCastParentheses: 'false' -SpacesInContainerLiterals: 'false' -SpacesInParentheses: 'false' -SpacesInSquareBrackets: 'false' -Standard: c++17 -TabWidth: '4' -UseTab: Never diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 3dc945a..d620987 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -23,8 +23,8 @@ jobs: fail-fast: false matrix: include: - - emsdk_ver: "3.1.73" - python_version: "3.13" + - emsdk_ver: "6.0.8" + python_version: "3.14" steps: diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index fb46a16..34a9ead 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,25 +13,28 @@ defaults: jobs: - test-browser: + test-browser-wasm32: runs-on: ubuntu-latest strategy: - fail-fast: false + fail-fast: true steps: - uses: actions/checkout@v2 - name: Install micromamba - uses: mamba-org/setup-micromamba@v1 + uses: mamba-org/setup-micromamba@v3 with: - environment-file: environment-dev.yml + init-shell: >- + bash + environment-file: environment-wasm-build-wasm32.yml environment-name: pyjs-wasm condarc: | channels: - - https://repo.prefix.dev/emscripten-forge-4x + - microsoft - conda-forge + - https://repo.prefix.dev/emscripten-forge-bot/emscripten-forge-6x - name: Install Playwright @@ -44,15 +47,15 @@ jobs: micromamba create -n pyjs-build-wasm \ --platform=emscripten-wasm32 \ - -c https://repo.prefix.dev/emscripten-forge-4x \ + -c https://repo.prefix.dev/emscripten-forge-bot/emscripten-forge-6x \ -c https://repo.mamba.pm/conda-forge \ --yes \ - "python=3.13" \ - "pybind11<3" \ - nlohmann_json pybind11_json numpy \ - pytest bzip2 sqlite zlib zstd libffi \ - exceptiongroup emscripten-abi>=4 \ - "openssl<4" liblzma + "python-dev=3.14" \ + "pybind11" \ + "nlohmann_json" "pybind11_json" "numpy" \ + pytest \ + exceptiongroup emscripten-abi>=6 + mkdir build @@ -62,15 +65,27 @@ jobs: export PREFIX=$MAMBA_ROOT_PREFIX/envs/pyjs-build-wasm export CMAKE_PREFIX_PATH=$PREFIX export CMAKE_SYSTEM_PREFIX_PATH=$PREFIX - + export PY_VER=3.14 # build pyjs emcmake cmake \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ON \ - -DBUILD_RUNTIME_BROWSER=ON \ - -DBUILD_RUNTIME_NODE=OFF \ - -DCMAKE_INSTALL_PREFIX=$PREFIX \ - .. + -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ON \ + -DBUILD_RUNTIME_BROWSER=ON \ + -DBUILD_RUNTIME_NODE=OFF \ + -DCMAKE_INSTALL_PREFIX=$PREFIX \ + -DLINK_LIBLZMA=ON \ + -DPY_VERSION=$PY_VER \ + -DPYTHON_SITE_PACKAGES=$PREFIX/lib/python${PY_VER}/site-packages \ + -DPython_INCLUDE_DIRS=$PREFIX/include/python${PY_VER} \ + -DPython_LIBRARY=$PREFIX/lib/libpython${PY_VER}.a \ + -DPython_LIBRARIES=$PREFIX/lib/libpython${PY_VER}.a \ + -DPython_Interpreter_FOUND=TRUE \ + -DPython_EXECUTABLE=$MAMBA_ROOT_PREFIX/envs/pyjs-wasm/bin/python${PY_VER} \ + -DPYTHON_MODULE_EXTENSION=.so \ + -DPYTHON_MODULE_DEBUG_POSTFIX="" \ + -DPYTHON_MODULE_EXT_SUFFIX=.so \ + -DPython_FOUND=TRUE \ + -DWASM64=FALSE \ + .. make -j2 @@ -83,10 +98,10 @@ jobs: micromamba activate pyjs-wasm micromamba create -n pyjs-build-wasm-with-numpy \ --platform=emscripten-wasm32 \ - -c https://repo.prefix.dev/emscripten-forge-4x \ - -c https://repo.mamba.pm/conda-forge \ + -c https://repo.prefix.dev/emscripten-forge-bot/emscripten-forge-6x \ + -c https://repo.prefix.dev/conda-forge \ --yes \ - "python=3.13" pytest numpy exceptiongroup + "python=3.14" "pytest>=9" numpy - name: Test in browser-main @@ -96,7 +111,7 @@ jobs: browser-main \ --conda-env $MAMBA_ROOT_PREFIX/envs/pyjs-build-wasm-with-numpy \ --mount $(pwd)/tests:/tests \ - --mount $(pwd)/module/pyjs:/lib/python3.13/site-packages/pyjs \ + --mount $(pwd)/module/pyjs:/lib/python3.14/site-packages/pyjs \ --script main.py \ --work-dir /tests \ --pyjs-dir $(pwd)/build \ @@ -112,7 +127,7 @@ jobs: browser-worker \ --conda-env $MAMBA_ROOT_PREFIX/envs/pyjs-build-wasm-with-numpy \ --mount $(pwd)/tests:/tests \ - --mount $(pwd)/module/pyjs:/lib/python3.13/site-packages/pyjs \ + --mount $(pwd)/module/pyjs:/lib/python3.14/site-packages/pyjs \ --script main.py \ --work-dir /tests \ --pyjs-dir $(pwd)/build \ @@ -124,10 +139,10 @@ jobs: micromamba activate pyjs-wasm micromamba create -n pyjs-build-wasm-no-numpy \ --platform=emscripten-wasm32 \ - -c https://repo.prefix.dev/emscripten-forge-4x \ - -c https://repo.mamba.pm/conda-forge \ + -c https://repo.prefix.dev/emscripten-forge-bot/emscripten-forge-6x \ + -c https://repo.prefix.dev/conda-forge \ --yes \ - "python=3.13" pytest exceptiongroup + "python=3.14" "pytest>=9" - name: Test in browser-main-no-numpy run: | @@ -138,10 +153,157 @@ jobs: browser-main \ --conda-env $MAMBA_ROOT_PREFIX/envs/pyjs-build-wasm-no-numpy \ --mount $(pwd)/tests:/tests \ - --mount $(pwd)/module/pyjs:/lib/python3.13/site-packages/pyjs \ + --mount $(pwd)/module/pyjs:/lib/python3.14/site-packages/pyjs \ --script main.py \ --work-dir /tests \ --pyjs-dir $(pwd)/build \ --headless \ --async-main \ - --no-cache \ No newline at end of file + --no-cache + test-browser-wasm64: + + runs-on: ubuntu-latest + + strategy: + fail-fast: true + + steps: + - uses: actions/checkout@v2 + + - name: Install micromamba + uses: mamba-org/setup-micromamba@v3 + with: + init-shell: >- + bash + environment-file: environment-wasm-build-wasm64.yml + environment-name: pyjs-wasm + condarc: | + channels: + - microsoft + - conda-forge + - https://repo.prefix.dev/emscripten-forge-bot/emscripten-forge-6x + + + - name: Install Playwright + run: | + playwright install + + - name: Build pyjs + run: | + micromamba activate pyjs-wasm + + micromamba create -n pyjs-build-wasm64 \ + --platform=emscripten-wasm64 \ + -c https://repo.prefix.dev/emscripten-forge-bot/emscripten-forge-6x \ + -c https://repo.mamba.pm/conda-forge \ + --yes \ + "python-dev=3.14" \ + "pybind11" \ + "nlohmann_json" "pybind11_json" "numpy" \ + pytest \ + exceptiongroup emscripten-abi>=6 + + + + mkdir build + pushd build + + + export PREFIX=$MAMBA_ROOT_PREFIX/envs/pyjs-build-wasm64 + export CMAKE_PREFIX_PATH=$PREFIX + export CMAKE_SYSTEM_PREFIX_PATH=$PREFIX + export PY_VER=3.14 + # build pyjs + emcmake cmake \ + -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ON \ + -DBUILD_RUNTIME_BROWSER=ON \ + -DBUILD_RUNTIME_NODE=OFF \ + -DCMAKE_INSTALL_PREFIX=$PREFIX \ + -DLINK_LIBLZMA=ON \ + -DPY_VERSION=$PY_VER \ + -DPYTHON_SITE_PACKAGES=$PREFIX/lib/python${PY_VER}/site-packages \ + -DPython_INCLUDE_DIRS=$PREFIX/include/python${PY_VER} \ + -DPython_LIBRARY=$PREFIX/lib/libpython${PY_VER}.a \ + -DPython_LIBRARIES=$PREFIX/lib/libpython${PY_VER}.a \ + -DPython_Interpreter_FOUND=TRUE \ + -DPython_EXECUTABLE=$MAMBA_ROOT_PREFIX/envs/pyjs-wasm/bin/python${PY_VER} \ + -DPYTHON_MODULE_EXTENSION=.so \ + -DPYTHON_MODULE_DEBUG_POSTFIX="" \ + -DPYTHON_MODULE_EXT_SUFFIX=.so \ + -DPython_FOUND=TRUE \ + -DWASM64=TRUE \ + .. + + make -j2 + + make install + + popd + + - name: setup env with numpy + run: | + micromamba activate pyjs-wasm + micromamba create -n pyjs-build-wasm-with-numpy \ + --platform=emscripten-wasm64 \ + -c https://repo.prefix.dev/emscripten-forge-bot/emscripten-forge-6x \ + -c https://repo.prefix.dev/conda-forge \ + --yes \ + "python=3.14" "pytest>=9" numpy + + + - name: Test in browser-main + run: | + micromamba activate pyjs-wasm + pyjs_code_runner run script \ + browser-main \ + --conda-env $MAMBA_ROOT_PREFIX/envs/pyjs-build-wasm-with-numpy \ + --mount $(pwd)/tests:/tests \ + --mount $(pwd)/module/pyjs:/lib/python3.14/site-packages/pyjs \ + --script main.py \ + --work-dir /tests \ + --pyjs-dir $(pwd)/build \ + --headless \ + --async-main + + - name: Test in browser-worker + run: | + micromamba activate pyjs-wasm + + + pyjs_code_runner run script \ + browser-worker \ + --conda-env $MAMBA_ROOT_PREFIX/envs/pyjs-build-wasm-with-numpy \ + --mount $(pwd)/tests:/tests \ + --mount $(pwd)/module/pyjs:/lib/python3.14/site-packages/pyjs \ + --script main.py \ + --work-dir /tests \ + --pyjs-dir $(pwd)/build \ + --headless \ + --async-main + + - name: setup minimal env without numpy + run: | + micromamba activate pyjs-wasm + micromamba create -n pyjs-build-wasm-no-numpy \ + --platform=emscripten-wasm64 \ + -c https://repo.prefix.dev/emscripten-forge-bot/emscripten-forge-6x \ + -c https://repo.prefix.dev/conda-forge \ + --yes \ + "python=3.14" "pytest>=9" + + - name: Test in browser-main-no-numpy + run: | + micromamba activate pyjs-wasm + + + pyjs_code_runner run script \ + browser-main \ + --conda-env $MAMBA_ROOT_PREFIX/envs/pyjs-build-wasm-no-numpy \ + --mount $(pwd)/tests:/tests \ + --mount $(pwd)/module/pyjs:/lib/python3.14/site-packages/pyjs \ + --script main.py \ + --work-dir /tests \ + --pyjs-dir $(pwd)/build \ + --headless \ + --async-main \ + --no-cache \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 56aa6b1..868a6f0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,17 +1,18 @@ -cmake_minimum_required(VERSION 3.9) - +cmake_minimum_required(VERSION 4.0) project(pyjs VERSION 4.0.6 DESCRIPTION "pyjs") -option(BUILD_RUNTIME_BROWSER "Build runtime" ON) -option(WITH_NODE_TESTS "With node tests" OFF) -option(LINK_LIBEXPAT "Link libexpat" OFF) -option(LINK_LIBMPDEC "Link libmpdec" OFF) -option(LINK_LIBLZMA "Link liblzma" OFF) +# cmake module directory +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + + +option(WASM64 "Enable WebAssembly 64-bit support" OFF) + + -# set PY_VERSION to 3.11 if the user has not set it if (NOT DEFINED PY_VERSION) - set(PY_VERSION 3.11) + # raise an error if the user has not set PY_VERSION + message(FATAL_ERROR "PY_VERSION is not set. Please set it to the desired Python version (e.g., 3.14) before running CMake.") endif() file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/pycpp_includes) @@ -19,7 +20,7 @@ file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/pycpp_includes) ########################################################## # generate prejs and postjs ########################################################## -set(PREJS_FILES +set(PREJS_FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/pyjs/pre_js/constants.js ${CMAKE_CURRENT_SOURCE_DIR}/include/pyjs/pre_js/get_type_string.js ${CMAKE_CURRENT_SOURCE_DIR}/include/pyjs/pre_js/wrap_result.js @@ -43,14 +44,12 @@ set(POSTJS_FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/pyjs/post_js/fixes.js ) - add_custom_target(merge_pyjs ALL DEPENDS "pyjs_pre.js" "pyjs_post.js" ) - add_custom_command(OUTPUT "pyjs_pre.js" COMMAND $ENV{CONDA_PREFIX}/bin/python ${CMAKE_SOURCE_DIR}/build_utils/merge_js.py @@ -68,7 +67,6 @@ add_custom_command(OUTPUT "pyjs_post.js" ${CMAKE_CURRENT_SOURCE_DIR}/src/js_timestamp.cpp DEPENDS ${POSTJS_FILES}) - ########################################################## # headers to install ########################################################## @@ -85,19 +83,10 @@ set(PYJS_HEADERS ${CMAKE_CURRENT_BINARY_DIR}/pyjs_post.js ) - - set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(pybind11_REQUIRED_VERSION 2.6.1) - -if (NOT TARGET pybind11::headers) - find_package(pybind11 ${pybind11_REQUIRED_VERSION} REQUIRED) -endif () - - add_library(pyjs STATIC src/export_js_module.cpp src/export_js_proxy.cpp @@ -108,10 +97,12 @@ add_library(pyjs STATIC src/inflate.cpp src/untar.cpp src/install_conda_file.cpp - ${PYCPPSOURCES} ) +if(WASM64) + target_compile_options(pyjs PUBLIC -m64) + target_link_options(pyjs PUBLIC -m64) +endif() -target_link_libraries(pyjs PRIVATE ${PYTHON_UTIL_LIBS} pybind11::embed) target_compile_options(pyjs PUBLIC --std=c++17 @@ -124,20 +115,15 @@ target_link_options(pyjs PUBLIC -Wno-unused-command-line-argument PUBLIC "SHELL: -fwasm-exceptions" PUBLIC "SHELL: -lembind" - # PUBLIC "SHELL: -fsanitize=address" - #PUBLIC "SHELL:-s EXPORT_EXCEPTION_HANDLING_HELPERS" - #PUBLIC "SHELL:-s EXCEPTION_CATCHING_ALLOWED=['we only want to allow exception handling in side modules']" ) - set_target_properties(pyjs PROPERTIES PUBLIC_HEADER "${PYJS_HEADERS}" - # DEPENDS "pyjs_pre.js" "pyjs_post.js" ) add_dependencies(pyjs merge_pyjs) -target_link_libraries(pyjs PRIVATE pybind11::pybind11) +target_link_libraries(pyjs PRIVATE ) target_compile_options(pyjs PRIVATE -fPIC) @@ -147,34 +133,34 @@ target_include_directories(pyjs $ ) -SET(PYTHON_UTIL_LIBS +SET(PYTHON_LIBRARIES ${CMAKE_INSTALL_PREFIX}/lib/libbz2.a ${CMAKE_INSTALL_PREFIX}/lib/libz.a ${CMAKE_INSTALL_PREFIX}/lib/libsqlite3.a ${CMAKE_INSTALL_PREFIX}/lib/libffi.a ${CMAKE_INSTALL_PREFIX}/lib/libzstd.a - # ssl ${CMAKE_INSTALL_PREFIX}/lib/libssl.a - # crypto ${CMAKE_INSTALL_PREFIX}/lib/libcrypto.a - # lzma ${CMAKE_INSTALL_PREFIX}/lib/liblzma.a + ${CMAKE_INSTALL_PREFIX}/lib/libpython${PY_VERSION}.a + ${CMAKE_INSTALL_PREFIX}/lib/libexpat.a + ${CMAKE_INSTALL_PREFIX}/lib/libmpdec.a + ${CMAKE_INSTALL_PREFIX}/lib/libHacl_Hash_BLAKE2.a + ${CMAKE_INSTALL_PREFIX}/lib/libHacl_Hash_MD5.a + ${CMAKE_INSTALL_PREFIX}/lib/libHacl_Hash_SHA1.a + ${CMAKE_INSTALL_PREFIX}/lib/libHacl_Hash_SHA2.a + ${CMAKE_INSTALL_PREFIX}/lib/libHacl_Hash_SHA3.a ) -if (LINK_LIBEXPAT) - SET(PYTHON_UTIL_LIBS ${PYTHON_UTIL_LIBS} ${CMAKE_INSTALL_PREFIX}/lib/libexpat.a) -endif() - -if (LINK_LIBMPDEC) - SET(PYTHON_UTIL_LIBS ${PYTHON_UTIL_LIBS} ${CMAKE_INSTALL_PREFIX}/lib/libmpdec.a) -endif() - set_target_properties(pyjs PROPERTIES CXX_STANDARD 17 ) +find_package(pybind11 CONFIG) + + add_executable(pyjs_runtime_browser src/runtime.cpp ) SET(ENVIRONMENT "web,worker") @@ -193,7 +179,11 @@ set_target_properties(pyjs_runtime_browser ) target_compile_definitions(pyjs_runtime_browser PUBLIC -DPYJS_WEB) target_compile_options(pyjs_runtime_browser PRIVATE -fPIC) -target_link_libraries(pyjs_runtime_browser PRIVATE pyjs pybind11::embed ${PYTHON_UTIL_LIBS}) + +# include the dir where pybind11 is installed, so that we can find the pybind11Config.cmake file +include_directories(${pybind11_INCLUDE_DIRS}) + +target_link_libraries(pyjs_runtime_browser PRIVATE ${PYTHON_LIBRARIES} pyjs) @@ -207,9 +197,6 @@ target_compile_options(pyjs_runtime_browser PUBLIC "SHELL: -s EXPORT_EXCEPTION_HANDLING_HELPERS" PUBLIC "SHELL: -s FORCE_FILESYSTEM" PUBLIC "SHELL: -s EXPORT_ALL=1" - # PUBLIC "SHELL: -flto" - # PUBLIC "SHELL: -s MAXIMUM_MEMORY=2GB" - # PUBLIC "SHELL: -fsanitize=address" ) target_link_options(pyjs_runtime_browser diff --git a/build_utils/merge_js.py b/build_utils/merge_js.py index 70581c8..64c5c9b 100644 --- a/build_utils/merge_js.py +++ b/build_utils/merge_js.py @@ -18,9 +18,9 @@ def merge(*filenames): outfile.write(line) outfile.write("\n") - with open(filename_timestamp, "w") as outfile: - timestamp = str(datetime.datetime.utcnow()) - outfile.write(f'#define PYJS_JS_UTC_TIMESTAMP "{timestamp}"') + # with open(filename_timestamp, "w") as outfile: + # timestamp = str(datetime.datetime.utcnow()) + # outfile.write(f'#define PYJS_JS_UTC_TIMESTAMP "{timestamp}"') if __name__ == "__main__": diff --git a/build_v2.sh b/build_v2.sh new file mode 100755 index 0000000..4cb58fc --- /dev/null +++ b/build_v2.sh @@ -0,0 +1,170 @@ +#!/bin/bash +set -e + + +# wasm bitness is first argument, if not passed, throw an error +WASM_BITNESS=$1 +if [ -z "$WASM_BITNESS" ]; then + echo "Error: WASM bitness not specified." + exit 1 +fi + +WASM_NAME=wasm$WASM_BITNESS +THIS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +BUILD_PREFIX_DIR=$THIS_DIR/build_prefix_$WASM_NAME +WASM_PREFIX_DIR=$THIS_DIR/wasm_prefix_$WASM_NAME +WASM_DEPLOY_PREFIX_DIR=$THIS_DIR/wasm_deploy_prefix_$WASM_NAME +DEPLOYMENT_DIR=$THIS_DIR/deploy +BUILD_DIR=$THIS_DIR/build-$WASM_NAME +mkdir -p $DEPLOYMENT_DIR + +MM=$MAMBA_EXE +RAT=rattker + +unset EMCC_FLAGS + + +# does build env exist? +if [ ! -d "$BUILD_PREFIX_DIR" ]; then + rm -rf $BUILD_PREFIX_DIR + echo "Creating wasm env at $BUILD_PREFIX_DIR" + $MM create -p $BUILD_PREFIX_DIR \ + -f $THIS_DIR/environment-wasm-build-$WASM_NAME.yml \ + --yes + exit 0 +fi + +if [ ! -d "$WASM_PREFIX_DIR" ]; then + rm -rf $WASM_PREFIX_DIR + echo "Creating wasm env at $WASM_PREFIX_DIR" + $MM create -p $WASM_PREFIX_DIR \ + --platform=emscripten-$WASM_NAME \ + -f $THIS_DIR/environment-wasm.yml \ + --yes +fi + +if [ ! -d "$WASM_DEPLOY_PREFIX_DIR" ]; then + echo "Creating wasm env at $WASM_DEPLOY_PREFIX_DIR" + $MM create -p $WASM_DEPLOY_PREFIX_DIR \ + --platform=emscripten-$WASM_NAME \ + -f $THIS_DIR/environment-wasm-deploy.yml \ + --yes +fi + +export PY_VER=3.14 + + +# clear CC and CXX to avoid using host compiler +unset LDFLAGS +unset LDFLAGS_LD + + +# set -m64 flag for wasm64 +if [ "$WASM_BITNESS" == "64" ]; then + echo "Setting EMCC_FLAGS for wasm64" + export EMCC_FLAGS="$EMCC_FLAGS -m64" +fi + +export PREFIX="${WASM_PREFIX_DIR}" + +if true; then + echo "Building pyjs" + + # rm -rf build + mkdir -p $BUILD_DIR + cd $BUILD_DIR + + export PREFIX=$WASM_PREFIX_DIR + export CMAKE_PREFIX_PATH=$PREFIX + export CMAKE_SYSTEM_PREFIX_PATH=$PREFIX + emcmake cmake \ + -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ON \ + -DBUILD_RUNTIME_BROWSER=ON \ + -DBUILD_RUNTIME_NODE=OFF \ + -DCMAKE_INSTALL_PREFIX=$PREFIX \ + -DLINK_LIBLZMA=ON \ + -DPY_VERSION=$PY_VER \ + -DPYTHON_SITE_PACKAGES=$PREFIX/lib/python${PY_VER}/site-packages \ + -DPython_INCLUDE_DIRS=$PREFIX/include/python${PY_VER} \ + -DPython_LIBRARY=$PREFIX/lib/libpython${PY_VER}.a \ + -DPython_LIBRARIES=$PREFIX/lib/libpython${PY_VER}.a \ + -DPython_Interpreter_FOUND=TRUE \ + -DPython_EXECUTABLE=$BUILD_PREFIX/bin/python${PY_VER} \ + -DPYTHON_MODULE_EXTENSION=.so \ + -DPYTHON_MODULE_DEBUG_POSTFIX="" \ + -DPYTHON_MODULE_EXT_SUFFIX=.so \ + -DPython_FOUND=TRUE \ + -DWASM64=TRUE \ + .. + + emmake make -j8 + emmake make install +fi + + +DEPLOYMENT_DIR=$THIS_DIR/deploy +mkdir -p $DEPLOYMENT_DIR + +# # pack env with empack +# if true; then + +# cd $THIS_DIR + + +# echo "Packing wasm env" +# rm -rf $DEPLOYMENT_DIR/pyjs-wasm-env.tar.zst + + +# empack pack env \ +# --env-prefix $WASM_PREFIX_DIR \ +# --relocate-prefix "/" \ +# --no-use-cache \ +# --outdir $DEPLOYMENT_DIR + +# echo "pack pyjs module" +# empack pack dir \ +# --host-dir $THIS_DIR/module/pyjs \ +# --mount-dir /lib/python3.14/site-packages/pyjs \ +# --outname "pyjsmod.tar.gz" \ +# --outdir $DEPLOYMENT_DIR + +# empack pack append \ +# --env-meta $DEPLOYMENT_DIR/empack_env_meta.json \ +# --tarfile $DEPLOYMENT_DIR/pyjsmod.tar.gz + +# fi + +# # copy pyjs binary to deployment dir +# cp $THIS_DIR/build/pyjs_runtime_browser.js $DEPLOYMENT_DIR/pyjs_runtime_browser.js +# cp $THIS_DIR/build/pyjs_runtime_browser.wasm $DEPLOYMENT_DIR/pyjs_runtime_browser.wasm +# # cp $THIS_DIR/index.html $DEPLOYMENT_DIR/index.html + +if true; then + mkdir -p $BUILD_DIR/host_work_dir + cd $THIS_DIR + + + # run in env with does not contain numpy + pyjs_code_runner run script \ + browser-main \ + --conda-env $WASM_DEPLOY_PREFIX_DIR \ + --mount $THIS_DIR/tests:/tests \ + --mount $THIS_DIR/module/pyjs:/lib/python3.14/site-packages/pyjs \ + --script main.py \ + --work-dir /tests \ + --host-work-dir $BUILD_DIR/host_work_dir \ + --headless \ + --no-cache \ + --slow-mo 0 \ + --async-main \ + --pyjs-dir $BUILD_DIR \ + +fi + + + +# rm -rf deploy +# mkdir -p deploy +# cd deploy + +# jupyter lite build --XeusAddon.prefix=$WASM_PREFIX_DIR \ No newline at end of file diff --git a/environment-dev.yml b/environment-wasm-build-wasm32.yml similarity index 67% rename from environment-dev.yml rename to environment-wasm-build-wasm32.yml index ef42e07..8f5a77e 100644 --- a/environment-dev.yml +++ b/environment-wasm-build-wasm32.yml @@ -1,17 +1,20 @@ -name: pyjs-wasm +name: pyjs-wasm-build channels: + - microsoft - conda-forge - - https://repo.prefix.dev/emscripten-forge-4x + - https://repo.prefix.dev/emscripten-forge-bot/emscripten-forge-6x -dependencies: + +dependencies: - cmake - pip - - python + - python =3.14 - yarn - click - - microsoft::playwright <= 1.50 - ninja - nodejs + - emscripten_emscripten-wasm32 == 6.0.8 + - microsoft::playwright - pyjs_code_runner >= 2.0.1 - exceptiongroup # documentation @@ -21,14 +24,13 @@ dependencies: - mkdocstrings-python - mkdocs-material - empack >=6.0.0 - - jupyter_server # to enable contents + - jupyter_server # to enable contents - jupyterlite - jupyterlite-xeus >= 3.1.8 - jupyterlite-sphinx - notebook >=7,<8 # to include the extension to switch between JupyterLab and Notebook # pyjs_code_runner dev deps - hatchling - - emscripten_emscripten-wasm32 == 4.0.9 - pip: - JLDracula - pyjs_code_runner >= 3.0 diff --git a/environment-wasm-build-wasm64.yml b/environment-wasm-build-wasm64.yml new file mode 100644 index 0000000..b9b2382 --- /dev/null +++ b/environment-wasm-build-wasm64.yml @@ -0,0 +1,32 @@ +name: pyjs-wasm-build +channels: + - microsoft + - conda-forge + - https://repo.prefix.dev/emscripten-forge-bot/emscripten-forge-6x + +dependencies: + - cmake + - pip + - python =3.14 + - yarn + - click + - ninja + - nodejs + - emscripten_emscripten-wasm64 == 6.0.8 + - microsoft::playwright + - pyjs_code_runner + - exceptiongroup + # documentation + - jupytext + - mkdocs + - mkdocstrings + - mkdocstrings-python + - mkdocs-material + - empack >=6.0.0 + - jupyter_server # to enable contents + - jupyterlite + - jupyterlite-xeus >= 3.1.8 + - jupyterlite-sphinx + - notebook >=7,<8 # to include the extension to switch between JupyterLab and Notebook + # pyjs_code_runner dev deps + - hatchling diff --git a/environment-wasm-deploy.yml b/environment-wasm-deploy.yml new file mode 100644 index 0000000..3cdd98a --- /dev/null +++ b/environment-wasm-deploy.yml @@ -0,0 +1,10 @@ +name: pyjs-wasm-deploy +channels: + - conda-forge + - https://repo.prefix.dev/emscripten-forge-bot/emscripten-forge-6x + +dependencies: + - python + - emscripten-abi==6.0.8 + - numpy + - pytest \ No newline at end of file diff --git a/environment-wasm.yml b/environment-wasm.yml new file mode 100644 index 0000000..b898f82 --- /dev/null +++ b/environment-wasm.yml @@ -0,0 +1,15 @@ +name: pyjs-wasm-run +channels: + - /Users/thorstenbeier/src/recipes/output + - conda-forge + - https://repo.prefix.dev/emscripten-forge-bot/emscripten-forge-6x + +dependencies: + - libpython-static + - python + - pybind11 + - emscripten-abi==6.0.8 + - numpy + - zlib-static + - libsqlite-static + - libbzip2-static \ No newline at end of file diff --git a/src/export_js_proxy.cpp b/src/export_js_proxy.cpp index 76062e3..2c1c568 100644 --- a/src/export_js_proxy.cpp +++ b/src/export_js_proxy.cpp @@ -212,8 +212,7 @@ namespace pyjs m_internal.def("val_bind", [](em::val* v, em::val arg1) { return v->call("bind", arg1); }); - - + // m_internal.def("val_new",[](em::val v){ // return v.new_(); // }); diff --git a/src/js_timestamp.cpp b/src/js_timestamp.cpp index 6c1742d..a0e4475 100644 --- a/src/js_timestamp.cpp +++ b/src/js_timestamp.cpp @@ -1 +1 @@ -#define PYJS_JS_UTC_TIMESTAMP "2025-10-07 09:33:27.627626" \ No newline at end of file +#define PYJS_JS_UTC_TIMESTAMP "2026-09-07 08:23:38.609625" \ No newline at end of file diff --git a/tests/main.py b/tests/main.py index 8cdf5fe..37da2d3 100644 --- a/tests/main.py +++ b/tests/main.py @@ -52,28 +52,31 @@ async def main(): if run_sync_pytest_tests: import pyjs - import pytest - import os + import pytest dir_path = os.path.dirname(os.path.realpath(__file__)) os.chdir(dir_path) - # import pytest_asyncio - - # start the tests os.environ["NO_COLOR"] = "1" specific_test = None - args = [] - args = ["-s", f"{dir_path}/tests"] + + args = [ + "-s", + "-vvv", + "-p", "no:faulthandler", + f"{dir_path}/tests", + ] + if specific_test is not None: args += ["-k", str(specific_test)] - # args += ["-p", "pytest_asyncio"] - retcode = pytest.main(args, plugins=[]) + if retcode != pytest.ExitCode.OK: raise RuntimeError(f"pytest failed with return code: {retcode}") + + return 0