WebAssembly 与 C++ 入门
现代 Web 开发对性能的要求越来越高,尤其是在图像处理、3D 图形、模拟和密码学等任务中。WebAssembly (WASM) 是一种低级二进制指令格式,在浏览器中以接近原生的速度执行。它允许在 Web 环境中利用 C++ 的强大功能,为开发者开辟了新的可能性。
在本文中,我们将探讨如何将 C++ 代码编译为 WebAssembly,使用 Emscripten 配置环境,将 WASM 模块与 JavaScript 集成,并优化性能。您将了解为什么 C++ 仍然是创建高性能 Web 应用程序的最佳语言之一。
什么是 WebAssembly,C++ 开发者为什么需要它?
WebAssembly 是一个在浏览器中运行的虚拟机。与 JavaScript 不同,WASM 是从 C、C++、Rust 或其他语言编译而来的二进制代码。主要优势包括:
- 性能 — 在计算密集型任务中,WASM 的执行速度比 JavaScript 快 10-50 倍。
- 可移植性 — 相同的代码在 Chrome、Firefox、Safari 和 Edge 中无需修改即可运行。
- 安全性 — WASM 在隔离的沙箱中运行,无法直接访问系统。
- C++ 生态系统 — 您可以在 Web 中重用现有的库(OpenCV、TensorFlow Lite、SQLite)。
C++ 非常适合 WebAssembly,因为它具有高效的内存管理、没有垃圾回收器以及丰富的工具集。例如,Unity 引擎使用 WASM 直接在浏览器中渲染 3D 场景。
环境配置:Emscripten 与将 C++ 编译为 WASM
将 C++ 编译为 WebAssembly 的主要工具是 Emscripten。它包含编译器 emcc,可以将 C++ 代码转换为 .wasm 文件和用于加载的 JavaScript 封装。
安装 Emscripten
# 克隆仓库
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
# 安装最新版本
./emsdk install latest
./emsdk activate latest
# 添加环境变量
source ./emsdk_env.sh
安装后,使用命令 emcc --version 验证是否成功。
第一个示例:"Hello, WASM!"
让我们创建一个简单的 C++ 函数,用于将两个数字相加:
// hello.cpp
#include <emscripten.h>
extern "C" {
int EMSCRIPTEN_KEEPALIVE add(int a, int b) {
return a + b;
}
}
关键点:宏 EMSCRIPTEN_KEEPALIVE 可防止函数在优化时被删除。编译代码:
emcc hello.cpp -o hello.html -s EXPORTED_FUNCTIONS="['_add']" -s EXPORTED_RUNTIME_METHODS="['ccall', 'cwrap']"
标志 -o hello.html 会创建一个包含使用示例的 HTML 文件。在浏览器中打开它,并调用 Module.ccall('add', 'number', ['number', 'number'], [5, 3]) — 结果将为 8。
将 C++ 代码与 JavaScript 集成
编译后,您将获得 .wasm 和 .js 文件。让我们看看如何从 JavaScript 调用 C++ 函数。
通过 ccall/cwrap 进行基本调用
// 在 HTML 中加载脚本后:
Module.onRuntimeInitialized = function() {
const add = Module.cwrap('add', 'number', ['number', 'number']);
console.log('结果:', add(10, 20)); // 30
};
cwrap 方法为函数创建一个封装,可以像普通 JS 函数一样调用。数据类型包括:'number'、'string'、'array'。
内存与数组操作
要传输大量数据(例如图像),请直接操作内存: