| -- WAMR for the wasm scripting backend. Flags proven by the luau_wasm EH | |
| -- spike: sw-bounds artifacts must never unwind through hardware traps | |
| -- (the longjmp skips the sjlj glue's native frames) and libc-wasi must be | |
| -- compiled in (without it emscripten-built module ctors spin; see | |
| -- spike_eh/README.md). Bounds checks default sw; wasm_hw_bounds below. | |
| local dependency = require('dependency') | |
| -- The patch set carries the rive fast-interp fixes (linear_mem_size | |
| -- refreshes around growth, gated OOB diagnostics); a clone without them is | |
| -- subtly wrong under memory growth. | |
| local wamr = dependency.github('bytecodealliance/wasm-micro-runtime', 'WAMR-2.4.5', { | |
| patches = path.join(path.getdirectory(_SCRIPT), 'wamr_patches'), | |
| }) | |
| -- Header-only simd library the fast interpreter's v128 handlers compile | |
| -- against; upstream fetches the same tag through CMake FetchContent. | |
| local simde = dependency.github('simd-everywhere/simde', 'v0.8.2') | |
| -- Struct layouts in wamr's internal headers follow these; any rive TU that | |
| -- includes them (the tier transplant) must compile with the identical set | |
| -- or instance layouts silently diverge. | |
| local wamrConfigDefines = { | |
| 'WASM_ENABLE_INTERP=1', | |
| 'WASM_ENABLE_FAST_INTERP=1', | |
| 'WASM_ENABLE_AOT=1', | |
| 'WASM_ENABLE_JIT=0', | |
| 'WASM_ENABLE_LIBC_BUILTIN=1', | |
| 'WASM_ENABLE_LIBC_WASI=1', | |
| 'WASM_ENABLE_MODULE_INST_CONTEXT=1', | |
| 'WASM_ENABLE_BULK_MEMORY=1', | |
| -- Simde-backed v128 in the fast interpreter; scalar modules | |
| -- translate the same as before, simd modules stop being refused. | |
| 'WASM_ENABLE_SIMD=1', | |
| 'WASM_ENABLE_SIMDE=1', | |
| 'WASM_DISABLE_STACK_HW_BOUND_CHECK=1', | |
| 'BH_MALLOC=wasm_runtime_malloc', | |
| 'BH_FREE=wasm_runtime_free', | |
| } | |
| -- Opt-in hw bounds serve AOT artifacts compiled --bounds-checks=0 only: | |
| -- patch 0009 keeps the interpreter sw-checked and patch 0010 keeps sw | |
| -- artifacts unwinding by checked returns, so the Luau lane never takes | |
| -- a hardware trap. Native stack checks stay sw everywhere (artifacts | |
| -- must carry --stack-bounds-checks=1). | |
| if not _OPTIONS['wasm_hw_bounds'] then | |
| table.insert(wamrConfigDefines, 'WASM_DISABLE_HW_BOUND_CHECK=1') | |
| end | |
| if os.target() == 'windows' then | |
| -- We link wamr statically; under clang's msvc mode wasm_export.h and | |
| -- wasm_c_api.h otherwise declare every API dllimport. | |
| table.insert(wamrConfigDefines, 'WASM_RUNTIME_API_EXTERN=') | |
| table.insert(wamrConfigDefines, 'WASM_API_EXTERN=') | |
| end | |
| -- os.target() stays the host under --for_android; the option is the | |
| -- truth for the platform dir. | |
| local forAndroid = _OPTIONS['for_android'] ~= nil | |
| local platformDir = forAndroid and 'android' | |
| or os.target() == 'linux' and 'linux' | |
| or os.target() == 'windows' and 'windows' | |
| or 'darwin' | |
| project('wamr') | |
| do | |
| kind('StaticLib') | |
| language('C') | |
| warnings('Off') | |
| -- Vendored dep nobody debugs into: an unoptimized interpreter is 6x | |
| -- slower, so every config builds it optimized. NDEBUG matches the CMake | |
| -- Release baseline; without it the interpreter's computed-goto dispatch | |
| -- tail-merges into a single prediction-killing branch. | |
| optimize('Speed') | |
| defines({ 'NDEBUG' }) | |
| -- Replicated per-handler dispatch is what makes the fast interpreter | |
| -- fast; default heuristics tail-merge the computed gotos into a single | |
| -- indirect branch (+27% on box2d). Guarded by bench/check_dispatch_sites. | |
| -- LTO would run codegen at link where these -mllvm knobs cannot reach, | |
| -- so this library opts out and keeps its dispatch replication. | |
| buildoptions({ '-fno-lto' }) | |
| -- The tail-dup knobs need llvm 19; older clangs build correct but | |
| -- slower dispatch, still caught by the dispatch-site guard where it runs. | |
| -- The probe runs host clang; cross toolchains (the NDK's) may reject | |
| -- the knobs the host accepts, so cross builds keep default dispatch. | |
| local devNull = os.ishost('windows') and 'NUL' or '/dev/null' | |
| local _, tailDupProbe = os.outputof( | |
| 'clang -fsyntax-only -x c ' .. devNull .. | |
| ' -mllvm -tail-dup-pred-size=5000' .. | |
| ' -mllvm -tail-dup-succ-size=5000 2>&1' | |
| ) | |
| if tailDupProbe == 0 and _OPTIONS['for_android'] == nil then | |
| buildoptions({ | |
| '-mllvm -tail-dup-pred-size=5000', | |
| '-mllvm -tail-dup-succ-size=5000', | |
| }) | |
| end | |
| defines(wamrConfigDefines) | |
| filter({ 'system:macosx' }) | |
| defines({ 'BH_PLATFORM_DARWIN' }) | |
| filter({ 'system:linux' }) | |
| defines({ 'BH_PLATFORM_LINUX' }) | |
| filter({ 'system:android' }) | |
| defines({ 'BH_PLATFORM_ANDROID' }) | |
| filter({ 'system:windows' }) | |
| defines({ | |
| 'BH_PLATFORM_WINDOWS', | |
| 'HAVE_STRUCT_TIMESPEC', | |
| '_WINSOCK_DEPRECATED_NO_WARNINGS', | |
| }) | |
| filter({}) | |
| -- Per-lane arch beats host arch: universal builds compile both lanes | |
| -- on one machine and each must get its own invoke shim and relocs. | |
| local archOption = _OPTIONS['arch'] | |
| local machine = os.outputof('uname -m') | |
| local isArm64 | |
| -- 'host' is the option's default, not an explicit lane. | |
| if archOption ~= nil and archOption ~= '' and archOption ~= 'host' then | |
| isArm64 = archOption == 'arm64' or archOption == 'aarch64' | |
| else | |
| isArm64 = machine == 'arm64' or machine == 'aarch64' | |
| end | |
| local isArm32 = forAndroid and archOption == 'arm' | |
| -- The quoted string define goes through buildoptions pre-escaped so both | |
| -- the gmake and ninja generators deliver the quotes to the compiler. | |
| if isArm32 then | |
| -- NDK armv7 compiles thumb2 with NEON/VFP by default. Upstream's | |
| -- thumb reloc does pointer arithmetic clang 18 makes a hard error. | |
| -- The THUMBV7 string matters: the aot loader matches it against | |
| -- wamrc's thumbv7 artifacts (bare THUMB defaults to thumbv4t). | |
| defines({ 'BUILD_TARGET_THUMB_VFP' }) | |
| buildoptions({ | |
| '-DBUILD_TARGET=\\"THUMBV7\\"', | |
| '-Wno-int-conversion', | |
| }) | |
| elseif isArm64 then | |
| defines({ 'BUILD_TARGET_AARCH64' }) | |
| buildoptions({ '-DBUILD_TARGET=\\"AARCH64\\"' }) | |
| else | |
| defines({ 'BUILD_TARGET_X86_64' }) | |
| buildoptions({ '-DBUILD_TARGET=\\"X86_64\\"' }) | |
| end | |
| -- em64 is WAMR's x86-64 SysV invoke shim. With WASM_ENABLE_SIMD the | |
| -- invoke marshaling widens float slots to v128, so the shim must be the | |
| -- _simd variant or int registers load from the wrong offsets. arm32 has | |
| -- no simd invoke variant; its marshaling never widens. Windows takes | |
| -- the mingw shim: same Win64 ABI as MSVC targets, and GAS syntax that | |
| -- clang's integrated assembler handles without ml64. | |
| local invokeNative = isArm32 and 'invokeNative_thumb_vfp.s' | |
| or isArm64 and 'invokeNative_aarch64_simd.s' | |
| or os.target() == 'windows' and 'invokeNative_mingw_x64_simd.s' | |
| or 'invokeNative_em64_simd.s' | |
| local aotReloc = isArm32 and 'aot_reloc_thumb.c' | |
| or isArm64 and 'aot_reloc_aarch64.c' | |
| or 'aot_reloc_x86_64.c' | |
| includedirs({ | |
| wamr .. '/core/iwasm/include', | |
| wamr .. '/core/iwasm/common', | |
| wamr .. '/core/iwasm/aot', | |
| wamr .. '/core/iwasm/interpreter', | |
| wamr .. '/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include', | |
| wamr .. '/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src', | |
| wamr .. '/core/shared/include', | |
| wamr .. '/core/shared/platform/include', | |
| -- platform_internal.h comes from the per-platform dir. | |
| wamr .. '/core/shared/platform/' .. platformDir, | |
| wamr .. '/core/shared/platform/common/libc-util', | |
| wamr .. '/core/shared/mem-alloc', | |
| -- wasm_runtime_common.h pulls the wasi primitives when libc-wasi is | |
| -- on, which our config always is. | |
| wamr .. '/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src', | |
| wamr .. '/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include', | |
| wamr .. '/core/shared/utils', | |
| wamr .. '/core/shared/utils/uncommon', | |
| simde, | |
| }) | |
| files({ | |
| wamr .. '/core/iwasm/common/*.c', | |
| wamr .. '/core/iwasm/common/arch/' .. invokeNative, | |
| wamr .. '/core/iwasm/interpreter/wasm_loader.c', | |
| wamr .. '/core/iwasm/interpreter/wasm_runtime.c', | |
| wamr .. '/core/iwasm/interpreter/wasm_interp_fast.c', | |
| wamr .. '/core/iwasm/aot/*.c', | |
| wamr .. '/core/iwasm/aot/arch/' .. aotReloc, | |
| wamr .. '/core/iwasm/libraries/libc-builtin/*.c', | |
| wamr .. '/core/iwasm/libraries/libc-wasi/**.c', | |
| wamr .. '/core/shared/platform/' .. platformDir .. '/*.c', | |
| -- Windows replaces the posix layer wholesale; win_atomic is C++. | |
| os.target() == 'windows' | |
| and (wamr .. '/core/shared/platform/windows/*.cpp') | |
| or (wamr .. '/core/shared/platform/common/posix/*.c'), | |
| wamr .. '/core/shared/platform/common/memory/*.c', | |
| wamr .. '/core/shared/platform/common/libc-util/*.c', | |
| wamr .. '/core/shared/mem-alloc/*.c', | |
| wamr .. '/core/shared/mem-alloc/ems/*.c', | |
| wamr .. '/core/shared/utils/*.c', | |
| wamr .. '/core/shared/utils/uncommon/*.c', | |
| }) | |
| if os.target() == 'windows' then | |
| -- Linux perf-map support; leans on pid_t/getpid. | |
| removefiles({ wamr .. '/core/iwasm/aot/aot_perf_map.c' }) | |
| end | |
| end | |
| return { | |
| wamr = wamr, | |
| configDefines = wamrConfigDefines, | |
| internalIncludes = { | |
| wamr .. '/core/iwasm/interpreter', | |
| wamr .. '/core/iwasm/aot', | |
| wamr .. '/core/iwasm/common', | |
| wamr .. '/core/shared/include', | |
| wamr .. '/core/shared/platform/include', | |
| -- platform_internal.h comes from the per-platform dir. | |
| wamr .. '/core/shared/platform/' .. platformDir, | |
| wamr .. '/core/shared/mem-alloc', | |
| -- wasm_runtime_common.h pulls the wasi primitives when libc-wasi is | |
| -- on, which our config always is. | |
| wamr .. '/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src', | |
| wamr .. '/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include', | |
| wamr .. '/core/shared/utils', | |
| }, | |
| } |