Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 1 addition & 8 deletions recipes/recipes_emscripten/h5py/build.sh
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@

# add ad-hoc code to load the shared libs
tmp_file="$(mktemp)"
printf 'import ctypes;ctypes.CDLL("/lib/libhdf5.so");ctypes.CDLL("/lib/libhdf5_hl.so")\n' > "$tmp_file"
cat "h5py/__init__.py" >> "$tmp_file"
mv "$tmp_file" "h5py/__init__.py"


# remove the emcc symlink in the $BUILD_PREFIX/bin
rm $BUILD_PREFIX/bin/emcc

Expand All @@ -30,7 +23,7 @@ export H5PY_DIRECT_VFD='0'
export HDF5_MPI=OFF

# Explitly set HDF5 version
export HDF5_VERSION=1.12.3
export HDF5_VERSION=1.14.6

${PYTHON} -m pip install . -vvv

Expand Down
2 changes: 1 addition & 1 deletion recipes/recipes_emscripten/h5py/recipe.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ source:
- patches/configure.patch

build:
number: 1
number: 2

requirements:
build:
Expand Down
18 changes: 17 additions & 1 deletion recipes/recipes_emscripten/h5py/test_h5py.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,20 @@ def test_usage():
assert dset2.name == "/subgroup/another_dataset"

f = h5py.File("mytestfile.hdf5", "r")
assert sorted(list(f.keys())) == ["mydataset", "subgroup"]
assert sorted(list(f.keys())) == ["mydataset", "subgroup"]


def test_dimscales(tmp_path):
"""Exercises the HL dimscale reopen path across a File close/open cycle."""
import h5py

path = str(tmp_path / "dimscales.h5")
with h5py.File(path, "w") as f:
scale = f.create_dataset("x", data=[0.0, 1.0, 2.0, 3.0])
scale.make_scale("x")
data = f.create_dataset("temp", data=[10.0, 20.0, 30.0, 40.0])
data.dims[0].attach_scale(scale)

with h5py.File(path, "r") as f:
assert h5py.h5ds.is_scale(f["x"].id)
assert f["temp"].dims[0][0].name == "/x"
6 changes: 1 addition & 5 deletions recipes/recipes_emscripten/hdf5/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ cd build

export LDFLAGS="-sNODERAWFS=1 -sUSE_ZLIB=1 -sFORCE_FILESYSTEM=1"

cp ${RECIPE_DIR}/settings/* ../src/

emcmake cmake .. \
-DCMAKE_INSTALL_PREFIX=${PREFIX} \
-DH5_HAVE_GETPWUID=OFF \
Expand All @@ -21,13 +19,11 @@ emcmake cmake .. \
-DHDF5_BUILD_EXAMPLES=OFF \
-DHDF5_BUILD_TOOLS=OFF \
-DHDF5_BUILD_UTILS=OFF \
-DHDF5_BUILD_HL_LIB=ON \
-DHDF5_ENABLE_Z_LIB_SUPPORT=ON \
-DHDF5_ENABLE_ROS3_VFD=OFF \
-DZLIB_INCLUDE_DIR=${PREFIX}/include \
-DZLIB_LIBRARY=${PREFIX}/lib/libz.a

cp ${RECIPE_DIR}/settings/* ../src/
cp ${RECIPE_DIR}/settings/* src/

emmake make -j 4
emmake make install
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Emscripten's <bits/fenv.h> defines only rounding modes and FE_ALL_EXCEPT=0;
FE_INVALID is not defined because WASM has no floating-point exception
flags. Guard the FE_INVALID clear so the build proceeds; under WASM there
are no FP exceptions to clear, so the guarded branch is a legitimate no-op.

--- a/src/H5Tinit_float.c
+++ b/src/H5Tinit_float.c
@@ -608,9 +608,11 @@
#endif

done:
+#ifdef FE_INVALID
/* Clear any FE_INVALID exceptions from NaN handling */
if (feclearexcept(FE_INVALID) != 0)
HSYS_GOTO_ERROR(H5E_DATATYPE, H5E_CANTSET, FAIL, "can't clear floating-point exceptions");
+#endif

/* Restore the original environment */
if (feupdateenv(&saved_fenv) != 0)
28 changes: 28 additions & 0 deletions recipes/recipes_emscripten/hdf5/patches/0002-drop-soversion.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
Under emscripten the loader dedupes shared libraries by string identity of
their NEEDED entry, not by realpath. When libhdf5_hl links against libhdf5
with SOVERSION set, it records NEEDED "libhdf5.so.310.5.1", while consumers
like h5py link with bare "-lhdf5" and record NEEDED "libhdf5.so". Both paths
resolve to the same file via symlinks, but the loader sees them as two
distinct libraries and creates two separate instances — each with its own
copy of libhdf5.so's file-static globals (H5CX_head_g etc.), which breaks
the metadata cache when calls cross between the instances.

Skip VERSION/SOVERSION for emscripten builds so every consumer records the
bare "libhdf5.so" NEEDED entry and the loader deduplicates properly.

