Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
9d4bf5a
Bump to Pyodide 0.28.1
agriyakhetarpal Aug 13, 2025
16f90d9
Bump Python version for conda-python-emscripten
agriyakhetarpal Aug 14, 2025
eebb7a8
Pass the right flag for WASM exception handling
agriyakhetarpal Aug 14, 2025
af2e18d
Install `libatomic1` for Pyodide Dockerfile
agriyakhetarpal Aug 14, 2025
41adbeb
Undo WASM EH flags as SjLj is enabled
agriyakhetarpal Aug 14, 2025
a89f7ec
Fix lint in Emscripten Dockerfile `apt-get` command
agriyakhetarpal Aug 14, 2025
20de7ad
Build static `libarrow_python` on Emscripten
agriyakhetarpal Aug 14, 2025
781b54a
Add Emscripten-specific flags for `_acero`
agriyakhetarpal Aug 14, 2025
f73c495
Fix CMake lint
agriyakhetarpal Aug 14, 2025
6ef7bb3
Revert "Fix CMake lint"
agriyakhetarpal Aug 14, 2025
18bf7d5
Revert "Add Emscripten-specific flags for `_acero`"
agriyakhetarpal Aug 14, 2025
eae25be
Revert "Build static `libarrow_python` on Emscripten"
agriyakhetarpal Aug 15, 2025
d279250
Merge main
agriyakhetarpal Aug 15, 2026
dc69985
Update to Python 3.14 and Pyodide 314.0.4
agriyakhetarpal Aug 15, 2026
89a6615
Use Pyodide 2026_0 ABI flags and set `RPATH` to `$ORIGIN`
agriyakhetarpal Aug 15, 2026
103bef4
`packaging` needed on Emscripten due to `pyarrow/tests/util.py`
agriyakhetarpal Aug 15, 2026
e62cf80
Add handling for Unix `script -c`/`script -q`
agriyakhetarpal Aug 15, 2026
b92772d
Fix Abseil ABI mismatch on linking with AppleClang
agriyakhetarpal Aug 15, 2026
ef4ecb6
Update to Node 24 in environment
agriyakhetarpal Aug 15, 2026
ff64e0d
Add separate pyodide-build version argument
agriyakhetarpal Aug 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 15 additions & 8 deletions ci/docker/conda-python-emscripten.dockerfile
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,32 +18,39 @@
ARG repo
ARG arch
ARG arch_short
ARG python="3.12"
ARG python="3.14"
FROM --platform=linux/${arch} ${repo}:${arch_short}-conda-python-${python}

ARG selenium_version="4.41.0"
ARG pyodide_version="0.26.0"
ARG pyodide_version="314.0.4"
# pyodide-build is versioned independently of Pyodide
ARG pyodide_build_version="0.39.0"
ARG chrome_version="latest"
ARG required_python_min="(3,12)"
# fail if python version < 3.12
ARG required_python_min="(3,14)"
# fail if python version < 3.14
RUN echo "check PYTHON>=${required_python_min}" && python -c "import sys;sys.exit(0 if sys.version_info>=${required_python_min} else 1)"

# install selenium and recent pyodide-build and recent python
RUN apt-get update -y -q && \
apt-get install -y -q --no-install-recommends \
libatomic1 && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

# needs to be a login shell so ~/.profile is read
SHELL ["/bin/bash", "--login", "-c", "-o", "pipefail"]

# install selenium and recent pyodide-build and recent python
RUN python -m pip install --no-cache-dir selenium==${selenium_version} && \
python -m pip install --no-cache-dir --upgrade pyodide-build>=${pyodide_version}
python -m pip install --no-cache-dir --upgrade "pyodide-build>=${pyodide_build_version}"

# install pyodide dist directory to /pyodide
RUN pyodide_dist_url="https://github.com/pyodide/pyodide/releases/download/${pyodide_version}/pyodide-${pyodide_version}.tar.bz2" && \
wget -q "${pyodide_dist_url}" -O- | tar -xj -C /

# install node 20 (needed for async call support)
# install node 24 (needed for async call support and JSPI)
# and pthread-stubs for build, and unzip needed for chrome build to work
# xz is needed by emsdk to extract node tarballs
RUN conda install nodejs=20 unzip pthread-stubs make xz -c conda-forge
RUN conda install nodejs=24 unzip pthread-stubs make xz -c conda-forge

# install correct version of emscripten for this pyodide
COPY ci/scripts/install_emscripten.sh /arrow/ci/scripts/
Expand Down
5 changes: 3 additions & 2 deletions compose.yaml
Original file line numberDiff line numberDiff line change
Expand Up@@ -981,10 +981,11 @@ services:
arch_short: ${ARCH_SHORT}
clang_tools: ${CLANG_TOOLS}
llvm: ${LLVM}
pyodide_version: "0.26.0"
pyodide_version: "314.0.4"
pyodide_build_version: "0.39.0"
chrome_version: "latest"
selenium_version: "4.41.0"
required_python_min: "(3,12)"
required_python_min: "(3,14)"
python: ${PYTHON}
shm_size: *shm-size
volumes: *ubuntu-volumes
Expand Down
31 changes: 20 additions & 11 deletions cpp/cmake_modules/SetupCxxFlags.cmake
Original file line numberDiff line numberDiff line change
Expand Up@@ -719,26 +719,35 @@ if(MSVC)
endif()

if(CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
# flags are:
# For the Pyodide 2026_0 ABI, the flags are:
# 1) We force *everything* to build as position independent
# 2) And with support for C++ exceptions
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -fexceptions")
# 2) We support C++ WASM exceptions, using the native WebAssembly
# exception handling proposal and WebAssembly-based setjmp/longjmp
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -fwasm-exceptions -sSUPPORT_LONGJMP=wasm")
# deprecated-literal-operator error is thrown in datetime (vendored lib in arrow)
set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -fPIC -fexceptions -Wno-error=deprecated-literal-operator")
"${CMAKE_CXX_FLAGS} -fPIC -fwasm-exceptions -sSUPPORT_LONGJMP=wasm -Wno-error=deprecated-literal-operator"
)

