WebAssembly与C++简介
现代网页开发不断寻求提升性能的方法。WebAssembly (Wasm) 是一种低层级的二进制指令格式,能在浏览器中以接近原生的速度执行。结合C++这一最快、最强大的编程语言之一,Wasm开辟了新天地:从高性能游戏和模拟,到直接在浏览器中运行的复杂数据处理算法。
本文将带您从基础走向实践:讲解如何将C++代码编译为WebAssembly,在浏览器中运行,并优化以获得最佳性能。
1. 工具集与环境配置
将C++编译为WebAssembly的主要工具是Emscripten编译器套件。它将LLVM字节码转换为Wasm,并自动生成加载模块所需的JavaScript胶水代码。
安装Emscripten
推荐的安装方式是通过包管理器emsdk:
# 克隆仓库git clone https://github.com/emscripten-core/emsdk.gitcd emsdk
# 安装并激活最新版本./emsdk install latest./emsdk activate latest
# 添加环境变量(shell变量)source ./emsdk_env.sh安装后,您将获得emcc(C编译器)和em++(C++编译器)命令,它们是Clang的封装。
2. 将C++编译为WebAssembly
来看一个最简单的例子。创建文件hello.cpp:
#include <emscripten/emscripten.h>
// 可从JavaScript调用的函数extern "C" { int EMSCRIPTEN_KEEPALIVE add(int a, int b) { return a + b; }}关键元素是宏EMSCRIPTEN_KEEPALIVE。它防止优化器删除该函数,并使其成为可导出的。
编译我们的代码:
em++ hello.cpp -o hello.html -s WASM=1 -s EXPORTED_FUNCTIONS='["_add"]' -O3参数说明:
-o hello.html— 创建一个包含运行示例的HTML文件。-s WASM=1— 明确指定生成Wasm(默认已启用)。-s EXPORTED_FUNCTIONS='["_add"]'— 导出的函数列表(带前缀_)。-O3— 高级优化。
结果将生成三个文件:hello.html、hello.js(胶水代码)和hello.wasm。
3. 与JavaScript交互
编译后,我们可以从JavaScript调用C++函数。以下是加载模块的最小代码:
<!DOCTYPE html><html><head> <script> var Module = {}; Module.onRuntimeInitialized = function() { // 现在可以访问add函数 var result = Module._add(5, 7); console.log("结果: " + result); // 12 }; </script> <script src="hello.js"></script></head><body></body></html>关键点:
Module.onRuntimeInitialized— 在Wasm模块加载完成后触发的事件。- JS中的函数名带有前缀
_(例如_add)。 - 传递复杂数据结构(字符串、数组)时,需使用
Module._malloc和指针。
传递字符串
返回问候语的函数示例:
// C++代码extern "C" { const char* EMSCRIPTEN_KEEPALIVE greet(const char* name) { static std::string msg = "Hello, " + std::string(name) + "!"; return msg.c_str(); }}在JavaS