--- a/config/cmake/HDF5Macros.cmake
+++ b/config/cmake/HDF5Macros.cmake
@@ -22,10 +22,10 @@
else ()
set (LIBHDF_VERSION ${HDF5_${libpackage}_PACKAGE_SOVERSION_MAJOR})
endif ()
- set_target_properties (${libtarget} PROPERTIES VERSION ${PACKAGE_SOVERSION})
+ if (NOT EMSCRIPTEN)
+ set_target_properties (${libtarget} PROPERTIES VERSION ${PACKAGE_SOVERSION})
+ endif ()
if (WIN32)
set (${LIB_OUT_NAME} "${LIB_OUT_NAME}-${LIBHDF_VERSION}")
- else ()
+ elseif (NOT EMSCRIPTEN)
set_target_properties (${libtarget} PROPERTIES SOVERSION ${LIBHDF_VERSION})
endif ()
19 changes: 15 additions & 4 deletions recipes/recipes_emscripten/hdf5/recipe.yaml
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
context:
version: 1.12.3
maj_min_ver: 1.12
version: 1.14.6
maj_min_ver: 1.14

package:
name: hdf5
version: ${{ version }}

source:
url: https://support.hdfgroup.org/ftp/HDF5/releases/hdf5-${{ maj_min_ver }}/hdf5-${{version }}/src/hdf5-${{ version }}.tar.gz
sha256: c15adf34647918dd48150ea1bd9dffd3b32a3aec5298991d56048cc3d39b4f6f
url: https://support.hdfgroup.org/releases/hdf5/v${{ maj_min_ver | replace(".", "_") }}/v${{ version | replace(".", "_") }}/downloads/hdf5-${{ version }}.tar.gz
sha256: e4defbac30f50d64e1556374aa49e574417c9e72c6b1de7a4ff88c4b1bea6e9b
patches:
- patches/0001-fenv-fe-invalid-guard.patch
- patches/0002-drop-soversion.patch

build:
number: 0
Expand All @@ -21,6 +24,14 @@ requirements:
host:
- zlib

tests:
- package_contents:
files:
- include/hdf5.h
- include/hdf5_hl.h
- lib/libhdf5.so
- lib/libhdf5_hl.so

about:
homepage: https://www.hdfgroup.org/solutions/hdf5/
license: BSD-3-Clause
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
DAOS container detection uses listxattr/getxattr which are declared in
Emscripten's <sys/xattr.h> but not implemented at runtime — the built .so
fails to load with "cannot resolve symbol listxattr". DAOS makes no sense
in a WASM sandbox anyway. Short-circuit isdaoscontainer() under
__EMSCRIPTEN__ so the xattr code is never reached.

--- a/libdispatch/dinfermodel.c
+++ b/libdispatch/dinfermodel.c
@@ -1594,6 +1594,10 @@
static int
isdaoscontainer(const char* path)
{
+#ifdef __EMSCRIPTEN__
+ (void)path;
+ return NC_ENOTNC;
+#else
int stat = NC_ENOTNC; /* default is that this is not a DAOS container */
#ifndef _WIN32
#ifdef USE_HDF5
@@ -1669,6 +1673,7 @@
#endif
errno = 0; /* reset */
return stat;
+#endif /* __EMSCRIPTEN__ */
}
3 changes: 2 additions & 1 deletion recipes/recipes_emscripten/libnetcdf/recipe.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ source:
patches:
- patches/parallel-disable.patch
- patches/hdf5-parallel-disable.patch
- patches/skip-daos-emscripten.patch

build:
number: 0
number: 1

files:
exclude:
Expand Down
4 changes: 2 additions & 2 deletions recipes/recipes_emscripten/netcdf4/recipe.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ source:
- patches/0001-Fix-unknown-arg-R-PREFIX-lib.patch

build:
number: 2
number: 3
script:
- export LDFLAGS="-L$PREFIX/lib -lhdf5 $LDFLAGS"
- export LDFLAGS="-L$PREFIX/lib -lhdf5 -lhdf5_hl $LDFLAGS"
- ${PYTHON} -m pip install . -vvv

files:
Expand Down
36 changes: 31 additions & 5 deletions recipes/recipes_emscripten/netcdf4/test_netcdf4.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,33 @@
def test_netcdf4():
from netCDF4 import Dataset
rootgrp = Dataset("test.nc", "w", format="NETCDF4")
rootgrp.data_model == "NETCDF4"
rootgrp.close()
import numpy as np
import netCDF4
from netCDF4 import Dataset


def test_versions():
print("netCDF4:", netCDF4.__version__)
print("libnetcdf:", netCDF4.__netcdf4libversion__)
print("libhdf5:", netCDF4.__hdf5libversion__)


def test_netcdf3_write_read(tmp_path):
path = str(tmp_path / "c.nc")
with Dataset(path, "w", format="NETCDF3_CLASSIC") as ds:
ds.createDimension("x", 4)
v = ds.createVariable("temp", "f8", ("x",))
v[:] = np.arange(4.0)
with Dataset(path, "r") as ds:
assert ds.variables["temp"].shape == (4,)


def test_netcdf4_roundtrip(tmp_path):
"""End-to-end netcdf-4 round-trip: dim + variable + attribute."""
path = str(tmp_path / "v.nc")
with Dataset(path, "w", format="NETCDF4") as ds:
ds.title = "hello"
ds.createDimension("x", 4)
v = ds.createVariable("temp", "f8", ("x",))
v[:] = np.arange(4.0)
with Dataset(path, "r") as ds:
assert ds.title == "hello"
assert "x" in ds.dimensions
np.testing.assert_array_equal(ds.variables["temp"][:], np.arange(4.0))
4 changes: 2 additions & 2 deletions variant.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ harfbuzz:
hdf4:
- 4.2
hdf5:
- 1.12.3
- 1.14.6
icu:
- '73'
ipopt:
Expand Down Expand Up @@ -449,7 +449,7 @@ libmatio:
libmicrohttpd:
- 0.9
libnetcdf:
- 4.9.3
- 4.10.1
libopencv:
- 4.5.5
libpcap:
Expand Down