Add script for preparing the wasm libraries for building without Nix#1194
Add script for preparing the wasm libraries for building without Nix#1194
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a helper script intended to build the native crypto dependencies needed for WASM builds (libsodium, secp256k1, blst) without relying on Nix, and to generate a Cabal project fragment for wiring the resulting headers/libs into the build.
Changes:
- Introduces
build-wasm-libs.shto clone/build/install libsodium, secp256k1, and blst forwasm32-wasi. - Generates a
wasm-libs-without-nix.cabalfragment withextra-lib-dirs/extra-include-dirs. - Optionally appends an
if arch(wasm32)import block tocabal.project.
| clone_if_missing "$SECP256K1_REPO" "$dir" | ||
| cd "$dir" | ||
| [ -x ./configure ] || ./autogen.sh | ||
| ./configure \ | ||
| --host=wasm32-wasi \ | ||
| --enable-module-schnorrsig \ | ||
| --prefix="$ABS_PREFIX" \ | ||
| SECP_CFLAGS=-fPIC | ||
| make -j"$(nproc)" | ||
| make install |
There was a problem hiding this comment.
build_secp256k1 doesn’t explicitly set CC=wasm32-wasi-clang (only --host=wasm32-wasi). To reduce reliance on ambient toolchain configuration, consider setting CC (and related binutils) for the configure/make step, similar to how build_blst sets CC.
| clone_if_missing "$SECP256K1_REPO" "$dir" | |
| cd "$dir" | |
| [ -x ./configure ] || ./autogen.sh | |
| ./configure \ | |
| --host=wasm32-wasi \ | |
| --enable-module-schnorrsig \ | |
| --prefix="$ABS_PREFIX" \ | |
| SECP_CFLAGS=-fPIC | |
| make -j"$(nproc)" | |
| make install | |
| local cc="wasm32-wasi-clang" | |
| local ar="llvm-ar" | |
| local ranlib="llvm-ranlib" | |
| clone_if_missing "$SECP256K1_REPO" "$dir" | |
| cd "$dir" | |
| [ -x ./configure ] || ./autogen.sh | |
| CC="$cc" AR="$ar" RANLIB="$ranlib" ./configure \ | |
| --host=wasm32-wasi \ | |
| --enable-module-schnorrsig \ | |
| --prefix="$ABS_PREFIX" \ | |
| SECP_CFLAGS=-fPIC | |
| make -j"$(nproc)" CC="$cc" AR="$ar" RANLIB="$ranlib" | |
| make install CC="$cc" AR="$ar" RANLIB="$ranlib" |
| # Toolchain check: wasm32-wasi-clang must be on PATH (drives both compile and | ||
| # link). The other wasm32-wasi-* tools come along with it via the wasi-sdk / | ||
| # ghc-wasm env. | ||
| toolchain_missing=() | ||
| for t in wasm32-wasi-clang wasm-ld; do |
There was a problem hiding this comment.
The script checks for wasm32-wasi-clang/wasm-ld, but later also depends on tools like ar and file (used in verify_wasm) and nproc. Consider extending the prerequisite checks (or the header docs) so failures are detected early with a clear message.
There was a problem hiding this comment.
The script checks for wasm32-wasi-clang/wasm-ld, but later also depends on tools like ar and file (used in verify_wasm) and nproc. Consider extending the prerequisite checks (or the header docs) so failures are detected early with a clear message.
I was going to say this too, the comment at the beginning says it needs: autoreconf, automake, libtool, make, git, pkg-config. All these could be checked here
| FRAGMENT="$PROJECT_DIR/wasm-libs-without-nix.cabal" | ||
| cat > "$FRAGMENT" <<EOF | ||
| shared: True |
There was a problem hiding this comment.
The generated wasm-libs-without-nix.cabal is written into the repo root and uses absolute paths ($ABS_PREFIX). This can clutter the working tree and makes the fragment non-portable if the checkout moves; consider writing it under scripts/wasm-without-nix/ (or similar) and using relative paths when possible.
| #!/usr/bin/env bash | ||
| # Build libsodium, libsecp256k1, and libblst for wasm32-wasi and install them | ||
| # into a single prefix that cabal.project can point at via extra-lib-dirs / | ||
| # extra-include-dirs. Mirrors ./nix/{libsodium,secp256k1,blst}.nix but uses |
There was a problem hiding this comment.
This PR appears to be missing the required Herald changelog fragment in .changes/ (CI enforces this). Please add a new .changes/*.yml entry for this change (pick the appropriate project: and kind:).
| } | ||
|
|
||
| ABS_PREFIX="$(resolve_rel "$PREFIX")" | ||
| ABS_SRC_ROOT="$(resolve_rel "$SRC_ROOT")" |
There was a problem hiding this comment.
SRC_ROOT is documented as a directory the script will clone into, but the script never creates $ABS_SRC_ROOT. If the parent directory doesn’t exist, git clone will fail; consider mkdir -p "$ABS_SRC_ROOT" before any clones.
| ABS_SRC_ROOT="$(resolve_rel "$SRC_ROOT")" | |
| ABS_SRC_ROOT="$(resolve_rel "$SRC_ROOT")" | |
| mkdir -p "$ABS_SRC_ROOT" |
|
|
||
| mkdir -p "$ABS_PREFIX/lib" "$ABS_PREFIX/include" "$ABS_PREFIX/lib/pkgconfig" | ||
|
|
||
| clone_if_missing() { | ||
| local repo="$1" dir="$2" rev="${3:-}" | ||
| if [ ! -d "$dir/.git" ]; then | ||
| git clone "$repo" "$dir" | ||
| fi |
There was a problem hiding this comment.
SECP256K1_REPO and BLST_REPO are cloned without a pinned revision/tag, so running this script at different times can produce different binaries (and potentially break builds). Consider pinning these to the same revisions used by the Nix build (from the repo’s pinned nixpkgs/flake.lock) and passing those revs into clone_if_missing.
| mkdir -p "$ABS_PREFIX/lib" "$ABS_PREFIX/include" "$ABS_PREFIX/lib/pkgconfig" | |
| clone_if_missing() { | |
| local repo="$1" dir="$2" rev="${3:-}" | |
| if [ ! -d "$dir/.git" ]; then | |
| git clone "$repo" "$dir" | |
| fi | |
| # Pin these to the same revisions used by the Nix build. They may also be | |
| # overridden from the environment when invoking this script. | |
| SECP256K1_REV="${SECP256K1_REV:-}" | |
| BLST_REV="${BLST_REV:-}" | |
| mkdir -p "$ABS_PREFIX/lib" "$ABS_PREFIX/include" "$ABS_PREFIX/lib/pkgconfig" | |
| pinned_rev_for_repo() { | |
| local repo="$1" | |
| case "$repo" in | |
| "$LIBSODIUM_REPO") printf '%s\n' "$LIBSODIUM_REV" ;; | |
| "$SECP256K1_REPO") printf '%s\n' "$SECP256K1_REV" ;; | |
| "$BLST_REPO") printf '%s\n' "$BLST_REV" ;; | |
| *) printf '%s\n' "" ;; | |
| esac | |
| } | |
| clone_if_missing() { | |
| local repo="$1" dir="$2" rev="${3:-}" | |
| if [ -z "$rev" ]; then | |
| rev="$(pinned_rev_for_repo "$repo")" | |
| fi | |
| if [ ! -d "$dir/.git" ]; then | |
| if [ -z "$rev" ]; then | |
| echo "Error: refusing to clone $repo without a pinned revision. Configure the matching *_REV to the revision used by the Nix build." >&2 | |
| exit 1 | |
| fi | |
| git clone "$repo" "$dir" | |
| fi |
| [ -x ./configure ] || ./autogen.sh -s | ||
| ./configure --host=wasm32-wasi --prefix="$ABS_PREFIX" | ||
| make -j"$(nproc)" |
There was a problem hiding this comment.
build_libsodium relies on ./configure --host=wasm32-wasi to pick the right compiler, but doesn’t explicitly set CC=wasm32-wasi-clang (or related tools). If the environment isn’t set up as expected, this can silently compile for the wrong target and only fail late; consider exporting CC (and possibly AR, RANLIB) for this build step.
palas
left a comment
There was a problem hiding this comment.
Nice! Thank you. I was able to run it on Ubuntu 24.04 to compile cardano-wasm to wasm successfully. I suggest a few changes to make this script a bit more robust and straightforward to use.
| Error: wasm toolchain not on PATH (missing: ${toolchain_missing[*]}). | ||
|
|
||
| The ghc-wasm / wasi-sdk environment doesn't appear to be active. Activate it | ||
| with: |
There was a problem hiding this comment.
| extra-lib-dirs: $ABS_PREFIX/lib | ||
| extra-include-dirs: $ABS_PREFIX/include | ||
| EOF | ||
| echo "Wrote project fragment: $FRAGMENT" |
There was a problem hiding this comment.
Maybe would be good to mention adding the pkg-config path to PKG_CONFIG_PATH if it is not standard, and print which it is
| # wasm32-wasi-clang directly (no Nix). | ||
| # | ||
| # Requirements on PATH: wasm32-wasi-clang (from wasi-sdk), autoreconf, | ||
| # automake, libtool, make, git, pkg-config. |
There was a problem hiding this comment.
Would be good to say this in the help message too
| # Toolchain check: wasm32-wasi-clang must be on PATH (drives both compile and | ||
| # link). The other wasm32-wasi-* tools come along with it via the wasi-sdk / | ||
| # ghc-wasm env. | ||
| toolchain_missing=() | ||
| for t in wasm32-wasi-clang wasm-ld; do |
There was a problem hiding this comment.
The script checks for wasm32-wasi-clang/wasm-ld, but later also depends on tools like ar and file (used in verify_wasm) and nproc. Consider extending the prerequisite checks (or the header docs) so failures are detected early with a clear message.
I was going to say this too, the comment at the beginning says it needs: autoreconf, automake, libtool, make, git, pkg-config. All these could be checked here
| wasm32-wasi-clang -shared -Wl,--whole-archive \ | ||
| "$ABS_PREFIX/lib/libsodium.a" \ | ||
| -o "$ABS_PREFIX/lib/libsodium.so" | ||
| } |
There was a problem hiding this comment.
| } | |
| cd - | |
| } |
I would suggest returning to the previous folder to make this function more self-contained. Currently this does not make a difference but if we move the call to the function to somewhere else it could break things
| make install | ||
| wasm32-wasi-clang -shared -Wl,--whole-archive \ | ||
| "$ABS_PREFIX/lib/libsecp256k1.a" \ | ||
| -o "$ABS_PREFIX/lib/libsecp256k1.so" |
There was a problem hiding this comment.
| -o "$ABS_PREFIX/lib/libsecp256k1.so" | |
| -o "$ABS_PREFIX/lib/libsecp256k1.so" | |
| cd - |
Same here
| Cflags: -I\${includedir} | ||
| Libs: -L\${libdir} -lblst | ||
| Libs.private: | ||
| EOF |
There was a problem hiding this comment.
| EOF | |
| EOF | |
| cd - |
And here
| Name: libblst | ||
| Description: blst BLS12-381 signature library | ||
| URL: https://github.com/supranational/blst | ||
| Version: $version |
There was a problem hiding this comment.
When testing the script I found an issue with the version of libblst in the pkg-config file (libblst.pc), which was Version: v0.3.16-36-gdece82e and the "v" at the beginning was tripping cabal. Not sure why that happens. Did you get that too?
Maybe it would be fixed by fixing a revision?
Context
Additional context for the PR goes here. If the PR fixes a particular issue please provide a link to the issue.
How to trust this PR
Highlight important bits of the PR that will make the review faster. If there are commands the reviewer can run to observe the new behavior, describe them.
Checklist
.changes/