必须使用 wasi-sdk 而非 wabt 或 wasi-libc 单独安装,因其含完整工具链(clang++、wasi-libc、target 配置);编译需指定 --sysroot 和 -Wl,--no-entry,C++ 代码须避免全局构造器,且生成的 wasm 需 WASI runtime(如 wasmtime)而非浏览器直接运行。

用 wasi-sdk 编译 C++ 代码前,先确认你装的是 wasi-sdk 而不是 wabt 或 wasi-libc
很多人卡在第一步:以为装了 wabt(提供 wasm-objdump 等工具)就能编译 WASI,其实不行。wasi-sdk 是完整工具链,自带 clang++、wasi-libc 和 target 配置。官方预编译包地址是 https://github.com/WebAssembly/wasi-sdk/releases,下载解压后把 bin/ 加进 $PATH。
- 验证是否可用:
wasi-sdk/bin/clang++ --version应显示类似clang version 17.0.0 (https://github.com/WebAssembly/wasi-sdk.git 123abc) - 别用系统自带的
clang++加--target=wasi—— 它默认不链接wasi-libc,会报undefined reference to '__wasi_args_get' - macOS 用户注意:Apple Silicon 上运行 x86_64 的
wasi-sdk二进制可能失败,优先选 arm64 版本(如wasi-sdk-23.0-arm64.tar.gz)
clang++ 命令必须带 --sysroot 和 -Wl,--no-entry
WASI 没有传统 C runtime 入口(比如 main 不是直接调用,而是由 host 提供启动环境),所以链接器不能假设存在 _start。同时,wasi-libc 头文件和库不在系统路径,得显式指定 sysroot。
- 最简可运行命令:
wasi-sdk/bin/clang++ -O2 --sysroot=wasi-sdk/share/wasi-sysroot -Wl,--no-entry hello.cpp -o hello.wasm -
--sysroot必须指向wasi-sdk/share/wasi-sysroot,否则#include <iostream>会报错找不到bits/c++config.h -
-Wl,--no-entry告诉 linker 不要校验入口符号;漏掉它会报error: entry symbol not defined (pass --no-entry to suppress) - 如果用了
std::cout,还得加-lc++(C++ 标准库)和-lc++abi,否则链接失败 ——wasi-libc只提供 C 库,C++ 运行时是额外组件
WASI 不支持全局构造器和 atexit,std::ios_base::Init 会静默失效
WASI 环境没有进程生命周期管理机制,C++ 全局对象构造/析构、atexit 注册的函数都不会被调用。这意味着依赖静态初始化的代码(比如 iostream 的隐式初始化)可能行为异常 —— std::cout << "hello" 在某些版本里输出为空或 crash。
- 安全做法:避免全局
std::ofstream、std::mutex等;所有资源在main()内显式构造 - 若必须用 iostream,加
-D_WASI_EMULATED_PROCESS_CLOCKS -D_WASI_EMULATED_SIGNALS(部分 SDK 版本需要) - 更稳妥的替代:用
__wasi_fd_write直接写 stdout,绕过 libc++ 的初始化逻辑 - 检查是否生效:用
wabt/wasm-objdump -x hello.wasm | grep -A5 "Import section",看到env.__wasi_snapshot_preview1.fd_write才说明 I/O 调用能落地
生成的 .wasm 文件不能直接浏览器运行,得用 WASI runtime 加载
浏览器的 WebAssembly API 默认只支持 web 环境(无文件、无命令行参数),而 WASI 是独立标准,需要专门的 runtime 支持。你编译出的 hello.wasm 在浏览器里 WebAssembly.instantiateStreaming() 会立即失败,报 LinkError: import object field 'env' is not a module。
立即学习“C++免费学习笔记(深入)”;
- 本地测试用
wasmtime hello.wasm(需安装 wasmtime)或wasmer run hello.wasm - 想在浏览器跑?得用
WASI polyfill(如@bjorn3/browser_wasi_shim),并手动注入fs、args、env等 namespace - 注意 ABI 版本:
wasi-sdk-21+默认生成preview1,但新版wasmtime已默认启用preview2,可能不兼容 —— 编译时加--target=wasm32-wasi-threads或降级 SDK



















