背景
我是一个 C/C++ 都没实战经验的前端开发,C 在几年前有了解过一些语法知识,现在开始从零开始学习 C++,往期精彩:
注:本文要求至少有一门编程语言的基础。
我的电脑环境:
- mac
- vscode 1.88.1
编写 WebAssembly(Wasm)模块并在网页中使用它是一个非常有趣的过程。WebAssembly 是一种低级字节码格式,可以在网页中高效地运行,适用于性能要求高的应用程序。C++ 是编写 WebAssembly 的常用语言之一,因为它可以编译为 WebAssembly 模块并在浏览器中执行。以下是一个简要的步骤指南,展示了如何使用 C++ 编写 WebAssembly 模块。
1. 准备环境
要编写 WebAssembly 模块,你需要以下工具:
-
Emscripten:这是一个开源工具链,允许你将 C++ 代码编译成 WebAssembly。你可以通过以下命令安装 Emscripten:
# 安装 Emscripten git clone https://github.com/emscripten-core/emsdk.git cd emsdk ./emsdk install latest ./emsdk activate latest source ./emsdk_env.sh
2. 编写 C++ 代码
编写一个简单的 C++ 程序,作为 WebAssembly 模块。创建一个名为 hello.cpp 的文件,内容如下:
#include <iostream>
#include <emscripten.h>
// 这是一个导出的函数,可以在 JavaScript 中调用
extern "C" {
// 使用 EMSCRIPTEN_KEEPALIVE 确保这个函数不会被优化掉
EMSCRIPTEN_KEEPALIVE
int add(int a, int b) {
return a + b;
}
}
vscode 环境报错
这个错误提示通常是因为你的开发环境(如 Visual Studio Code 或其他编辑器)无法找到 C++ 标准库的头文件或你设置的 includePath 不正确。下面是一些常见的解决方案,帮助你更新 includePath 并修复这个问题:
1. 确认 Emscripten 环境设置
确保你已经正确安装并配置了 Emscripten。你可以使用以下命令检查 Emscripten 是否正常工作:
emcc --version
2. 更新 includePath
如果你使用的是 Visual Studio Code(VSCode),你需要更新 C++ 插件的 includePath 设置,以便正确找到头文件。按照以下步骤操作:
2.1. 打开 c_cpp_properties.json
- 打开 VSCode。
- 点击左侧的“资源管理器”图标。
- 进入你项目目录中的
.vscode文件夹。如果没有这个文件夹,你可以创建一个。 - 在
.vscode文件夹中,找到或创建c_cpp_properties.json文件。
2.2. 编辑 c_cpp_properties.json
确保你的 c_cpp_properties.json 文件包含正确的 includePath 配置。以下是一个示例配置,你需要根据你的 Emscripten 安装路径进行调整:
{
"version": 4,
"configurations": [
{
"name": "Emscripten",
"includePath": [
"${workspaceFolder}/**",
"/path/to/emsdk/upstream/emscripten/system/include/**",
"/path/to/emsdk/upstream/emscripten/system/include/libc/**",
"/path/to/emsdk/upstream/emscripten/system/include/libcxx/**",
"/path/to/emsdk/upstream/emscripten/system/include/libcxxabi/**",
"/path/to/emsdk/upstream/emscripten/system/include/SDL2/**"
],
"defines": [],
"compilerPath": "/path/to/emsdk/upstream/emscripten/emcc",
"cStandard": "c11",
"cppStandard": "c++17",
"intelliSenseMode": "clang-x64"
}
]
}
请将 /path/to/emsdk/ 替换为你实际的 Emscripten 安装路径。你可以在 Emscripten 安装目录中找到 include 目录的确切位置。
3. 确保 Emscripten 配置正确
在你的终端中运行以下命令,确保 Emscripten 配置正确,并且环境变量已经设置:
source /path/to/emsdk/emsdk_env.sh
4. 重启编辑器
修改完 c_cpp_properties.json 文件后,重启你的编辑器,以确保新的设置生效。
5. 检查编译器路径
确保在 c_cpp_properties.json 中设置的 compilerPath 指向了正确的编译器。如果你使用的是 Emscripten,它通常位于 /path/to/emsdk/upstream/emscripten/emcc。
6. 使用其他编辑器的设置
如果你使用的是其他编辑器,类似的设置也需要配置。例如,在 CLion 中,你需要在 CMake 配置中指定正确的包含路径。
3. 编译 C++ 代码
使用 Emscripten 工具链将 C++ 代码编译成 WebAssembly 模块。运行以下命令:
emcc hello.cpp -o hello.html -s EXPORTED_FUNCTIONS="['_add']" -s EXPORTED_RUNTIME_METHODS='["ccall", "cwrap"]'
-o hello.html指定输出文件,Emscripten 会生成一个包含 HTML 和 JavaScript 的文件,以便在浏览器中运行 WebAssembly 模块。-s EXPORTED_FUNCTIONS="['_add']"指定需要导出的函数(注意函数名需要加上下划线_)。-s EXPORTED_RUNTIME_METHODS='["ccall", "cwrap"]'允许使用ccall和cwrap方法调用 WebAssembly 中的函数。
提示zsh: command not found: emcc
这个提示表明你的系统无法找到 emcc 命令。这通常是因为 Emscripten 没有正确安装,或者环境变量没有设置好。以下是解决这个问题的步骤:
1. 设置环境变量
在本地path/emsdk/下运行以下指令:
source ./emsdk_env.sh
这会将 emcc 和其他 Emscripten 工具添加到你的 PATH 环境变量中。
2. 确保环境变量设置正确
每次打开一个新的终端窗口时,你需要重新设置 Emscripten 环境变量。为了避免每次都手动设置,你可以将 source ./emsdk_env.sh 添加到你的 shell 启动脚本中(例如 .zshrc 文件),以便每次打开终端时自动设置环境变量:
- 打开或编辑你的
.zshrc文件:
nano ~/.zshrc
- 在文件末尾添加以下行:
source ~/emsdk/emsdk_env.sh
-
保存并关闭文件(在
nano中,你可以按Ctrl + X,然后按Y确认保存)。 -
使更改生效:
source ~/.zshrc
3. 检查 emcc 命令是否可用
在终端中输入以下命令,检查 emcc 是否可以正常运行:
emcc --version
如果一切正常,你应该能够看到 emcc 的版本信息。
4. 其他可能的问题
- 路径问题:确保
emsdk目录和emsdk_env.sh文件的位置正确,并且你设置了正确的路径。 - 权限问题:确保你有权限访问
emsdk目录及其文件。
4. 创建 HTML 文件
Emscripten 会自动生成一个 HTML 文件,但你也可以手动创建一个简单的 HTML 文件来加载和使用生成的 WebAssembly 模块。创建一个名为 index.html 的文件,内容如下:
<!DOCTYPE html>
<html>
<head>
<title>WebAssembly Example</title>
<script src="hello.js"></script>
<script>
// 确保 WebAssembly 模块加载完成后再调用
Module.onRuntimeInitialized = function() {
// 使用 ccall 调用 WebAssembly 中的 add 函数
var result = Module.ccall('add', 'number', ['number', 'number'], [5, 3]);
console.log('Result of add(5, 3):', result);
};
</script>
</head>
<body>
<h1>WebAssembly Example</h1>
</body>
</html>
5. 运行 WebAssembly 模块
使用一个 HTTP 服务器来运行你的 HTML 文件。你可以使用 Python 内置的 HTTP 服务器:
python3 -m http.server
在浏览器中访问 http://localhost:8000,你应该能看到控制台输出结果 Result of add(5, 3): 8。
6. 进一步探索
- 数据交换:你可以通过
ccall和cwrap方法在 JavaScript 和 WebAssembly 之间交换数据。 - 内存管理:了解 WebAssembly 的内存模型,以便高效地处理大数据或复杂计算。
- 优化:Emscripten 提供了许多优化选项,可以提高 WebAssembly 模块的性能。
通过这些步骤,你可以将 C++ 代码编译成 WebAssembly,并在浏览器中运行它。