# flags for creating shared libraries (only used in pyarrow, because
# Emscripten builds libarrow as static)
# flags are:
# 1) Tell it to use JavaScript / WebAssembly 64 bit number support.
# 2) Tell it to build with support for C++ exceptions
# 2) Tell it to build with support for C++ exceptions (see above)
# 3) Skip linker flags error which happens with -soname parameter
set(ARROW_EMSCRIPTEN_LINKER_FLAGS "-sWASM_BIGINT=1 -fexceptions -Wno-error=linkflags")
set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS
"-sSIDE_MODULE=1 ${ARROW_EMSCRIPTEN_LINKER_FLAGS}")
set(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS
"-sSIDE_MODULE=1 ${ARROW_EMSCRIPTEN_LINKER_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "-sSIDE_MODULE=1 ${ARROW_EMSCRIPTEN_LINKER_FLAGS}")
# 4) Record $ORIGIN as an RPATH, so that Pyodide can locate
# libarrow_python.so next to the extension modules needing it
# Note: the CMAKE_SHARED_LIBRARY_CREATE_<LANG>_FLAGS and
# CMAKE_SHARED_MODULE_CREATE_<LANG>_FLAGS variables are not used by the
# Ninja generator, so the flags must go through the linker-flags
# variables, which apply to SHARED (libarrow_python) and MODULE (Cython
# extension) targets respectively.
set(ARROW_EMSCRIPTEN_LINKER_FLAGS
"-sWASM_BIGINT=1 -fwasm-exceptions -sSUPPORT_LONGJMP=wasm -Wno-error=linkflags")
set(ARROW_EMSCRIPTEN_DYLIB_CREATE_FLAGS
"-sSIDE_MODULE=1 ${ARROW_EMSCRIPTEN_LINKER_FLAGS} '-Wl,-rpath,$ORIGIN'")
set(CMAKE_SHARED_LINKER_FLAGS "${ARROW_EMSCRIPTEN_DYLIB_CREATE_FLAGS}")
set(CMAKE_MODULE_LINKER_FLAGS "${ARROW_EMSCRIPTEN_DYLIB_CREATE_FLAGS}")
if(ARROW_TESTING)
# flags for building test executables for use in node
if("${UPPERCASE_BUILD_TYPE}" STREQUAL "RELEASE")
Expand Down
4 changes: 4 additions & 0 deletions cpp/cmake_modules/ThirdpartyToolchain.cmake
Original file line numberDiff line numberDiff line change
Expand Up@@ -2183,6 +2183,10 @@ function(build_protobuf)
set(PROTOBUF_HOST_CMAKE_ARGS
"-DCMAKE_CXX_FLAGS="
"-DCMAKE_C_FLAGS="
# Explicitly set the C++ standard for the host build. Without this,
# Abseil may be compiled with the host compiler's default standard,
# which can be older than C++17.
"-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
Comment on lines +2186 to +2189

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hope this change is fine to keep here; this happened to me because I am using AppleClang 21 on my macOS machine to cross-compile for Emscripten.

The reason is that in the host protoc build, where CMAKE_CXX_FLAGS is blanked and no standard is set, absl compiles as C++14 and uses absl::string_view. That results in an ABI mismatch because Protobuf's targets reference the std::string_view signatures (since Protobuf compiles to C++17 or newer).

(I guess no one has hit this before, since the CI job exercises going from Linux to Emscripten, where gcc defaults to C++17)

"-DCMAKE_INSTALL_PREFIX=${PROTOBUF_HOST_PREFIX}"
-Dprotobuf_BUILD_TESTS=OFF
-Dprotobuf_DEBUG_POSTFIX=
Expand Down
2 changes: 1 addition & 1 deletion dev/tasks/tasks.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -521,7 +521,7 @@ tasks:
params:
env:
UBUNTU: 22.04
PYTHON: 3.12
PYTHON: 3.14
image: conda-python-emscripten

test-conda-python-3.11-hypothesis:
Expand Down
4 changes: 2 additions & 2 deletions docs/source/developers/cpp/emscripten.rst
Original file line numberDiff line numberDiff line change
Expand Up@@ -34,9 +34,9 @@ activate it using the commands below (see https://emscripten.org/docs/getting_st
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
# replace <version> with the desired EMSDK version.
# e.g. for Pyodide 0.26, you need EMSDK version 3.1.58
# e.g. for Pyodide 314.0.x, you need EMSDK version 5.0.3
# the versions can be found in the Makefile.envs file in the Pyodide repo:
# https://github.com/pyodide/pyodide/blob/10b484cfe427e076c929a55dc35cfff01ea8d3bc/Makefile.envs
# https://github.com/pyodide/pyodide/blob/314.0.4/Makefile.envs
./emsdk install <version>
./emsdk activate <version>
source ./emsdk_env.sh
Expand Down
4 changes: 3 additions & 1 deletion python/CMakeLists.txt
Original file line numberDiff line numberDiff line change
Expand Up@@ -111,7 +111,9 @@ if("$ENV{CMAKE_EXPORT_COMPILE_COMMANDS}" STREQUAL "1")
set(CMAKE_EXPORT_COMPILE_COMMANDS 1)
endif()

if(UNIX)
# On Emscripten, the equivalent $ORIGIN runtime path is added
# through the linker flags in SetupCxxFlags.cmake instead
if(UNIX AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
# In the event that we are bundling the shared libraries (e.g. in a
# manylinux1 wheel), we need to set the RPATH of the extensions to the
Expand Down
9 changes: 8 additions & 1 deletion python/scripts/run_emscripten_tests.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -148,8 +148,14 @@ class NodeDriver:
import subprocess

def __init__(self, hostname, port):
# handle different syntax for util-linux script and macOS BSD-style script
if sys.platform == "darwin":
script_command = [shutil.which("script"), "-q", "/dev/null",
shutil.which("node")]
else:
script_command = [shutil.which("script"), "-c", shutil.which("node")]
self.process = subprocess.Popen(
[shutil.which("script"), "-c", shutil.which("node")],
script_command,
stdin=subprocess.PIPE,
shell=False,
bufsize=0,
Expand DownExpand Up@@ -320,6 +326,7 @@ def _load_pyarrow_in_runner(driver, wheel_name):
if "pyarrow" not in sys.modules:
await micropip.install("hypothesis")
import pyodide_js as pjs
await pjs.loadPackage("packaging")
await pjs.loadPackage("tzdata")
await pjs.loadPackage("numpy")
await pjs.loadPackage("pandas")
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all \u003cpre\u003e\u003ccode\u003e blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks"); } } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); } })(); (function(){ try { var __m = "github.com"; var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
9d4bf5a
Bump to Pyodide 0.28.1
agriyakhetarpal Aug 13, 2025
16f90d9
Bump Python version for conda-python-emscripten
agriyakhetarpal Aug 14, 2025
eebb7a8
Pass the right flag for WASM exception handling
agriyakhetarpal Aug 14, 2025
af2e18d
Install `libatomic1` for Pyodide Dockerfile
agriyakhetarpal Aug 14, 2025
41adbeb
Undo WASM EH flags as SjLj is enabled
agriyakhetarpal Aug 14, 2025
a89f7ec
Fix lint in Emscripten Dockerfile `apt-get` command
agriyakhetarpal Aug 14, 2025
20de7ad
Build static `libarrow_python` on Emscripten
agriyakhetarpal Aug 14, 2025
781b54a
Add Emscripten-specific flags for `_acero`
agriyakhetarpal Aug 14, 2025
f73c495
Fix CMake lint
agriyakhetarpal Aug 14, 2025
6ef7bb3
Revert "Fix CMake lint"
agriyakhetarpal Aug 14, 2025
18bf7d5
Revert "Add Emscripten-specific flags for `_acero`"
agriyakhetarpal Aug 14, 2025
eae25be
Revert "Build static `libarrow_python` on Emscripten"
agriyakhetarpal Aug 15, 2025
d279250
Merge main
agriyakhetarpal Aug 15, 2026
dc69985
Update to Python 3.14 and Pyodide 314.0.4
agriyakhetarpal Aug 15, 2026
89a6615
Use Pyodide 2026_0 ABI flags and set `RPATH` to `$ORIGIN`
agriyakhetarpal Aug 15, 2026
103bef4
`packaging` needed on Emscripten due to `pyarrow/tests/util.py`
agriyakhetarpal Aug 15, 2026
e62cf80
Add handling for Unix `script -c`/`script -q`
agriyakhetarpal Aug 15, 2026
b92772d
Fix Abseil ABI mismatch on linking with AppleClang
agriyakhetarpal Aug 15, 2026
ef4ecb6
Update to Node 24 in environment
agriyakhetarpal Aug 15, 2026
ff64e0d
Add separate pyodide-build version argument
agriyakhetarpal Aug 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 15 additions & 8 deletions ci/docker/conda-python-emscripten.dockerfile
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,32 +18,39 @@
ARG repo
ARG arch
ARG arch_short
ARG python="3.12"
ARG python="3.14"
FROM --platform=linux/${arch} ${repo}:${arch_short}-conda-python-${python}

ARG selenium_version="4.41.0"
ARG pyodide_version="0.26.0"
ARG pyodide_version="314.0.4"
# pyodide-build is versioned independently of Pyodide
ARG pyodide_build_version="0.39.0"
ARG chrome_version="latest"
ARG required_python_min="(3,12)"
# fail if python version < 3.12
ARG required_python_min="(3,14)"
# fail if python version < 3.14
RUN echo "check PYTHON>=${required_python_min}" && python -c "import sys;sys.exit(0 if sys.version_info>=${required_python_min} else 1)"

# install selenium and recent pyodide-build and recent python
RUN apt-get update -y -q && \
apt-get install -y -q --no-install-recommends \
libatomic1 && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

# needs to be a login shell so ~/.profile is read
SHELL ["/bin/bash", "--login", "-c", "-o", "pipefail"]

# install selenium and recent pyodide-build and recent python
RUN python -m pip install --no-cache-dir selenium==${selenium_version} && \
python -m pip install --no-cache-dir --upgrade pyodide-build>=${pyodide_version}
python -m pip install --no-cache-dir --upgrade "pyodide-build>=${pyodide_build_version}"

# install pyodide dist directory to /pyodide
RUN pyodide_dist_url="https://github.com/pyodide/pyodide/releases/download/${pyodide_version}/pyodide-${pyodide_version}.tar.bz2" && \
wget -q "${pyodide_dist_url}" -O- | tar -xj -C /

# install node 20 (needed for async call support)
# install node 24 (needed for async call support and JSPI)
# and pthread-stubs for build, and unzip needed for chrome build to work
# xz is needed by emsdk to extract node tarballs
RUN conda install nodejs=20 unzip pthread-stubs make xz -c conda-forge
RUN conda install nodejs=24 unzip pthread-stubs make xz -c conda-forge

# install correct version of emscripten for this pyodide
COPY ci/scripts/install_emscripten.sh /arrow/ci/scripts/
Expand Down
5 changes: 3 additions & 2 deletions compose.yaml
Original file line numberDiff line numberDiff line change
Expand Up@@ -981,10 +981,11 @@ services:
arch_short: ${ARCH_SHORT}
clang_tools: ${CLANG_TOOLS}
llvm: ${LLVM}
pyodide_version: "0.26.0"
pyodide_version: "314.0.4"
pyodide_build_version: "0.39.0"
chrome_version: "latest"
selenium_version: "4.41.0"
required_python_min: "(3,12)"
required_python_min: "(3,14)"
python: ${PYTHON}
shm_size: *shm-size
volumes: *ubuntu-volumes
Expand Down
31 changes: 20 additions & 11 deletions cpp/cmake_modules/SetupCxxFlags.cmake
Original file line numberDiff line numberDiff line change
Expand Up@@ -719,26 +719,35 @@ if(MSVC)
endif()

if(CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
# flags are:
# For the Pyodide 2026_0 ABI, the flags are:
# 1) We force *everything* to build as position independent
# 2) And with support for C++ exceptions
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -fexceptions")
# 2) We support C++ WASM exceptions, using the native WebAssembly
# exception handling proposal and WebAssembly-based setjmp/longjmp
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -fwasm-exceptions -sSUPPORT_LONGJMP=wasm")
# deprecated-literal-operator error is thrown in datetime (vendored lib in arrow)
set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -fPIC -fexceptions -Wno-error=deprecated-literal-operator")
"${CMAKE_CXX_FLAGS} -fPIC -fwasm-exceptions -sSUPPORT_LONGJMP=wasm -Wno-error=deprecated-literal-operator"
)

# flags for creating shared libraries (only used in pyarrow, because
# Emscripten builds libarrow as static)
# flags are:
# 1) Tell it to use JavaScript / WebAssembly 64 bit number support.
# 2) Tell it to build with support for C++ exceptions
# 2) Tell it to build with support for C++ exceptions (see above)
# 3) Skip linker flags error which happens with -soname parameter
set(ARROW_EMSCRIPTEN_LINKER_FLAGS "-sWASM_BIGINT=1 -fexceptions -Wno-error=linkflags")
set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS
"-sSIDE_MODULE=1 ${ARROW_EMSCRIPTEN_LINKER_FLAGS}")
set(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS
"-sSIDE_MODULE=1 ${ARROW_EMSCRIPTEN_LINKER_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "-sSIDE_MODULE=1 ${ARROW_EMSCRIPTEN_LINKER_FLAGS}")
# 4) Record $ORIGIN as an RPATH, so that Pyodide can locate
# libarrow_python.so next to the extension modules needing it
# Note: the CMAKE_SHARED_LIBRARY_CREATE_<LANG>_FLAGS and
# CMAKE_SHARED_MODULE_CREATE_<LANG>_FLAGS variables are not used by the
# Ninja generator, so the flags must go through the linker-flags
# variables, which apply to SHARED (libarrow_python) and MODULE (Cython
# extension) targets respectively.
set(ARROW_EMSCRIPTEN_LINKER_FLAGS
"-sWASM_BIGINT=1 -fwasm-exceptions -sSUPPORT_LONGJMP=wasm -Wno-error=linkflags")
set(ARROW_EMSCRIPTEN_DYLIB_CREATE_FLAGS
"-sSIDE_MODULE=1 ${ARROW_EMSCRIPTEN_LINKER_FLAGS} '-Wl,-rpath,$ORIGIN'")
set(CMAKE_SHARED_LINKER_FLAGS "${ARROW_EMSCRIPTEN_DYLIB_CREATE_FLAGS}")
set(CMAKE_MODULE_LINKER_FLAGS "${ARROW_EMSCRIPTEN_DYLIB_CREATE_FLAGS}")
if(ARROW_TESTING)
# flags for building test executables for use in node
if("${UPPERCASE_BUILD_TYPE}" STREQUAL "RELEASE")
Expand Down
4 changes: 4 additions & 0 deletions cpp/cmake_modules/ThirdpartyToolchain.cmake
Original file line numberDiff line numberDiff line change
Expand Up@@ -2183,6 +2183,10 @@ function(build_protobuf)
set(PROTOBUF_HOST_CMAKE_ARGS
"-DCMAKE_CXX_FLAGS="
"-DCMAKE_C_FLAGS="
# Explicitly set the C++ standard for the host build. Without this,
# Abseil may be compiled with the host compiler's default standard,
# which can be older than C++17.
"-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
Comment on lines +2186 to +2189

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hope this change is fine to keep here; this happened to me because I am using AppleClang 21 on my macOS machine to cross-compile for Emscripten.

The reason is that in the host protoc build, where CMAKE_CXX_FLAGS is blanked and no standard is set, absl compiles as C++14 and uses absl::string_view. That results in an ABI mismatch because Protobuf's targets reference the std::string_view signatures (since Protobuf compiles to C++17 or newer).

(I guess no one has hit this before, since the CI job exercises going from Linux to Emscripten, where gcc defaults to C++17)

"-DCMAKE_INSTALL_PREFIX=${PROTOBUF_HOST_PREFIX}"
-Dprotobuf_BUILD_TESTS=OFF
-Dprotobuf_DEBUG_POSTFIX=
Expand Down
2 changes: 1 addition & 1 deletion dev/tasks/tasks.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -521,7 +521,7 @@ tasks:
params:
env:
UBUNTU: 22.04
PYTHON: 3.12
PYTHON: 3.14
image: conda-python-emscripten

test-conda-python-3.11-hypothesis:
Expand Down
4 changes: 2 additions & 2 deletions docs/source/developers/cpp/emscripten.rst
Original file line numberDiff line numberDiff line change
Expand Up@@ -34,9 +34,9 @@ activate it using the commands below (see https://emscripten.org/docs/getting_st
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
# replace <version> with the desired EMSDK version.
# e.g. for Pyodide 0.26, you need EMSDK version 3.1.58
# e.g. for Pyodide 314.0.x, you need EMSDK version 5.0.3
# the versions can be found in the Makefile.envs file in the Pyodide repo:
# https://github.com/pyodide/pyodide/blob/10b484cfe427e076c929a55dc35cfff01ea8d3bc/Makefile.envs
# https://github.com/pyodide/pyodide/blob/314.0.4/Makefile.envs
./emsdk install <version>
./emsdk activate <version>
source ./emsdk_env.sh
Expand Down
4 changes: 3 additions & 1 deletion python/CMakeLists.txt
Original file line numberDiff line numberDiff line change
Expand Up@@ -111,7 +111,9 @@ if("$ENV{CMAKE_EXPORT_COMPILE_COMMANDS}" STREQUAL "1")
set(CMAKE_EXPORT_COMPILE_COMMANDS 1)
endif()

if(UNIX)
# On Emscripten, the equivalent $ORIGIN runtime path is added
# through the linker flags in SetupCxxFlags.cmake instead
if(UNIX AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
# In the event that we are bundling the shared libraries (e.g. in a
# manylinux1 wheel), we need to set the RPATH of the extensions to the
Expand Down
9 changes: 8 additions & 1 deletion python/scripts/run_emscripten_tests.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -148,8 +148,14 @@ class NodeDriver:
import subprocess

def __init__(self, hostname, port):
# handle different syntax for util-linux script and macOS BSD-style script
if sys.platform == "darwin":
script_command = [shutil.which("script"), "-q", "/dev/null",
shutil.which("node")]
else:
script_command = [shutil.which("script"), "-c", shutil.which("node")]
self.process = subprocess.Popen(
[shutil.which("script"), "-c", shutil.which("node")],
script_command,
stdin=subprocess.PIPE,
shell=False,
bufsize=0,
Expand DownExpand Up@@ -320,6 +326,7 @@ def _load_pyarrow_in_runner(driver, wheel_name):
if "pyarrow" not in sys.modules:
await micropip.install("hypothesis")
import pyodide_js as pjs
await pjs.loadPackage("packaging")
await pjs.loadPackage("tzdata")
await pjs.loadPackage("numpy")
await pjs.loadPackage("pandas")
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
9d4bf5a
Bump to Pyodide 0.28.1
agriyakhetarpal Aug 13, 2025
16f90d9
Bump Python version for conda-python-emscripten
agriyakhetarpal Aug 14, 2025
eebb7a8
Pass the right flag for WASM exception handling
agriyakhetarpal Aug 14, 2025
af2e18d
Install `libatomic1` for Pyodide Dockerfile
agriyakhetarpal Aug 14, 2025
41adbeb
Undo WASM EH flags as SjLj is enabled
agriyakhetarpal Aug 14, 2025
a89f7ec
Fix lint in Emscripten Dockerfile `apt-get` command
agriyakhetarpal Aug 14, 2025
20de7ad
Build static `libarrow_python` on Emscripten
agriyakhetarpal Aug 14, 2025
781b54a
Add Emscripten-specific flags for `_acero`
agriyakhetarpal Aug 14, 2025
f73c495
Fix CMake lint
agriyakhetarpal Aug 14, 2025
6ef7bb3
Revert "Fix CMake lint"
agriyakhetarpal Aug 14, 2025
18bf7d5
Revert "Add Emscripten-specific flags for `_acero`"
agriyakhetarpal Aug 14, 2025
eae25be
Revert "Build static `libarrow_python` on Emscripten"
agriyakhetarpal Aug 15, 2025
d279250
Merge main
agriyakhetarpal Aug 15, 2026
dc69985
Update to Python 3.14 and Pyodide 314.0.4
agriyakhetarpal Aug 15, 2026
89a6615
Use Pyodide 2026_0 ABI flags and set `RPATH` to `$ORIGIN`
agriyakhetarpal Aug 15, 2026
103bef4
`packaging` needed on Emscripten due to `pyarrow/tests/util.py`
agriyakhetarpal Aug 15, 2026
e62cf80
Add handling for Unix `script -c`/`script -q`
agriyakhetarpal Aug 15, 2026
b92772d
Fix Abseil ABI mismatch on linking with AppleClang
agriyakhetarpal Aug 15, 2026
ef4ecb6
Update to Node 24 in environment
agriyakhetarpal Aug 15, 2026
ff64e0d
Add separate pyodide-build version argument
agriyakhetarpal Aug 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 15 additions & 8 deletions ci/docker/conda-python-emscripten.dockerfile
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,32 +18,39 @@
ARG repo
ARG arch
ARG arch_short
ARG python="3.12"
ARG python="3.14"
FROM --platform=linux/${arch} ${repo}:${arch_short}-conda-python-${python}

ARG selenium_version="4.41.0"
ARG pyodide_version="0.26.0"
ARG pyodide_version="314.0.4"
# pyodide-build is versioned independently of Pyodide
ARG pyodide_build_version="0.39.0"
ARG chrome_version="latest"
ARG required_python_min="(3,12)"
# fail if python version < 3.12
ARG required_python_min="(3,14)"
# fail if python version < 3.14
RUN echo "check PYTHON>=${required_python_min}" && python -c "import sys;sys.exit(0 if sys.version_info>=${required_python_min} else 1)"

# install selenium and recent pyodide-build and recent python
RUN apt-get update -y -q && \
apt-get install -y -q --no-install-recommends \
libatomic1 && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

# needs to be a login shell so ~/.profile is read
SHELL ["/bin/bash", "--login", "-c", "-o", "pipefail"]

# install selenium and recent pyodide-build and recent python
RUN python -m pip install --no-cache-dir selenium==${selenium_version} && \
python -m pip install --no-cache-dir --upgrade pyodide-build>=${pyodide_version}
python -m pip install --no-cache-dir --upgrade "pyodide-build>=${pyodide_build_version}"

# install pyodide dist directory to /pyodide
RUN pyodide_dist_url="https://github.com/pyodide/pyodide/releases/download/${pyodide_version}/pyodide-${pyodide_version}.tar.bz2" && \
wget -q "${pyodide_dist_url}" -O- | tar -xj -C /

# install node 20 (needed for async call support)
# install node 24 (needed for async call support and JSPI)
# and pthread-stubs for build, and unzip needed for chrome build to work
# xz is needed by emsdk to extract node tarballs
RUN conda install nodejs=20 unzip pthread-stubs make xz -c conda-forge
RUN conda install nodejs=24 unzip pthread-stubs make xz -c conda-forge

# install correct version of emscripten for this pyodide
COPY ci/scripts/install_emscripten.sh /arrow/ci/scripts/
Expand Down
5 changes: 3 additions & 2 deletions compose.yaml
Original file line numberDiff line numberDiff line change
Expand Up@@ -981,10 +981,11 @@ services:
arch_short: ${ARCH_SHORT}
clang_tools: ${CLANG_TOOLS}
llvm: ${LLVM}
pyodide_version: "0.26.0"
pyodide_version: "314.0.4"
pyodide_build_version: "0.39.0"
chrome_version: "latest"
selenium_version: "4.41.0"
required_python_min: "(3,12)"
required_python_min: "(3,14)"
python: ${PYTHON}
shm_size: *shm-size
volumes: *ubuntu-volumes
Expand Down
31 changes: 20 additions & 11 deletions cpp/cmake_modules/SetupCxxFlags.cmake
Original file line numberDiff line numberDiff line change
Expand Up@@ -719,26 +719,35 @@ if(MSVC)
endif()

if(CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
# flags are:
# For the Pyodide 2026_0 ABI, the flags are:
# 1) We force *everything* to build as position independent
# 2) And with support for C++ exceptions
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -fexceptions")
# 2) We support C++ WASM exceptions, using the native WebAssembly
# exception handling proposal and WebAssembly-based setjmp/longjmp
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -fwasm-exceptions -sSUPPORT_LONGJMP=wasm")
# deprecated-literal-operator error is thrown in datetime (vendored lib in arrow)
set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -fPIC -fexceptions -Wno-error=deprecated-literal-operator")
"${CMAKE_CXX_FLAGS} -fPIC -fwasm-exceptions -sSUPPORT_LONGJMP=wasm -Wno-error=deprecated-literal-operator"
)

# flags for creating shared libraries (only used in pyarrow, because
# Emscripten builds libarrow as static)
# flags are:
# 1) Tell it to use JavaScript / WebAssembly 64 bit number support.
# 2) Tell it to build with support for C++ exceptions
# 2) Tell it to build with support for C++ exceptions (see above)
# 3) Skip linker flags error which happens with -soname parameter
set(ARROW_EMSCRIPTEN_LINKER_FLAGS "-sWASM_BIGINT=1 -fexceptions -Wno-error=linkflags")
set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS
"-sSIDE_MODULE=1 ${ARROW_EMSCRIPTEN_LINKER_FLAGS}")
set(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS
"-sSIDE_MODULE=1 ${ARROW_EMSCRIPTEN_LINKER_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "-sSIDE_MODULE=1 ${ARROW_EMSCRIPTEN_LINKER_FLAGS}")
# 4) Record $ORIGIN as an RPATH, so that Pyodide can locate
# libarrow_python.so next to the extension modules needing it
# Note: the CMAKE_SHARED_LIBRARY_CREATE_<LANG>_FLAGS and
# CMAKE_SHARED_MODULE_CREATE_<LANG>_FLAGS variables are not used by the
# Ninja generator, so the flags must go through the linker-flags
# variables, which apply to SHARED (libarrow_python) and MODULE (Cython
# extension) targets respectively.
set(ARROW_EMSCRIPTEN_LINKER_FLAGS
"-sWASM_BIGINT=1 -fwasm-exceptions -sSUPPORT_LONGJMP=wasm -Wno-error=linkflags")
set(ARROW_EMSCRIPTEN_DYLIB_CREATE_FLAGS
"-sSIDE_MODULE=1 ${ARROW_EMSCRIPTEN_LINKER_FLAGS} '-Wl,-rpath,$ORIGIN'")
set(CMAKE_SHARED_LINKER_FLAGS "${ARROW_EMSCRIPTEN_DYLIB_CREATE_FLAGS}")
set(CMAKE_MODULE_LINKER_FLAGS "${ARROW_EMSCRIPTEN_DYLIB_CREATE_FLAGS}")
if(ARROW_TESTING)
# flags for building test executables for use in node
if("${UPPERCASE_BUILD_TYPE}" STREQUAL "RELEASE")
Expand Down
4 changes: 4 additions & 0 deletions cpp/cmake_modules/ThirdpartyToolchain.cmake
Original file line numberDiff line numberDiff line change
Expand Up@@ -2183,6 +2183,10 @@ function(build_protobuf)
set(PROTOBUF_HOST_CMAKE_ARGS
"-DCMAKE_CXX_FLAGS="
"-DCMAKE_C_FLAGS="
# Explicitly set the C++ standard for the host build. Without this,
# Abseil may be compiled with the host compiler's default standard,
# which can be older than C++17.
"-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
Comment on lines +2186 to +2189

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hope this change is fine to keep here; this happened to me because I am using AppleClang 21 on my macOS machine to cross-compile for Emscripten.

The reason is that in the host protoc build, where CMAKE_CXX_FLAGS is blanked and no standard is set, absl compiles as C++14 and uses absl::string_view. That results in an ABI mismatch because Protobuf's targets reference the std::string_view signatures (since Protobuf compiles to C++17 or newer).

(I guess no one has hit this before, since the CI job exercises going from Linux to Emscripten, where gcc defaults to C++17)

"-DCMAKE_INSTALL_PREFIX=${PROTOBUF_HOST_PREFIX}"
-Dprotobuf_BUILD_TESTS=OFF
-Dprotobuf_DEBUG_POSTFIX=
Expand Down
2 changes: 1 addition & 1 deletion dev/tasks/tasks.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -521,7 +521,7 @@ tasks:
params:
env:
UBUNTU: 22.04
PYTHON: 3.12
PYTHON: 3.14
image: conda-python-emscripten

test-conda-python-3.11-hypothesis:
Expand Down
4 changes: 2 additions & 2 deletions docs/source/developers/cpp/emscripten.rst
Original file line numberDiff line numberDiff line change
Expand Up@@ -34,9 +34,9 @@ activate it using the commands below (see https://emscripten.org/docs/getting_st
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
# replace <version> with the desired EMSDK version.
# e.g. for Pyodide 0.26, you need EMSDK version 3.1.58
# e.g. for Pyodide 314.0.x, you need EMSDK version 5.0.3
# the versions can be found in the Makefile.envs file in the Pyodide repo:
# https://github.com/pyodide/pyodide/blob/10b484cfe427e076c929a55dc35cfff01ea8d3bc/Makefile.envs
# https://github.com/pyodide/pyodide/blob/314.0.4/Makefile.envs
./emsdk install <version>
./emsdk activate <version>
source ./emsdk_env.sh
Expand Down
4 changes: 3 additions & 1 deletion python/CMakeLists.txt
Original file line numberDiff line numberDiff line change
Expand Up@@ -111,7 +111,9 @@ if("$ENV{CMAKE_EXPORT_COMPILE_COMMANDS}" STREQUAL "1")
set(CMAKE_EXPORT_COMPILE_COMMANDS 1)
endif()

if(UNIX)
# On Emscripten, the equivalent $ORIGIN runtime path is added
# through the linker flags in SetupCxxFlags.cmake instead
if(UNIX AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
# In the event that we are bundling the shared libraries (e.g. in a
# manylinux1 wheel), we need to set the RPATH of the extensions to the
Expand Down
9 changes: 8 additions & 1 deletion python/scripts/run_emscripten_tests.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -148,8 +148,14 @@ class NodeDriver:
import subprocess

def __init__(self, hostname, port):
# handle different syntax for util-linux script and macOS BSD-style script
if sys.platform == "darwin":
script_command = [shutil.which("script"), "-q", "/dev/null",
shutil.which("node")]
else:
script_command = [shutil.which("script"), "-c", shutil.which("node")]
self.process = subprocess.Popen(
[shutil.which("script"), "-c", shutil.which("node")],
script_command,
stdin=subprocess.PIPE,
shell=False,
bufsize=0,
Expand DownExpand Up@@ -320,6 +326,7 @@ def _load_pyarrow_in_runner(driver, wheel_name):
if "pyarrow" not in sys.modules:
await micropip.install("hypothesis")
import pyodide_js as pjs
await pjs.loadPackage("packaging")
await pjs.loadPackage("tzdata")
await pjs.loadPackage("numpy")
await pjs.loadPackage("pandas")
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length \u003e 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
9d4bf5a
Bump to Pyodide 0.28.1
agriyakhetarpal Aug 13, 2025
16f90d9
Bump Python version for conda-python-emscripten
agriyakhetarpal Aug 14, 2025
eebb7a8
Pass the right flag for WASM exception handling
agriyakhetarpal Aug 14, 2025
af2e18d
Install `libatomic1` for Pyodide Dockerfile
agriyakhetarpal Aug 14, 2025
41adbeb
Undo WASM EH flags as SjLj is enabled
agriyakhetarpal Aug 14, 2025
a89f7ec
Fix lint in Emscripten Dockerfile `apt-get` command
agriyakhetarpal Aug 14, 2025
20de7ad
Build static `libarrow_python` on Emscripten
agriyakhetarpal Aug 14, 2025
781b54a
Add Emscripten-specific flags for `_acero`
agriyakhetarpal Aug 14, 2025
f73c495
Fix CMake lint
agriyakhetarpal Aug 14, 2025
6ef7bb3
Revert "Fix CMake lint"
agriyakhetarpal Aug 14, 2025
18bf7d5
Revert "Add Emscripten-specific flags for `_acero`"
agriyakhetarpal Aug 14, 2025
eae25be
Revert "Build static `libarrow_python` on Emscripten"
agriyakhetarpal Aug 15, 2025
d279250
Merge main
agriyakhetarpal Aug 15, 2026
dc69985
Update to Python 3.14 and Pyodide 314.0.4
agriyakhetarpal Aug 15, 2026
89a6615
Use Pyodide 2026_0 ABI flags and set `RPATH` to `$ORIGIN`
agriyakhetarpal Aug 15, 2026
103bef4
`packaging` needed on Emscripten due to `pyarrow/tests/util.py`
agriyakhetarpal Aug 15, 2026
e62cf80
Add handling for Unix `script -c`/`script -q`
agriyakhetarpal Aug 15, 2026
b92772d
Fix Abseil ABI mismatch on linking with AppleClang
agriyakhetarpal Aug 15, 2026
ef4ecb6
Update to Node 24 in environment
agriyakhetarpal Aug 15, 2026
ff64e0d
Add separate pyodide-build version argument
agriyakhetarpal Aug 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 15 additions & 8 deletions ci/docker/conda-python-emscripten.dockerfile
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,32 +18,39 @@
ARG repo
ARG arch
ARG arch_short
ARG python="3.12"
ARG python="3.14"
FROM --platform=linux/${arch} ${repo}:${arch_short}-conda-python-${python}

ARG selenium_version="4.41.0"
ARG pyodide_version="0.26.0"
ARG pyodide_version="314.0.4"
# pyodide-build is versioned independently of Pyodide
ARG pyodide_build_version="0.39.0"
ARG chrome_version="latest"
ARG required_python_min="(3,12)"
# fail if python version < 3.12
ARG required_python_min="(3,14)"
# fail if python version < 3.14
RUN echo "check PYTHON>=${required_python_min}" && python -c "import sys;sys.exit(0 if sys.version_info>=${required_python_min} else 1)"

# install selenium and recent pyodide-build and recent python
RUN apt-get update -y -q && \
apt-get install -y -q --no-install-recommends \
libatomic1 && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

# needs to be a login shell so ~/.profile is read
SHELL ["/bin/bash", "--login", "-c", "-o", "pipefail"]

# install selenium and recent pyodide-build and recent python
RUN python -m pip install --no-cache-dir selenium==${selenium_version} && \
python -m pip install --no-cache-dir --upgrade pyodide-build>=${pyodide_version}
python -m pip install --no-cache-dir --upgrade "pyodide-build>=${pyodide_build_version}"

# install pyodide dist directory to /pyodide
RUN pyodide_dist_url="https://github.com/pyodide/pyodide/releases/download/${pyodide_version}/pyodide-${pyodide_version}.tar.bz2" && \
wget -q "${pyodide_dist_url}" -O- | tar -xj -C /

# install node 20 (needed for async call support)
# install node 24 (needed for async call support and JSPI)
# and pthread-stubs for build, and unzip needed for chrome build to work
# xz is needed by emsdk to extract node tarballs
RUN conda install nodejs=20 unzip pthread-stubs make xz -c conda-forge
RUN conda install nodejs=24 unzip pthread-stubs make xz -c conda-forge

# install correct version of emscripten for this pyodide
COPY ci/scripts/install_emscripten.sh /arrow/ci/scripts/
Expand Down
5 changes: 3 additions & 2 deletions compose.yaml
Original file line numberDiff line numberDiff line change
Expand Up@@ -981,10 +981,11 @@ services:
arch_short: ${ARCH_SHORT}
clang_tools: ${CLANG_TOOLS}
llvm: ${LLVM}
pyodide_version: "0.26.0"
pyodide_version: "314.0.4"
pyodide_build_version: "0.39.0"
chrome_version: "latest"
selenium_version: "4.41.0"
required_python_min: "(3,12)"
required_python_min: "(3,14)"
python: ${PYTHON}
shm_size: *shm-size
volumes: *ubuntu-volumes
Expand Down
31 changes: 20 additions & 11 deletions cpp/cmake_modules/SetupCxxFlags.cmake
Original file line numberDiff line numberDiff line change
Expand Up@@ -719,26 +719,35 @@ if(MSVC)
endif()

if(CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
# flags are:
# For the Pyodide 2026_0 ABI, the flags are:
# 1) We force *everything* to build as position independent
# 2) And with support for C++ exceptions
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -fexceptions")
# 2) We support C++ WASM exceptions, using the native WebAssembly
# exception handling proposal and WebAssembly-based setjmp/longjmp
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -fwasm-exceptions -sSUPPORT_LONGJMP=wasm")
# deprecated-literal-operator error is thrown in datetime (vendored lib in arrow)
set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -fPIC -fexceptions -Wno-error=deprecated-literal-operator")
"${CMAKE_CXX_FLAGS} -fPIC -fwasm-exceptions -sSUPPORT_LONGJMP=wasm -Wno-error=deprecated-literal-operator"
)

# flags for creating shared libraries (only used in pyarrow, because
# Emscripten builds libarrow as static)
# flags are:
# 1) Tell it to use JavaScript / WebAssembly 64 bit number support.
# 2) Tell it to build with support for C++ exceptions
# 2) Tell it to build with support for C++ exceptions (see above)
# 3) Skip linker flags error which happens with -soname parameter
set(ARROW_EMSCRIPTEN_LINKER_FLAGS "-sWASM_BIGINT=1 -fexceptions -Wno-error=linkflags")
set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS
"-sSIDE_MODULE=1 ${ARROW_EMSCRIPTEN_LINKER_FLAGS}")
set(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS
"-sSIDE_MODULE=1 ${ARROW_EMSCRIPTEN_LINKER_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "-sSIDE_MODULE=1 ${ARROW_EMSCRIPTEN_LINKER_FLAGS}")
# 4) Record $ORIGIN as an RPATH, so that Pyodide can locate
# libarrow_python.so next to the extension modules needing it
# Note: the CMAKE_SHARED_LIBRARY_CREATE_<LANG>_FLAGS and
# CMAKE_SHARED_MODULE_CREATE_<LANG>_FLAGS variables are not used by the
# Ninja generator, so the flags must go through the linker-flags
# variables, which apply to SHARED (libarrow_python) and MODULE (Cython
# extension) targets respectively.
set(ARROW_EMSCRIPTEN_LINKER_FLAGS
"-sWASM_BIGINT=1 -fwasm-exceptions -sSUPPORT_LONGJMP=wasm -Wno-error=linkflags")
set(ARROW_EMSCRIPTEN_DYLIB_CREATE_FLAGS
"-sSIDE_MODULE=1 ${ARROW_EMSCRIPTEN_LINKER_FLAGS} '-Wl,-rpath,$ORIGIN'")
set(CMAKE_SHARED_LINKER_FLAGS "${ARROW_EMSCRIPTEN_DYLIB_CREATE_FLAGS}")
set(CMAKE_MODULE_LINKER_FLAGS "${ARROW_EMSCRIPTEN_DYLIB_CREATE_FLAGS}")
if(ARROW_TESTING)
# flags for building test executables for use in node
if("${UPPERCASE_BUILD_TYPE}" STREQUAL "RELEASE")
Expand Down
4 changes: 4 additions & 0 deletions cpp/cmake_modules/ThirdpartyToolchain.cmake
Original file line numberDiff line numberDiff line change
Expand Up@@ -2183,6 +2183,10 @@ function(build_protobuf)
set(PROTOBUF_HOST_CMAKE_ARGS
"-DCMAKE_CXX_FLAGS="
"-DCMAKE_C_FLAGS="
# Explicitly set the C++ standard for the host build. Without this,
# Abseil may be compiled with the host compiler's default standard,
# which can be older than C++17.
"-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
Comment on lines +2186 to +2189

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hope this change is fine to keep here; this happened to me because I am using AppleClang 21 on my macOS machine to cross-compile for Emscripten.

The reason is that in the host protoc build, where CMAKE_CXX_FLAGS is blanked and no standard is set, absl compiles as C++14 and uses absl::string_view. That results in an ABI mismatch because Protobuf's targets reference the std::string_view signatures (since Protobuf compiles to C++17 or newer).

(I guess no one has hit this before, since the CI job exercises going from Linux to Emscripten, where gcc defaults to C++17)

"-DCMAKE_INSTALL_PREFIX=${PROTOBUF_HOST_PREFIX}"
-Dprotobuf_BUILD_TESTS=OFF
-Dprotobuf_DEBUG_POSTFIX=
Expand Down
2 changes: 1 addition & 1 deletion dev/tasks/tasks.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -521,7 +521,7 @@ tasks:
params:
env:
UBUNTU: 22.04
PYTHON: 3.12
PYTHON: 3.14
image: conda-python-emscripten

test-conda-python-3.11-hypothesis:
Expand Down
4 changes: 2 additions & 2 deletions docs/source/developers/cpp/emscripten.rst
Original file line numberDiff line numberDiff line change
Expand Up@@ -34,9 +34,9 @@ activate it using the commands below (see https://emscripten.org/docs/getting_st
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
# replace <version> with the desired EMSDK version.
# e.g. for Pyodide 0.26, you need EMSDK version 3.1.58
# e.g. for Pyodide 314.0.x, you need EMSDK version 5.0.3
# the versions can be found in the Makefile.envs file in the Pyodide repo:
# https://github.com/pyodide/pyodide/blob/10b484cfe427e076c929a55dc35cfff01ea8d3bc/Makefile.envs
# https://github.com/pyodide/pyodide/blob/314.0.4/Makefile.envs
./emsdk install <version>
./emsdk activate <version>
source ./emsdk_env.sh
Expand Down
4 changes: 3 additions & 1 deletion python/CMakeLists.txt
Original file line numberDiff line numberDiff line change
Expand Up@@ -111,7 +111,9 @@ if("$ENV{CMAKE_EXPORT_COMPILE_COMMANDS}" STREQUAL "1")
set(CMAKE_EXPORT_COMPILE_COMMANDS 1)
endif()

if(UNIX)
# On Emscripten, the equivalent $ORIGIN runtime path is added
# through the linker flags in SetupCxxFlags.cmake instead
if(UNIX AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
# In the event that we are bundling the shared libraries (e.g. in a
# manylinux1 wheel), we need to set the RPATH of the extensions to the
Expand Down
9 changes: 8 additions & 1 deletion python/scripts/run_emscripten_tests.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -148,8 +148,14 @@ class NodeDriver:
import subprocess

def __init__(self, hostname, port):
# handle different syntax for util-linux script and macOS BSD-style script
if sys.platform == "darwin":
script_command = [shutil.which("script"), "-q", "/dev/null",
shutil.which("node")]
else:
script_command = [shutil.which("script"), "-c", shutil.which("node")]
self.process = subprocess.Popen(
[shutil.which("script"), "-c", shutil.which("node")],
script_command,
stdin=subprocess.PIPE,
shell=False,
bufsize=0,
Expand DownExpand Up@@ -320,6 +326,7 @@ def _load_pyarrow_in_runner(driver, wheel_name):
if "pyarrow" not in sys.modules:
await micropip.install("hypothesis")
import pyodide_js as pjs
await pjs.loadPackage("packaging")
await pjs.loadPackage("tzdata")
await pjs.loadPackage("numpy")
await pjs.loadPackage("pandas")
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
9d4bf5a
Bump to Pyodide 0.28.1
agriyakhetarpal Aug 13, 2025
16f90d9
Bump Python version for conda-python-emscripten
agriyakhetarpal Aug 14, 2025
eebb7a8
Pass the right flag for WASM exception handling
agriyakhetarpal Aug 14, 2025
af2e18d
Install `libatomic1` for Pyodide Dockerfile
agriyakhetarpal Aug 14, 2025
41adbeb
Undo WASM EH flags as SjLj is enabled
agriyakhetarpal Aug 14, 2025
a89f7ec
Fix lint in Emscripten Dockerfile `apt-get` command
agriyakhetarpal Aug 14, 2025
20de7ad
Build static `libarrow_python` on Emscripten
agriyakhetarpal Aug 14, 2025
781b54a
Add Emscripten-specific flags for `_acero`
agriyakhetarpal Aug 14, 2025
f73c495
Fix CMake lint
agriyakhetarpal Aug 14, 2025
6ef7bb3
Revert "Fix CMake lint"
agriyakhetarpal Aug 14, 2025
18bf7d5
Revert "Add Emscripten-specific flags for `_acero`"
agriyakhetarpal Aug 14, 2025
eae25be
Revert "Build static `libarrow_python` on Emscripten"
agriyakhetarpal Aug 15, 2025
d279250
Merge main
agriyakhetarpal Aug 15, 2026
dc69985
Update to Python 3.14 and Pyodide 314.0.4
agriyakhetarpal Aug 15, 2026
89a6615
Use Pyodide 2026_0 ABI flags and set `RPATH` to `$ORIGIN`
agriyakhetarpal Aug 15, 2026
103bef4
`packaging` needed on Emscripten due to `pyarrow/tests/util.py`
agriyakhetarpal Aug 15, 2026
e62cf80
Add handling for Unix `script -c`/`script -q`
agriyakhetarpal Aug 15, 2026
b92772d
Fix Abseil ABI mismatch on linking with AppleClang
agriyakhetarpal Aug 15, 2026
ef4ecb6
Update to Node 24 in environment
agriyakhetarpal Aug 15, 2026
ff64e0d
Add separate pyodide-build version argument
agriyakhetarpal Aug 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 15 additions & 8 deletions ci/docker/conda-python-emscripten.dockerfile
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,32 +18,39 @@
ARG repo
ARG arch
ARG arch_short
ARG python="3.12"
ARG python="3.14"
FROM --platform=linux/${arch} ${repo}:${arch_short}-conda-python-${python}

ARG selenium_version="4.41.0"
ARG pyodide_version="0.26.0"
ARG pyodide_version="314.0.4"
# pyodide-build is versioned independently of Pyodide
ARG pyodide_build_version="0.39.0"
ARG chrome_version="latest"
ARG required_python_min="(3,12)"
# fail if python version < 3.12
ARG required_python_min="(3,14)"
# fail if python version < 3.14
RUN echo "check PYTHON>=${required_python_min}" && python -c "import sys;sys.exit(0 if sys.version_info>=${required_python_min} else 1)"

# install selenium and recent pyodide-build and recent python
RUN apt-get update -y -q && \
apt-get install -y -q --no-install-recommends \
libatomic1 && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

# needs to be a login shell so ~/.profile is read
SHELL ["/bin/bash", "--login", "-c", "-o", "pipefail"]

# install selenium and recent pyodide-build and recent python
RUN python -m pip install --no-cache-dir selenium==${selenium_version} && \
python -m pip install --no-cache-dir --upgrade pyodide-build>=${pyodide_version}
python -m pip install --no-cache-dir --upgrade "pyodide-build>=${pyodide_build_version}"

# install pyodide dist directory to /pyodide
RUN pyodide_dist_url="https://github.com/pyodide/pyodide/releases/download/${pyodide_version}/pyodide-${pyodide_version}.tar.bz2" && \
wget -q "${pyodide_dist_url}" -O- | tar -xj -C /

# install node 20 (needed for async call support)
# install node 24 (needed for async call support and JSPI)
# and pthread-stubs for build, and unzip needed for chrome build to work
# xz is needed by emsdk to extract node tarballs
RUN conda install nodejs=20 unzip pthread-stubs make xz -c conda-forge
RUN conda install nodejs=24 unzip pthread-stubs make xz -c conda-forge

# install correct version of emscripten for this pyodide
COPY ci/scripts/install_emscripten.sh /arrow/ci/scripts/
Expand Down
5 changes: 3 additions & 2 deletions compose.yaml
Original file line numberDiff line numberDiff line change
Expand Up@@ -981,10 +981,11 @@ services:
arch_short: ${ARCH_SHORT}
clang_tools: ${CLANG_TOOLS}
llvm: ${LLVM}
pyodide_version: "0.26.0"
pyodide_version: "314.0.4"
pyodide_build_version: "0.39.0"
chrome_version: "latest"
selenium_version: "4.41.0"
required_python_min: "(3,12)"
required_python_min: "(3,14)"
python: ${PYTHON}
shm_size: *shm-size
volumes: *ubuntu-volumes
Expand Down
31 changes: 20 additions & 11 deletions cpp/cmake_modules/SetupCxxFlags.cmake
Original file line numberDiff line numberDiff line change
Expand Up@@ -719,26 +719,35 @@ if(MSVC)
endif()

if(CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
# flags are:
# For the Pyodide 2026_0 ABI, the flags are:
# 1) We force *everything* to build as position independent
# 2) And with support for C++ exceptions
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -fexceptions")
# 2) We support C++ WASM exceptions, using the native WebAssembly
# exception handling proposal and WebAssembly-based setjmp/longjmp
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -fwasm-exceptions -sSUPPORT_LONGJMP=wasm")
# deprecated-literal-operator error is thrown in datetime (vendored lib in arrow)
set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -fPIC -fexceptions -Wno-error=deprecated-literal-operator")
"${CMAKE_CXX_FLAGS} -fPIC -fwasm-exceptions -sSUPPORT_LONGJMP=wasm -Wno-error=deprecated-literal-operator"
)

# flags for creating shared libraries (only used in pyarrow, because
# Emscripten builds libarrow as static)
# flags are:
# 1) Tell it to use JavaScript / WebAssembly 64 bit number support.
# 2) Tell it to build with support for C++ exceptions
# 2) Tell it to build with support for C++ exceptions (see above)
# 3) Skip linker flags error which happens with -soname parameter
set(ARROW_EMSCRIPTEN_LINKER_FLAGS "-sWASM_BIGINT=1 -fexceptions -Wno-error=linkflags")
set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS
"-sSIDE_MODULE=1 ${ARROW_EMSCRIPTEN_LINKER_FLAGS}")
set(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS
"-sSIDE_MODULE=1 ${ARROW_EMSCRIPTEN_LINKER_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "-sSIDE_MODULE=1 ${ARROW_EMSCRIPTEN_LINKER_FLAGS}")
# 4) Record $ORIGIN as an RPATH, so that Pyodide can locate
# libarrow_python.so next to the extension modules needing it
# Note: the CMAKE_SHARED_LIBRARY_CREATE_<LANG>_FLAGS and
# CMAKE_SHARED_MODULE_CREATE_<LANG>_FLAGS variables are not used by the
# Ninja generator, so the flags must go through the linker-flags
# variables, which apply to SHARED (libarrow_python) and MODULE (Cython
# extension) targets respectively.
set(ARROW_EMSCRIPTEN_LINKER_FLAGS
"-sWASM_BIGINT=1 -fwasm-exceptions -sSUPPORT_LONGJMP=wasm -Wno-error=linkflags")
set(ARROW_EMSCRIPTEN_DYLIB_CREATE_FLAGS
"-sSIDE_MODULE=1 ${ARROW_EMSCRIPTEN_LINKER_FLAGS} '-Wl,-rpath,$ORIGIN'")
set(CMAKE_SHARED_LINKER_FLAGS "${ARROW_EMSCRIPTEN_DYLIB_CREATE_FLAGS}")
set(CMAKE_MODULE_LINKER_FLAGS "${ARROW_EMSCRIPTEN_DYLIB_CREATE_FLAGS}")
if(ARROW_TESTING)
# flags for building test executables for use in node
if("${UPPERCASE_BUILD_TYPE}" STREQUAL "RELEASE")
Expand Down
4 changes: 4 additions & 0 deletions cpp/cmake_modules/ThirdpartyToolchain.cmake
Original file line numberDiff line numberDiff line change
Expand Up@@ -2183,6 +2183,10 @@ function(build_protobuf)
set(PROTOBUF_HOST_CMAKE_ARGS
"-DCMAKE_CXX_FLAGS="
"-DCMAKE_C_FLAGS="
# Explicitly set the C++ standard for the host build. Without this,
# Abseil may be compiled with the host compiler's default standard,
# which can be older than C++17.
"-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
Comment on lines +2186 to +2189

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hope this change is fine to keep here; this happened to me because I am using AppleClang 21 on my macOS machine to cross-compile for Emscripten.

The reason is that in the host protoc build, where CMAKE_CXX_FLAGS is blanked and no standard is set, absl compiles as C++14 and uses absl::string_view. That results in an ABI mismatch because Protobuf's targets reference the std::string_view signatures (since Protobuf compiles to C++17 or newer).

(I guess no one has hit this before, since the CI job exercises going from Linux to Emscripten, where gcc defaults to C++17)

"-DCMAKE_INSTALL_PREFIX=${PROTOBUF_HOST_PREFIX}"
-Dprotobuf_BUILD_TESTS=OFF
-Dprotobuf_DEBUG_POSTFIX=
Expand Down
2 changes: 1 addition & 1 deletion dev/tasks/tasks.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -521,7 +521,7 @@ tasks:
params:
env:
UBUNTU: 22.04
PYTHON: 3.12
PYTHON: 3.14
image: conda-python-emscripten

test-conda-python-3.11-hypothesis:
Expand Down
4 changes: 2 additions & 2 deletions docs/source/developers/cpp/emscripten.rst
Original file line numberDiff line numberDiff line change
Expand Up@@ -34,9 +34,9 @@ activate it using the commands below (see https://emscripten.org/docs/getting_st
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
# replace <version> with the desired EMSDK version.
# e.g. for Pyodide 0.26, you need EMSDK version 3.1.58
# e.g. for Pyodide 314.0.x, you need EMSDK version 5.0.3
# the versions can be found in the Makefile.envs file in the Pyodide repo:
# https://github.com/pyodide/pyodide/blob/10b484cfe427e076c929a55dc35cfff01ea8d3bc/Makefile.envs
# https://github.com/pyodide/pyodide/blob/314.0.4/Makefile.envs
./emsdk install <version>
./emsdk activate <version>
source ./emsdk_env.sh
Expand Down
4 changes: 3 additions & 1 deletion python/CMakeLists.txt
Original file line numberDiff line numberDiff line change
Expand Up@@ -111,7 +111,9 @@ if("$ENV{CMAKE_EXPORT_COMPILE_COMMANDS}" STREQUAL "1")
set(CMAKE_EXPORT_COMPILE_COMMANDS 1)
endif()

if(UNIX)
# On Emscripten, the equivalent $ORIGIN runtime path is added
# through the linker flags in SetupCxxFlags.cmake instead
if(UNIX AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
# In the event that we are bundling the shared libraries (e.g. in a
# manylinux1 wheel), we need to set the RPATH of the extensions to the
Expand Down
9 changes: 8 additions & 1 deletion python/scripts/run_emscripten_tests.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -148,8 +148,14 @@ class NodeDriver:
import subprocess

def __init__(self, hostname, port):
# handle different syntax for util-linux script and macOS BSD-style script
if sys.platform == "darwin":
script_command = [shutil.which("script"), "-q", "/dev/null",
shutil.which("node")]
else:
script_command = [shutil.which("script"), "-c", shutil.which("node")]
self.process = subprocess.Popen(
[shutil.which("script"), "-c", shutil.which("node")],
script_command,
stdin=subprocess.PIPE,
shell=False,
bufsize=0,
Expand DownExpand Up@@ -320,6 +326,7 @@ def _load_pyarrow_in_runner(driver, wheel_name):
if "pyarrow" not in sys.modules:
await micropip.install("hypothesis")
import pyodide_js as pjs
await pjs.loadPackage("packaging")
await pjs.loadPackage("tzdata")
await pjs.loadPackage("numpy")
await pjs.loadPackage("pandas")
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
9d4bf5a
Bump to Pyodide 0.28.1
agriyakhetarpal Aug 13, 2025
16f90d9
Bump Python version for conda-python-emscripten
agriyakhetarpal Aug 14, 2025
eebb7a8
Pass the right flag for WASM exception handling
agriyakhetarpal Aug 14, 2025
af2e18d
Install `libatomic1` for Pyodide Dockerfile
agriyakhetarpal Aug 14, 2025
41adbeb
Undo WASM EH flags as SjLj is enabled
agriyakhetarpal Aug 14, 2025
a89f7ec
Fix lint in Emscripten Dockerfile `apt-get` command
agriyakhetarpal Aug 14, 2025
20de7ad
Build static `libarrow_python` on Emscripten
agriyakhetarpal Aug 14, 2025
781b54a
Add Emscripten-specific flags for `_acero`
agriyakhetarpal Aug 14, 2025
f73c495
Fix CMake lint
agriyakhetarpal Aug 14, 2025
6ef7bb3
Revert "Fix CMake lint"
agriyakhetarpal Aug 14, 2025
18bf7d5
Revert "Add Emscripten-specific flags for `_acero`"
agriyakhetarpal Aug 14, 2025
eae25be
Revert "Build static `libarrow_python` on Emscripten"
agriyakhetarpal Aug 15, 2025
d279250
Merge main
agriyakhetarpal Aug 15, 2026
dc69985
Update to Python 3.14 and Pyodide 314.0.4
agriyakhetarpal Aug 15, 2026
89a6615
Use Pyodide 2026_0 ABI flags and set `RPATH` to `$ORIGIN`
agriyakhetarpal Aug 15, 2026
103bef4
`packaging` needed on Emscripten due to `pyarrow/tests/util.py`
agriyakhetarpal Aug 15, 2026
e62cf80
Add handling for Unix `script -c`/`script -q`
agriyakhetarpal Aug 15, 2026
b92772d
Fix Abseil ABI mismatch on linking with AppleClang
agriyakhetarpal Aug 15, 2026
ef4ecb6
Update to Node 24 in environment
agriyakhetarpal Aug 15, 2026
ff64e0d
Add separate pyodide-build version argument
agriyakhetarpal Aug 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 15 additions & 8 deletions ci/docker/conda-python-emscripten.dockerfile
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,32 +18,39 @@
ARG repo
ARG arch
ARG arch_short
ARG python="3.12"
ARG python="3.14"
FROM --platform=linux/${arch} ${repo}:${arch_short}-conda-python-${python}

ARG selenium_version="4.41.0"
ARG pyodide_version="0.26.0"
ARG pyodide_version="314.0.4"
# pyodide-build is versioned independently of Pyodide
ARG pyodide_build_version="0.39.0"
ARG chrome_version="latest"
ARG required_python_min="(3,12)"
# fail if python version < 3.12
ARG required_python_min="(3,14)"
# fail if python version < 3.14
RUN echo "check PYTHON>=${required_python_min}" && python -c "import sys;sys.exit(0 if sys.version_info>=${required_python_min} else 1)"

# install selenium and recent pyodide-build and recent python
RUN apt-get update -y -q && \
apt-get install -y -q --no-install-recommends \
libatomic1 && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

# needs to be a login shell so ~/.profile is read
SHELL ["/bin/bash", "--login", "-c", "-o", "pipefail"]

# install selenium and recent pyodide-build and recent python
RUN python -m pip install --no-cache-dir selenium==${selenium_version} && \
python -m pip install --no-cache-dir --upgrade pyodide-build>=${pyodide_version}
python -m pip install --no-cache-dir --upgrade "pyodide-build>=${pyodide_build_version}"

# install pyodide dist directory to /pyodide
RUN pyodide_dist_url="https://github.com/pyodide/pyodide/releases/download/${pyodide_version}/pyodide-${pyodide_version}.tar.bz2" && \
wget -q "${pyodide_dist_url}" -O- | tar -xj -C /

# install node 20 (needed for async call support)
# install node 24 (needed for async call support and JSPI)
# and pthread-stubs for build, and unzip needed for chrome build to work
# xz is needed by emsdk to extract node tarballs
RUN conda install nodejs=20 unzip pthread-stubs make xz -c conda-forge
RUN conda install nodejs=24 unzip pthread-stubs make xz -c conda-forge

# install correct version of emscripten for this pyodide
COPY ci/scripts/install_emscripten.sh /arrow/ci/scripts/
Expand Down
5 changes: 3 additions & 2 deletions compose.yaml
Original file line numberDiff line numberDiff line change
Expand Up@@ -981,10 +981,11 @@ services:
arch_short: ${ARCH_SHORT}
clang_tools: ${CLANG_TOOLS}
llvm: ${LLVM}
pyodide_version: "0.26.0"
pyodide_version: "314.0.4"
pyodide_build_version: "0.39.0"
chrome_version: "latest"
selenium_version: "4.41.0"
required_python_min: "(3,12)"
required_python_min: "(3,14)"
python: ${PYTHON}
shm_size: *shm-size
volumes: *ubuntu-volumes
Expand Down
31 changes: 20 additions & 11 deletions cpp/cmake_modules/SetupCxxFlags.cmake
Original file line numberDiff line numberDiff line change
Expand Up@@ -719,26 +719,35 @@ if(MSVC)
endif()

if(CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
# flags are:
# For the Pyodide 2026_0 ABI, the flags are:
# 1) We force *everything* to build as position independent
# 2) And with support for C++ exceptions
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -fexceptions")
# 2) We support C++ WASM exceptions, using the native WebAssembly
# exception handling proposal and WebAssembly-based setjmp/longjmp
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -fwasm-exceptions -sSUPPORT_LONGJMP=wasm")
# deprecated-literal-operator error is thrown in datetime (vendored lib in arrow)
set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -fPIC -fexceptions -Wno-error=deprecated-literal-operator")
"${CMAKE_CXX_FLAGS} -fPIC -fwasm-exceptions -sSUPPORT_LONGJMP=wasm -Wno-error=deprecated-literal-operator"
)

# flags for creating shared libraries (only used in pyarrow, because
# Emscripten builds libarrow as static)
# flags are:
# 1) Tell it to use JavaScript / WebAssembly 64 bit number support.
# 2) Tell it to build with support for C++ exceptions
# 2) Tell it to build with support for C++ exceptions (see above)
# 3) Skip linker flags error which happens with -soname parameter
set(ARROW_EMSCRIPTEN_LINKER_FLAGS "-sWASM_BIGINT=1 -fexceptions -Wno-error=linkflags")
set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS
"-sSIDE_MODULE=1 ${ARROW_EMSCRIPTEN_LINKER_FLAGS}")
set(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS
"-sSIDE_MODULE=1 ${ARROW_EMSCRIPTEN_LINKER_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "-sSIDE_MODULE=1 ${ARROW_EMSCRIPTEN_LINKER_FLAGS}")
# 4) Record $ORIGIN as an RPATH, so that Pyodide can locate
# libarrow_python.so next to the extension modules needing it
# Note: the CMAKE_SHARED_LIBRARY_CREATE_<LANG>_FLAGS and
# CMAKE_SHARED_MODULE_CREATE_<LANG>_FLAGS variables are not used by the
# Ninja generator, so the flags must go through the linker-flags
# variables, which apply to SHARED (libarrow_python) and MODULE (Cython
# extension) targets respectively.
set(ARROW_EMSCRIPTEN_LINKER_FLAGS
"-sWASM_BIGINT=1 -fwasm-exceptions -sSUPPORT_LONGJMP=wasm -Wno-error=linkflags")
set(ARROW_EMSCRIPTEN_DYLIB_CREATE_FLAGS
"-sSIDE_MODULE=1 ${ARROW_EMSCRIPTEN_LINKER_FLAGS} '-Wl,-rpath,$ORIGIN'")
set(CMAKE_SHARED_LINKER_FLAGS "${ARROW_EMSCRIPTEN_DYLIB_CREATE_FLAGS}")
set(CMAKE_MODULE_LINKER_FLAGS "${ARROW_EMSCRIPTEN_DYLIB_CREATE_FLAGS}")
if(ARROW_TESTING)
# flags for building test executables for use in node
if("${UPPERCASE_BUILD_TYPE}" STREQUAL "RELEASE")
Expand Down
4 changes: 4 additions & 0 deletions cpp/cmake_modules/ThirdpartyToolchain.cmake
Original file line numberDiff line numberDiff line change
Expand Up@@ -2183,6 +2183,10 @@ function(build_protobuf)
set(PROTOBUF_HOST_CMAKE_ARGS
"-DCMAKE_CXX_FLAGS="
"-DCMAKE_C_FLAGS="
# Explicitly set the C++ standard for the host build. Without this,
# Abseil may be compiled with the host compiler's default standard,
# which can be older than C++17.
"-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
Comment on lines +2186 to +2189

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hope this change is fine to keep here; this happened to me because I am using AppleClang 21 on my macOS machine to cross-compile for Emscripten.

The reason is that in the host protoc build, where CMAKE_CXX_FLAGS is blanked and no standard is set, absl compiles as C++14 and uses absl::string_view. That results in an ABI mismatch because Protobuf's targets reference the std::string_view signatures (since Protobuf compiles to C++17 or newer).

(I guess no one has hit this before, since the CI job exercises going from Linux to Emscripten, where gcc defaults to C++17)

"-DCMAKE_INSTALL_PREFIX=${PROTOBUF_HOST_PREFIX}"
-Dprotobuf_BUILD_TESTS=OFF
-Dprotobuf_DEBUG_POSTFIX=
Expand Down
2 changes: 1 addition & 1 deletion dev/tasks/tasks.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -521,7 +521,7 @@ tasks:
params:
env:
UBUNTU: 22.04
PYTHON: 3.12
PYTHON: 3.14
image: conda-python-emscripten

test-conda-python-3.11-hypothesis:
Expand Down
4 changes: 2 additions & 2 deletions docs/source/developers/cpp/emscripten.rst
Original file line numberDiff line numberDiff line change
Expand Up@@ -34,9 +34,9 @@ activate it using the commands below (see https://emscripten.org/docs/getting_st
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
# replace <version> with the desired EMSDK version.
# e.g. for Pyodide 0.26, you need EMSDK version 3.1.58
# e.g. for Pyodide 314.0.x, you need EMSDK version 5.0.3
# the versions can be found in the Makefile.envs file in the Pyodide repo:
# https://github.com/pyodide/pyodide/blob/10b484cfe427e076c929a55dc35cfff01ea8d3bc/Makefile.envs
# https://github.com/pyodide/pyodide/blob/314.0.4/Makefile.envs
./emsdk install <version>
./emsdk activate <version>
source ./emsdk_env.sh
Expand Down
4 changes: 3 additions & 1 deletion python/CMakeLists.txt
Original file line numberDiff line numberDiff line change
Expand Up@@ -111,7 +111,9 @@ if("$ENV{CMAKE_EXPORT_COMPILE_COMMANDS}" STREQUAL "1")
set(CMAKE_EXPORT_COMPILE_COMMANDS 1)
endif()

if(UNIX)
# On Emscripten, the equivalent $ORIGIN runtime path is added
# through the linker flags in SetupCxxFlags.cmake instead
if(UNIX AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
# In the event that we are bundling the shared libraries (e.g. in a
# manylinux1 wheel), we need to set the RPATH of the extensions to the
Expand Down
9 changes: 8 additions & 1 deletion python/scripts/run_emscripten_tests.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -148,8 +148,14 @@ class NodeDriver:
import subprocess

def __init__(self, hostname, port):
# handle different syntax for util-linux script and macOS BSD-style script
if sys.platform == "darwin":
script_command = [shutil.which("script"), "-q", "/dev/null",
shutil.which("node")]
else:
script_command = [shutil.which("script"), "-c", shutil.which("node")]
self.process = subprocess.Popen(
[shutil.which("script"), "-c", shutil.which("node")],
script_command,
stdin=subprocess.PIPE,
shell=False,
bufsize=0,
Expand DownExpand Up@@ -320,6 +326,7 @@ def _load_pyarrow_in_runner(driver, wheel_name):
if "pyarrow" not in sys.modules:
await micropip.install("hypothesis")
import pyodide_js as pjs
await pjs.loadPackage("packaging")
await pjs.loadPackage("tzdata")
await pjs.loadPackage("numpy")
await pjs.loadPackage("pandas")
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
9d4bf5a
Bump to Pyodide 0.28.1
agriyakhetarpal Aug 13, 2025
16f90d9
Bump Python version for conda-python-emscripten
agriyakhetarpal Aug 14, 2025
eebb7a8
Pass the right flag for WASM exception handling
agriyakhetarpal Aug 14, 2025
af2e18d
Install `libatomic1` for Pyodide Dockerfile
agriyakhetarpal Aug 14, 2025
41adbeb
Undo WASM EH flags as SjLj is enabled
agriyakhetarpal Aug 14, 2025
a89f7ec
Fix lint in Emscripten Dockerfile `apt-get` command
agriyakhetarpal Aug 14, 2025
20de7ad
Build static `libarrow_python` on Emscripten
agriyakhetarpal Aug 14, 2025
781b54a
Add Emscripten-specific flags for `_acero`
agriyakhetarpal Aug 14, 2025
f73c495
Fix CMake lint
agriyakhetarpal Aug 14, 2025
6ef7bb3
Revert "Fix CMake lint"
agriyakhetarpal Aug 14, 2025
18bf7d5
Revert "Add Emscripten-specific flags for `_acero`"
agriyakhetarpal Aug 14, 2025
eae25be
Revert "Build static `libarrow_python` on Emscripten"
agriyakhetarpal Aug 15, 2025
d279250
Merge main
agriyakhetarpal Aug 15, 2026
dc69985
Update to Python 3.14 and Pyodide 314.0.4
agriyakhetarpal Aug 15, 2026
89a6615
Use Pyodide 2026_0 ABI flags and set `RPATH` to `$ORIGIN`
agriyakhetarpal Aug 15, 2026
103bef4
`packaging` needed on Emscripten due to `pyarrow/tests/util.py`
agriyakhetarpal Aug 15, 2026
e62cf80
Add handling for Unix `script -c`/`script -q`
agriyakhetarpal Aug 15, 2026
b92772d
Fix Abseil ABI mismatch on linking with AppleClang
agriyakhetarpal Aug 15, 2026
ef4ecb6
Update to Node 24 in environment
agriyakhetarpal Aug 15, 2026
ff64e0d
Add separate pyodide-build version argument
agriyakhetarpal Aug 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 15 additions & 8 deletions ci/docker/conda-python-emscripten.dockerfile
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,32 +18,39 @@
ARG repo
ARG arch
ARG arch_short
ARG python="3.12"
ARG python="3.14"
FROM --platform=linux/${arch} ${repo}:${arch_short}-conda-python-${python}

ARG selenium_version="4.41.0"
ARG pyodide_version="0.26.0"
ARG pyodide_version="314.0.4"
# pyodide-build is versioned independently of Pyodide
ARG pyodide_build_version="0.39.0"
ARG chrome_version="latest"
ARG required_python_min="(3,12)"
# fail if python version < 3.12
ARG required_python_min="(3,14)"
# fail if python version < 3.14
RUN echo "check PYTHON>=${required_python_min}" && python -c "import sys;sys.exit(0 if sys.version_info>=${required_python_min} else 1)"

# install selenium and recent pyodide-build and recent python
RUN apt-get update -y -q && \
apt-get install -y -q --no-install-recommends \
libatomic1 && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

# needs to be a login shell so ~/.profile is read
SHELL ["/bin/bash", "--login", "-c", "-o", "pipefail"]

# install selenium and recent pyodide-build and recent python
RUN python -m pip install --no-cache-dir selenium==${selenium_version} && \
python -m pip install --no-cache-dir --upgrade pyodide-build>=${pyodide_version}
python -m pip install --no-cache-dir --upgrade "pyodide-build>=${pyodide_build_version}"

# install pyodide dist directory to /pyodide
RUN pyodide_dist_url="https://github.com/pyodide/pyodide/releases/download/${pyodide_version}/pyodide-${pyodide_version}.tar.bz2" && \
wget -q "${pyodide_dist_url}" -O- | tar -xj -C /

# install node 20 (needed for async call support)
# install node 24 (needed for async call support and JSPI)
# and pthread-stubs for build, and unzip needed for chrome build to work
# xz is needed by emsdk to extract node tarballs
RUN conda install nodejs=20 unzip pthread-stubs make xz -c conda-forge
RUN conda install nodejs=24 unzip pthread-stubs make xz -c conda-forge

# install correct version of emscripten for this pyodide
COPY ci/scripts/install_emscripten.sh /arrow/ci/scripts/
Expand Down
5 changes: 3 additions & 2 deletions compose.yaml
Original file line numberDiff line numberDiff line change
Expand Up@@ -981,10 +981,11 @@ services:
arch_short: ${ARCH_SHORT}
clang_tools: ${CLANG_TOOLS}
llvm: ${LLVM}
pyodide_version: "0.26.0"
pyodide_version: "314.0.4"
pyodide_build_version: "0.39.0"
chrome_version: "latest"
selenium_version: "4.41.0"
required_python_min: "(3,12)"
required_python_min: "(3,14)"
python: ${PYTHON}
shm_size: *shm-size
volumes: *ubuntu-volumes
Expand Down
31 changes: 20 additions & 11 deletions cpp/cmake_modules/SetupCxxFlags.cmake
Original file line numberDiff line numberDiff line change
Expand Up@@ -719,26 +719,35 @@ if(MSVC)
endif()

if(CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
# flags are:
# For the Pyodide 2026_0 ABI, the flags are:
# 1) We force *everything* to build as position independent
# 2) And with support for C++ exceptions
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -fexceptions")
# 2) We support C++ WASM exceptions, using the native WebAssembly
# exception handling proposal and WebAssembly-based setjmp/longjmp
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -fwasm-exceptions -sSUPPORT_LONGJMP=wasm")
# deprecated-literal-operator error is thrown in datetime (vendored lib in arrow)
set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -fPIC -fexceptions -Wno-error=deprecated-literal-operator")
"${CMAKE_CXX_FLAGS} -fPIC -fwasm-exceptions -sSUPPORT_LONGJMP=wasm -Wno-error=deprecated-literal-operator"
)

# flags for creating shared libraries (only used in pyarrow, because
# Emscripten builds libarrow as static)
# flags are:
# 1) Tell it to use JavaScript / WebAssembly 64 bit number support.
# 2) Tell it to build with support for C++ exceptions
# 2) Tell it to build with support for C++ exceptions (see above)
# 3) Skip linker flags error which happens with -soname parameter
set(ARROW_EMSCRIPTEN_LINKER_FLAGS "-sWASM_BIGINT=1 -fexceptions -Wno-error=linkflags")
set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS
"-sSIDE_MODULE=1 ${ARROW_EMSCRIPTEN_LINKER_FLAGS}")
set(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS
"-sSIDE_MODULE=1 ${ARROW_EMSCRIPTEN_LINKER_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "-sSIDE_MODULE=1 ${ARROW_EMSCRIPTEN_LINKER_FLAGS}")
# 4) Record $ORIGIN as an RPATH, so that Pyodide can locate
# libarrow_python.so next to the extension modules needing it
# Note: the CMAKE_SHARED_LIBRARY_CREATE_<LANG>_FLAGS and
# CMAKE_SHARED_MODULE_CREATE_<LANG>_FLAGS variables are not used by the
# Ninja generator, so the flags must go through the linker-flags
# variables, which apply to SHARED (libarrow_python) and MODULE (Cython
# extension) targets respectively.
set(ARROW_EMSCRIPTEN_LINKER_FLAGS
"-sWASM_BIGINT=1 -fwasm-exceptions -sSUPPORT_LONGJMP=wasm -Wno-error=linkflags")
set(ARROW_EMSCRIPTEN_DYLIB_CREATE_FLAGS
"-sSIDE_MODULE=1 ${ARROW_EMSCRIPTEN_LINKER_FLAGS} '-Wl,-rpath,$ORIGIN'")
set(CMAKE_SHARED_LINKER_FLAGS "${ARROW_EMSCRIPTEN_DYLIB_CREATE_FLAGS}")
set(CMAKE_MODULE_LINKER_FLAGS "${ARROW_EMSCRIPTEN_DYLIB_CREATE_FLAGS}")
if(ARROW_TESTING)
# flags for building test executables for use in node
if("${UPPERCASE_BUILD_TYPE}" STREQUAL "RELEASE")
Expand Down
4 changes: 4 additions & 0 deletions cpp/cmake_modules/ThirdpartyToolchain.cmake
Original file line numberDiff line numberDiff line change
Expand Up@@ -2183,6 +2183,10 @@ function(build_protobuf)
set(PROTOBUF_HOST_CMAKE_ARGS
"-DCMAKE_CXX_FLAGS="
"-DCMAKE_C_FLAGS="
# Explicitly set the C++ standard for the host build. Without this,
# Abseil may be compiled with the host compiler's default standard,
# which can be older than C++17.
"-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
Comment on lines +2186 to +2189

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hope this change is fine to keep here; this happened to me because I am using AppleClang 21 on my macOS machine to cross-compile for Emscripten.

The reason is that in the host protoc build, where CMAKE_CXX_FLAGS is blanked and no standard is set, absl compiles as C++14 and uses absl::string_view. That results in an ABI mismatch because Protobuf's targets reference the std::string_view signatures (since Protobuf compiles to C++17 or newer).

(I guess no one has hit this before, since the CI job exercises going from Linux to Emscripten, where gcc defaults to C++17)

"-DCMAKE_INSTALL_PREFIX=${PROTOBUF_HOST_PREFIX}"
-Dprotobuf_BUILD_TESTS=OFF
-Dprotobuf_DEBUG_POSTFIX=
Expand Down
2 changes: 1 addition & 1 deletion dev/tasks/tasks.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -521,7 +521,7 @@ tasks:
params:
env:
UBUNTU: 22.04
PYTHON: 3.12
PYTHON: 3.14
image: conda-python-emscripten

test-conda-python-3.11-hypothesis:
Expand Down
4 changes: 2 additions & 2 deletions docs/source/developers/cpp/emscripten.rst
Original file line numberDiff line numberDiff line change
Expand Up@@ -34,9 +34,9 @@ activate it using the commands below (see https://emscripten.org/docs/getting_st
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
# replace <version> with the desired EMSDK version.
# e.g. for Pyodide 0.26, you need EMSDK version 3.1.58
# e.g. for Pyodide 314.0.x, you need EMSDK version 5.0.3
# the versions can be found in the Makefile.envs file in the Pyodide repo:
# https://github.com/pyodide/pyodide/blob/10b484cfe427e076c929a55dc35cfff01ea8d3bc/Makefile.envs
# https://github.com/pyodide/pyodide/blob/314.0.4/Makefile.envs
./emsdk install <version>
./emsdk activate <version>
source ./emsdk_env.sh
Expand Down
4 changes: 3 additions & 1 deletion python/CMakeLists.txt
Original file line numberDiff line numberDiff line change
Expand Up@@ -111,7 +111,9 @@ if("$ENV{CMAKE_EXPORT_COMPILE_COMMANDS}" STREQUAL "1")
set(CMAKE_EXPORT_COMPILE_COMMANDS 1)
endif()

if(UNIX)
# On Emscripten, the equivalent $ORIGIN runtime path is added
# through the linker flags in SetupCxxFlags.cmake instead
if(UNIX AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
# In the event that we are bundling the shared libraries (e.g. in a
# manylinux1 wheel), we need to set the RPATH of the extensions to the
Expand Down
9 changes: 8 additions & 1 deletion python/scripts/run_emscripten_tests.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -148,8 +148,14 @@ class NodeDriver:
import subprocess

def __init__(self, hostname, port):
# handle different syntax for util-linux script and macOS BSD-style script
if sys.platform == "darwin":
script_command = [shutil.which("script"), "-q", "/dev/null",
shutil.which("node")]
else:
script_command = [shutil.which("script"), "-c", shutil.which("node")]
self.process = subprocess.Popen(
[shutil.which("script"), "-c", shutil.which("node")],
script_command,
stdin=subprocess.PIPE,
shell=False,
bufsize=0,
Expand DownExpand Up@@ -320,6 +326,7 @@ def _load_pyarrow_in_runner(driver, wheel_name):
if "pyarrow" not in sys.modules:
await micropip.install("hypothesis")
import pyodide_js as pjs
await pjs.loadPackage("packaging")
await pjs.loadPackage("tzdata")
await pjs.loadPackage("numpy")
await pjs.loadPackage("pandas")
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
9d4bf5a
Bump to Pyodide 0.28.1
agriyakhetarpal Aug 13, 2025
16f90d9
Bump Python version for conda-python-emscripten
agriyakhetarpal Aug 14, 2025
eebb7a8
Pass the right flag for WASM exception handling
agriyakhetarpal Aug 14, 2025
af2e18d
Install `libatomic1` for Pyodide Dockerfile
agriyakhetarpal Aug 14, 2025
41adbeb
Undo WASM EH flags as SjLj is enabled
agriyakhetarpal Aug 14, 2025
a89f7ec
Fix lint in Emscripten Dockerfile `apt-get` command
agriyakhetarpal Aug 14, 2025
20de7ad
Build static `libarrow_python` on Emscripten
agriyakhetarpal Aug 14, 2025
781b54a
Add Emscripten-specific flags for `_acero`
agriyakhetarpal Aug 14, 2025
f73c495
Fix CMake lint
agriyakhetarpal Aug 14, 2025
6ef7bb3
Revert "Fix CMake lint"
agriyakhetarpal Aug 14, 2025
18bf7d5
Revert "Add Emscripten-specific flags for `_acero`"
agriyakhetarpal Aug 14, 2025
eae25be
Revert "Build static `libarrow_python` on Emscripten"
agriyakhetarpal Aug 15, 2025
d279250
Merge main
agriyakhetarpal Aug 15, 2026
dc69985
Update to Python 3.14 and Pyodide 314.0.4
agriyakhetarpal Aug 15, 2026
89a6615
Use Pyodide 2026_0 ABI flags and set `RPATH` to `$ORIGIN`
agriyakhetarpal Aug 15, 2026
103bef4
`packaging` needed on Emscripten due to `pyarrow/tests/util.py`
agriyakhetarpal Aug 15, 2026
e62cf80
Add handling for Unix `script -c`/`script -q`
agriyakhetarpal Aug 15, 2026
b92772d
Fix Abseil ABI mismatch on linking with AppleClang
agriyakhetarpal Aug 15, 2026
ef4ecb6
Update to Node 24 in environment
agriyakhetarpal Aug 15, 2026
ff64e0d
Add separate pyodide-build version argument
agriyakhetarpal Aug 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 15 additions & 8 deletions ci/docker/conda-python-emscripten.dockerfile
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,32 +18,39 @@
ARG repo
ARG arch
ARG arch_short
ARG python="3.12"
ARG python="3.14"
FROM --platform=linux/${arch} ${repo}:${arch_short}-conda-python-${python}

ARG selenium_version="4.41.0"
ARG pyodide_version="0.26.0"
ARG pyodide_version="314.0.4"
# pyodide-build is versioned independently of Pyodide
ARG pyodide_build_version="0.39.0"
ARG chrome_version="latest"
ARG required_python_min="(3,12)"
# fail if python version < 3.12
ARG required_python_min="(3,14)"
# fail if python version < 3.14
RUN echo "check PYTHON>=${required_python_min}" && python -c "import sys;sys.exit(0 if sys.version_info>=${required_python_min} else 1)"

# install selenium and recent pyodide-build and recent python
RUN apt-get update -y -q && \
apt-get install -y -q --no-install-recommends \
libatomic1 && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

# needs to be a login shell so ~/.profile is read
SHELL ["/bin/bash", "--login", "-c", "-o", "pipefail"]

# install selenium and recent pyodide-build and recent python
RUN python -m pip install --no-cache-dir selenium==${selenium_version} && \
python -m pip install --no-cache-dir --upgrade pyodide-build>=${pyodide_version}
python -m pip install --no-cache-dir --upgrade "pyodide-build>=${pyodide_build_version}"

# install pyodide dist directory to /pyodide
RUN pyodide_dist_url="https://github.com/pyodide/pyodide/releases/download/${pyodide_version}/pyodide-${pyodide_version}.tar.bz2" && \
wget -q "${pyodide_dist_url}" -O- | tar -xj -C /

# install node 20 (needed for async call support)
# install node 24 (needed for async call support and JSPI)
# and pthread-stubs for build, and unzip needed for chrome build to work
# xz is needed by emsdk to extract node tarballs
RUN conda install nodejs=20 unzip pthread-stubs make xz -c conda-forge
RUN conda install nodejs=24 unzip pthread-stubs make xz -c conda-forge

# install correct version of emscripten for this pyodide
COPY ci/scripts/install_emscripten.sh /arrow/ci/scripts/
Expand Down
5 changes: 3 additions & 2 deletions compose.yaml
Original file line numberDiff line numberDiff line change
Expand Up@@ -981,10 +981,11 @@ services:
arch_short: ${ARCH_SHORT}
clang_tools: ${CLANG_TOOLS}
llvm: ${LLVM}
pyodide_version: "0.26.0"
pyodide_version: "314.0.4"
pyodide_build_version: "0.39.0"
chrome_version: "latest"
selenium_version: "4.41.0"
required_python_min: "(3,12)"
required_python_min: "(3,14)"
python: ${PYTHON}
shm_size: *shm-size
volumes: *ubuntu-volumes
Expand Down
31 changes: 20 additions & 11 deletions cpp/cmake_modules/SetupCxxFlags.cmake
Original file line numberDiff line numberDiff line change
Expand Up@@ -719,26 +719,35 @@ if(MSVC)
endif()

if(CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
# flags are:
# For the Pyodide 2026_0 ABI, the flags are:
# 1) We force *everything* to build as position independent
# 2) And with support for C++ exceptions
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -fexceptions")
# 2) We support C++ WASM exceptions, using the native WebAssembly
# exception handling proposal and WebAssembly-based setjmp/longjmp
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -fwasm-exceptions -sSUPPORT_LONGJMP=wasm")
# deprecated-literal-operator error is thrown in datetime (vendored lib in arrow)
set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -fPIC -fexceptions -Wno-error=deprecated-literal-operator")
"${CMAKE_CXX_FLAGS} -fPIC -fwasm-exceptions -sSUPPORT_LONGJMP=wasm -Wno-error=deprecated-literal-operator"
)

# flags for creating shared libraries (only used in pyarrow, because
# Emscripten builds libarrow as static)
# flags are:
# 1) Tell it to use JavaScript / WebAssembly 64 bit number support.
# 2) Tell it to build with support for C++ exceptions
# 2) Tell it to build with support for C++ exceptions (see above)
# 3) Skip linker flags error which happens with -soname parameter
set(ARROW_EMSCRIPTEN_LINKER_FLAGS "-sWASM_BIGINT=1 -fexceptions -Wno-error=linkflags")
set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS
"-sSIDE_MODULE=1 ${ARROW_EMSCRIPTEN_LINKER_FLAGS}")
set(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS
"-sSIDE_MODULE=1 ${ARROW_EMSCRIPTEN_LINKER_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "-sSIDE_MODULE=1 ${ARROW_EMSCRIPTEN_LINKER_FLAGS}")
# 4) Record $ORIGIN as an RPATH, so that Pyodide can locate
# libarrow_python.so next to the extension modules needing it
# Note: the CMAKE_SHARED_LIBRARY_CREATE_<LANG>_FLAGS and
# CMAKE_SHARED_MODULE_CREATE_<LANG>_FLAGS variables are not used by the
# Ninja generator, so the flags must go through the linker-flags
# variables, which apply to SHARED (libarrow_python) and MODULE (Cython
# extension) targets respectively.
set(ARROW_EMSCRIPTEN_LINKER_FLAGS
"-sWASM_BIGINT=1 -fwasm-exceptions -sSUPPORT_LONGJMP=wasm -Wno-error=linkflags")
set(ARROW_EMSCRIPTEN_DYLIB_CREATE_FLAGS
"-sSIDE_MODULE=1 ${ARROW_EMSCRIPTEN_LINKER_FLAGS} '-Wl,-rpath,$ORIGIN'")
set(CMAKE_SHARED_LINKER_FLAGS "${ARROW_EMSCRIPTEN_DYLIB_CREATE_FLAGS}")
set(CMAKE_MODULE_LINKER_FLAGS "${ARROW_EMSCRIPTEN_DYLIB_CREATE_FLAGS}")
if(ARROW_TESTING)
# flags for building test executables for use in node
if("${UPPERCASE_BUILD_TYPE}" STREQUAL "RELEASE")
Expand Down
4 changes: 4 additions & 0 deletions cpp/cmake_modules/ThirdpartyToolchain.cmake
Original file line numberDiff line numberDiff line change
Expand Up@@ -2183,6 +2183,10 @@ function(build_protobuf)
set(PROTOBUF_HOST_CMAKE_ARGS
"-DCMAKE_CXX_FLAGS="
"-DCMAKE_C_FLAGS="
# Explicitly set the C++ standard for the host build. Without this,
# Abseil may be compiled with the host compiler's default standard,
# which can be older than C++17.
"-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
Comment on lines +2186 to +2189

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hope this change is fine to keep here; this happened to me because I am using AppleClang 21 on my macOS machine to cross-compile for Emscripten.

The reason is that in the host protoc build, where CMAKE_CXX_FLAGS is blanked and no standard is set, absl compiles as C++14 and uses absl::string_view. That results in an ABI mismatch because Protobuf's targets reference the std::string_view signatures (since Protobuf compiles to C++17 or newer).

(I guess no one has hit this before, since the CI job exercises going from Linux to Emscripten, where gcc defaults to C++17)

"-DCMAKE_INSTALL_PREFIX=${PROTOBUF_HOST_PREFIX}"
-Dprotobuf_BUILD_TESTS=OFF
-Dprotobuf_DEBUG_POSTFIX=
Expand Down
2 changes: 1 addition & 1 deletion dev/tasks/tasks.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -521,7 +521,7 @@ tasks:
params:
env:
UBUNTU: 22.04
PYTHON: 3.12
PYTHON: 3.14
image: conda-python-emscripten

test-conda-python-3.11-hypothesis:
Expand Down
4 changes: 2 additions & 2 deletions docs/source/developers/cpp/emscripten.rst
Original file line numberDiff line numberDiff line change
Expand Up@@ -34,9 +34,9 @@ activate it using the commands below (see https://emscripten.org/docs/getting_st
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
# replace <version> with the desired EMSDK version.
# e.g. for Pyodide 0.26, you need EMSDK version 3.1.58
# e.g. for Pyodide 314.0.x, you need EMSDK version 5.0.3
# the versions can be found in the Makefile.envs file in the Pyodide repo:
# https://github.com/pyodide/pyodide/blob/10b484cfe427e076c929a55dc35cfff01ea8d3bc/Makefile.envs
# https://github.com/pyodide/pyodide/blob/314.0.4/Makefile.envs
./emsdk install <version>
./emsdk activate <version>
source ./emsdk_env.sh
Expand Down
4 changes: 3 additions & 1 deletion python/CMakeLists.txt
Original file line numberDiff line numberDiff line change
Expand Up@@ -111,7 +111,9 @@ if("$ENV{CMAKE_EXPORT_COMPILE_COMMANDS}" STREQUAL "1")
set(CMAKE_EXPORT_COMPILE_COMMANDS 1)
endif()

if(UNIX)
# On Emscripten, the equivalent $ORIGIN runtime path is added
# through the linker flags in SetupCxxFlags.cmake instead
if(UNIX AND NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
# In the event that we are bundling the shared libraries (e.g. in a
# manylinux1 wheel), we need to set the RPATH of the extensions to the
Expand Down
9 changes: 8 additions & 1 deletion python/scripts/run_emscripten_tests.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -148,8 +148,14 @@ class NodeDriver:
import subprocess

def __init__(self, hostname, port):
# handle different syntax for util-linux script and macOS BSD-style script
if sys.platform == "darwin":
script_command = [shutil.which("script"), "-q", "/dev/null",
shutil.which("node")]
else:
script_command = [shutil.which("script"), "-c", shutil.which("node")]
self.process = subprocess.Popen(
[shutil.which("script"), "-c", shutil.which("node")],
script_command,
stdin=subprocess.PIPE,
shell=False,
bufsize=0,
Expand DownExpand Up@@ -320,6 +326,7 @@ def _load_pyarrow_in_runner(driver, wheel_name):
if "pyarrow" not in sys.modules:
await micropip.install("hypothesis")
import pyodide_js as pjs
await pjs.loadPackage("packaging")
await pjs.loadPackage("tzdata")
await pjs.loadPackage("numpy")
await pjs.loadPackage("pandas")
Expand Down
Loading