feat(pkg): compat.wamr 2.4.5 (WebAssembly Micro Runtime) - #299
Merged
Conversation
C-source compat, interpreter runtime only, with libc-builtin and libc-wasi behind features. Linux section only; consumers gate the dependency the way compat.libaio does. The descriptor solves one problem the schema does not have a hook for. WAMR needs architecture-specific input twice: a BUILD_TARGET_* define, without which wasm_runtime_common.c compiles its whole invoke-native section away and the link fails on invokeNative, and the implementation of that symbol, which is hand-written assembly per architecture. `sources` and `cflags` vary per OS, not per architecture, and `archs` is package metadata rather than a selector, so both decisions are handed to the preprocessor instead: a generated config header maps __x86_64__/__aarch64__ to the matching BUILD_TARGET_* and reaches every TU through -include, and a generated .S includes the chosen assembly file as text. The dispatcher has to be .S because upstream's arch/invokeNative_*.s are lowercase, which clang assembles without the preprocessor -- so unlike libffi's .S files they cannot guard themselves. Two further notes carried in the descriptor comments: -std=gnu11 arrives through cflags because c_standard = "c11" defines __STRICT_ANSI__, under which the bare `asm` in platform_internal.h is not a keyword; and the POSIX platform files upstream drops when WASI is off are carried unconditionally rather than `!`-excluded and re-added by the feature, because an exclusion glob is global and beats the feature's own entry for the same file (that arrangement compiled and then failed to link on os_file_get_access_mode and friends). Two members. tests/examples/wamr runs a hand-assembled module whose export calls back into a host native function -- compute(6,7) returns 42 only if invokeNative works -- and asserts the negative half of the feature gate: env.putchar must be refused. tests/examples/wamr-features asserts the positive half for both features. The gate has to be tested by calling, not by instantiating: WAMR does not reject an unresolved import at load time, it warns and defers, and the refusal only appears on the call. Verified with the pinned mcpp 2026.8.27.2 from a cleaned target/, .mcpp/ and global build cache, so both members show `Compiling compat.wamr` rather than `Cached`. Design notes in .agents/docs/2026-08-30-add-wamr-plan.md. No CN mirror: no mcpp-res write access, so `url` uses the plain-string upstream form and CN users fall back to GitHub. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds
compat.wamr2.4.5 — the Bytecode Alliance's WebAssembly Micro Runtime, a small-footprint wasm interpreter. Pure C, Apache-2.0 WITH LLVM-exception.Shape
C-source compat, the
compat.mbedtlstemplate. The base is the interpreter runtime only: classic and fast interpreter, bulk memory and reference types (both on in upstream's own default configuration), no AOT, no JIT, no guest-facing libc. That keeps AOT's LLVM dependency out of the index and is the configuration an embedder wants when wasm modules are plugins reached only through host-provided imports. Guest libc arrives through two features,libc-builtinandlibc-wasi.The interesting part: per-architecture selection
WAMR needs architecture-specific input in two places, and the descriptor schema has a per-OS hook but not a per-architecture one (
archsdeclares support rather than selecting).The first is a
BUILD_TARGET_*define. The whole invoke-native section ofcore/iwasm/common/wasm_runtime_common.csits inside#if defined(BUILD_TARGET_X86_64) || … || defined(BUILD_TARGET_AARCH64), so with none defined the file compiles quietly with no way to call a native function and the failure only shows up at link time oninvokeNative. The second is the implementation of that symbol, which is hand-written assembly, one file per architecture.Both decisions are moved into the preprocessor, which does know the target:
generated_filesemits a config header mapping__x86_64__/__aarch64__to the matchingBUILD_TARGET_*, delivered to every TU with-include— the mechanismcompat.zlibalready uses forZ_HAVE_UNISTD_H.generated_filesalso emits a.Sthat#includes the chosenarch/invokeNative_*.sas text.The dispatcher has to be
.S.compat.libffican list upstream'sunix64.Sandsysv.Sdirectly and let each guard itself, but WAMR's equivalents are lowercase.s, which clang assembles without running the preprocessor, so an#ifdefinside them is never evaluated. Listing all of them is not an option either — each definesinvokeNative, and the aarch64 file does not assemble on x86_64. Both branches were checked directly before any of this reached a descriptor:Two smaller decisions worth flagging for review
-std=gnu11throughcflagsrather thanc_standard.platform_internal.hwrites the GS base with a bareasm volatile.-std=c11defines__STRICT_ANSI__, under whichasmis not a keyword, andwasm_memory.candwasm_interp_fast.cboth fail with use of undeclared identifier 'asm'. The alternative is-DWASM_DISABLE_WRITE_GS_BASE=1, a real upstream knob that also compiles — I did not take it because it turns off an x86_64 fast path to work around a language-mode choice. Happy to switch if you would rather not have a-stdincflags.The POSIX platform files are carried unconditionally. Upstream's
platform_api_posix.cmakedropsposix_file.c,posix_clock.candposix_socket.cunless WASI is on, and the natural translation is a!exclusion in the base with thelibc-wasifeature adding them back. That does not work — the exclusion is global and beats the feature's own entry for the same file, producing a build that compiles and then fails to link:all referenced from the feature's own
sandboxed-system-primitives/src/posix.c. All four files compile cleanly with WASI off, verified individually, so the base just always carries them.Relatedly, a feature cannot carry
include_dirs, and withWASM_ENABLE_LIBC_WASI=1it is not only the feature's sources that need the WASI header roots —common/wasm_runtime_common.hitself opens#include "posix.h", sowasm_loader.candwasm_runtime.cstop compiling without them. Those five roots therefore live in the baseinclude_dirs, where they are inert when the features are off.Features and the ABI question
Both features carry
defines, so I checked them against the rule that keepscompat.recastnavigation'sDT_POLYREF64out of the feature table. NeitherWASM_ENABLE_LIBC_BUILTINnorWASM_ENABLE_LIBC_WASIappears incore/iwasm/include/at all outside comments, so a consumer compiled without them still sees the samewasm_export.hthe library was built against.libc-wasialso needsWASM_ENABLE_MODULE_INST_CONTEXT=1, which is not obvious:build-scripts/runtime_lib.cmake:97-99turns it on together withWAMR_BUILD_LIBC_WASI, and without itwasm_native.ccalls context helpers thatwasm_native.honly declares under that macro.Linux only, on purpose
xpmcarrieslinuxand nothing else, and consumers gate with[target.'cfg(linux)'.dependencies]— thecompat.libaioshape. WAMR itself is portable, there areplatform/darwinandplatform/windowstrees, and the assembly files carry Darwin guards that this.Sdispatcher would honour, so macOS is probably a small delta. But I could not build or run either, and Windows additionally has an unresolved choice between upstream's MASM.asmand the MinGW.svariant. I would rather leave those sections to someone who can verify them than declare platforms because they look symmetric.One scope limit inside
linux, for the same reason: everything built and run here was x86_64. On aarch64 I verified only that the generated dispatcher assembles and definesinvokeNativeunder--target=aarch64-unknown-linux-gnu, and that the config header selectsBUILD_TARGET_AARCH64there. The C half of an aarch64 build is unverified — I have no aarch64 sysroot on this machine, and cross-compiling against the host's headers fails in glibc, not in WAMR. Nothing suggests it is a problem, but I would rather say so than let thelinuxsection imply more testing than happened.Verification
Everything below used the pinned
MCPP_VERSION2026.8.27.2 withMCPP_INDEX_MIRROR=GLOBAL.Lint reproduced locally — lua syntax, required fields, no leading
v,check_mirror_urls.lua,check_package_name.lua, noc++fly, pluscheck_cross_package_refs.lua,check_duplicate_versions.luaandcheck_platform_version_parity.lua. All pass.mcpp xpkg parsereportsparse OK(11 sources, 16 includes, 2 generated files, 2 features).Two members, run from a cleaned
target/,.mcpp/and a cleared global build cache, so both showCompiling compat.wamrrather thanCached:Both test modules are hand-assembled wasm bytes in the test source, so neither member needs a wasm toolchain.
tests/examples/wamris not a link check:compute(6,7)returns 42 only because the guest called back into a nativehost_multhroughinvokeNative, which is exactly what a missingBUILD_TARGET_*or a mis-dispatched assembly file would break.The feature gate is asserted in both directions — positively in
wamr-features, negatively inwamr, where the sameenv.putcharmodule must be refused. Worth recording: the negative check has to call, not instantiate. WAMR does not reject an unresolved import at load or instantiation, it logswarning: failed to link import functionand defers; the refusal only appears on the call. The first version of that test asserted on instantiation and was green for the wrong reason.No CN mirror
I do not have
mcpp-reswrite access, sourlis the plain-string upstream form and CN users fall back to GitHub. Happy for a maintainer to promote it to the{ GLOBAL=…, CN=… }table after mirroring the identical tarball.One note on the skill
.agents/skills/add-mcpp-index-packagestep 8 says to add a row to the category table inREADME.mdandREADME.zh-CN.md. Those tables are gone — the README points at the online index site now and keeps only the short "Reference examples" list. I put the record indocs/descriptor-examples.mdanddocs/zh/descriptor-examples.mdinstead, as a new shape row. Say the word if you would rather it went somewhere else, or if the skill should be updated.Design notes, including the dead ends, are in
.agents/docs/2026-08-30-add-wamr-plan.md.