Skip to content

new(WebAssembly/binaryen): wasm-opt toolchain (unblocks emscripten)#13080

Merged
jhheider merged 11 commits into
pkgxdev:mainfrom
tannevaled:new/binaryen
Jun 6, 2026
Merged

new(WebAssembly/binaryen): wasm-opt toolchain (unblocks emscripten)#13080
jhheider merged 11 commits into
pkgxdev:mainfrom
tannevaled:new/binaryen

Conversation

@tannevaled
Copy link
Copy Markdown
Contributor

Part of the CNCF coverage + emscripten unblock batch.

🤖 Generated with Claude Code

tannevaled and others added 10 commits May 29, 2026 16:46
binaryen 119+ uses std::set::contains and std::map::contains, both
introduced in C++20 (P0458). Default CMake target is C++17, so the
build fails on the first .cpp under src/ir/:

  src/ir/effects.h:572:42: error: no member named 'contains' in
                                  'std::set<wasm::Name>'

Bumping CMAKE_CXX_STANDARD to 20 (and marking it required) tells the
build to compile with -std=c++20.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…s wins)

CMAKE_CXX_STANDARD=20 didn't take effect — binaryen's CMakeLists.txt
sets the standard per-target via target_compile_features(cxx_std_17)
which CMake gives priority over the global CMAKE_CXX_STANDARD. The
build kept compiling at -std=c++17 and re-hit the same error:

  src/ir/effects.h:572: error: no member named 'contains' in
                                 'std::set<wasm::Name>'

Drop the global and pass -std=c++20 via CMAKE_CXX_FLAGS. Clang's
last-wins -std= argument resolution puts our 20 ahead of the
per-target 17 that target_compile_features emits.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The -DCMAKE_CXX_FLAGS=-std=c++20 form replaced CMAKE_CXX_FLAGS
entirely, stripping brewkit's -fPIC / -fPIE etc and only narrowly
shadowing the per-target cxx_std_17 feature. Switch to exporting
CXXFLAGS=$CXXFLAGS -std=c++20 in the script step — CMake then
appends the brewkit + our -std= into CMAKE_CXX_FLAGS at configure
time, and clang's last-wins -std= resolution puts c++20 ahead of
the cxx_std_17-derived -std=c++17 that target_compile_features
emits per source file.

If this iter still fails we'll pin the binaryen version to ≤118
(pre-std::set::contains) instead and document the dead-end.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
iter 4. Three previous attempts at forcing -std=c++20 (global,
flags-D, env CXXFLAGS) all failed identically with
  src/ir/effects.h:572: error: no member named 'contains' in
                                 'std::set<wasm::Name>'
which on its face looks like a -std= issue.

Checking how nixpkgs handles binaryen (per the updated org memory
quirks: ALWAYS look at upstream packagers FIRST): they ship empty
cmakeFlags. Their stdenv's cc-wrapper guarantees clang picks up the
SAME gcc derivation's libstdc++ headers. That's what's actually
missing here — pkgx clang on Linux falls back to the host
/usr/include/c++/12/ (Ubuntu 22.04 ships GCC 12 whose libstdc++
predates the back-port of `contains` to C++17/feature-test gates).

Fix: add gnu.org/gcc as a Linux build dep and -isystem its libstdc++
include dir explicitly. clang then sees the modern <set>/<map>
headers, std::set::contains resolves, build completes.

Darwin keeps the simple cmake invocation: libc++ from llvm.org is
already wired through pkgx's clang properly there.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
iter 4's -isystem trick got us past std::set::contains — that part
works. But the cross builds now hit a different wall:

  src/support/suffix_tree.h:38: fatal error: llvm/Support/Allocator.h:
                                              No such file or directory

binaryen vendors a slim copy of LLVM under third_party/llvm-project/,
but their CMakeLists only adds that path to -I when BUILD_LLVM_DWARF=ON.
suffix_tree.h includes <llvm/Support/Allocator.h> unconditionally, so
with DWARF OFF every TU that transitively pulls suffix_tree.h fails
at preprocessing.

Just remove the optimization — net binary cost is ~2 MB extra in
wasm-opt; trivial vs the clean-build benefit.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
iter 6. Build was green on the cross targets but ARM64 native failed
at the test step:

  + wasm-opt --version
  + grep -i wasm-opt
  [no output between]

wasm-opt in newer binaryen versions prints --version to stderr.
Merge stderr with 2>&1 so the test sees it, and match against the
versioned literal we know binaryen emits (`version_<N>`).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
wasm-opt's --version output format shifted: older releases printed
`wasm-opt version_129`, newer ones print `wasm-opt 129.0`. The
prefixed regex `version_{{version.raw}}` doesn't match newer
outputs.

Match just the raw number (e.g. `129`) so the test stays stable
across the release-line.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
iter 7's build was green on all 4 jobs; the test failed at runtime
with:

  wasm-opt: /usr/lib/aarch64-linux-gnu/libstdc++.so.6:
    version `GLIBCXX_3.4.31' not found
    (required by /opt/.../v129.0.0/lib/libbinaryen.so)

The build correctly compiled against pkgx gcc 16's libstdc++ headers
(thanks to iter 4's -isystem) but the resulting libbinaryen.so still
records a dynamic-link dep on libstdc++.so.6 with symbol versions
≥ GLIBCXX_3.4.31 — which only gcc 13+'s runtime exposes. Ubuntu
22.04's stock libstdc++.so.6 (from gcc 12) tops out at 3.4.30.

Embed gcc's runtime statically into libbinaryen.so so the .so has
no host-libstdc++ dep. Mirrors what we did historically for gcc
itself's `--with-boot-ldflags=-static-libstdc++ -static-libgcc`.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
tannevaled added a commit to tannevaled/pantry that referenced this pull request May 31, 2026
Test failed with:
  emcc: error: BINARYEN_ROOT not set in config, and `wasm-opt`
  not found in PATH

Pantry's llvm.org does not ship wasm-opt — that tool lives in
WebAssembly/binaryen (added by PR pkgxdev#13080, currently green). Wire
binaryen as a runtime + build dep and point BINARYEN_ROOT at it
in both runtime.env and the seeded .emscripten config.

Mirrors how homebrew/nixpkgs configure emscripten (separate
binaryen install referenced via BINARYEN_ROOT).
tannevaled added a commit to tannevaled/pantry that referenced this pull request May 31, 2026
pantry's convention for non-domain projects is github.com/<owner>/<repo>;
the binaryen recipe lives at projects/github.com/WebAssembly/binaryen/.
Previous commit used 'WebAssembly/binaryen' which libpkgx rejected:

  Error: pkg not found: WebAssembly/binaryen

NB: this PR now hard-depends on pkgxdev#13080 (new(WebAssembly/binaryen))
being merged first — that PR is green and mergeable.
Refactors the build script by consolidating common steps and moving Linux-specific `LDFLAGS` (for static libstdc++ linking) and `CXXFLAGS` (for `isystem` includes) into a dedicated `env.linux` block. This improves script clarity and ensures platform-specific flags are applied declaratively.

Pins the `gnu.org/gcc` dependency to `14` for consistent `libstdc++` headers and runtime, further mitigating ABI compatibility issues seen on Linux runners.

Adjusts version tag parsing (`distributable.url`, `versions.strip`) and the `wasm-opt --version` test assertion to correctly handle evolving upstream release tagging and output formats. Removes redundant `platforms` and `gnu.org/make` entries.
@jhheider jhheider merged commit 4a3a56f into pkgxdev:main Jun 6, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants