这是一篇关于使用 Emscripten 将 C/C++代码构建为可在 Web 浏览器中运行的 Web 应用程序的教程文章,主要内容总结如下:
- 介绍:作者通过将自己的魔方最优求解器转换为 Web 应用程序,学习了使用 Emscripten 将 C 代码编译为 WebAssembly 并与 JavaScript 和 HTML 结合的过程,介绍了使用 WebAssembly 的原因,以及该教程不适合初学者,适合 C/C++开发者将程序或库移植到 Web 的情况。
- 设置环境:教程示例包含在 git 仓库中,需要安装 Emscripten(包含 Node.js)和 web 服务器(如 darkhttpd 或 Python 的
http.server
包),作者仅在 Linux 上测试过,Windows 用户可在 WSL 中运行或调整示例。 - Hello World:编译简单的 C 代码
hello.c
为 Web 应用程序,生成index.html
、index.wasm
和index.js
文件,可在浏览器或终端中运行,展示了基本的编译和运行过程。 - 中间环节 I:WebAssembly 是什么:介绍了 WebAssembly 是一种在 Web 浏览器虚拟机中运行的低级语言,动机是提供接近原生的性能,早期 Emscripten 将 C/C++代码编译为 JavaScript 的子集 asm.js,WebAssembly 有文本表示形式,2025 年初之前是 32 位架构,目前 Firefox 和 Chrome 支持 64 位指针的 WASM64 标准。
- 构建库:将 C 库编译为 WebAssembly 并从 JavaScript 调用,使用
emcc
命令生成library.js
和library.wasm
文件,需要指定要导出的函数,使用onRuntimeInitialized
回调函数处理异步初始化,展示了简单库的构建和调用过程。 - 中间环节 II:JavaScript 和 DOM:介绍了 JavaScript 与文档对象模型(DOM)的交互,通过
getElementById
、innerText
等方法访问和修改 HTML 元素的内容,还展示了如何在 HTML 中加载外部 JavaScript 脚本,并使用defer
属性确保脚本在页面加载完成后执行。 - 加载库并使其成为模块:构建模块化的库,使用
emcc
的-sMODULARIZE
、-sEXPORT_NAME
等选项生成library.mjs
文件,在 Node.js 和浏览器中使用模块的方式不同,需要注意文件扩展名和服务器配置,展示了模块化库的构建和使用方法。 - 多线程:将多线程应用程序移植到 Web,使用 pthreads 实现并行计算,在浏览器中运行多线程代码需要设置
Cross-Origin-Opener-Policy
和Cross-Origin-Embedder-Policy
HTTP 头,展示了多线程程序的构建和运行。 - 中间环节 III:Web Workers 和 Spectre:介绍了 Web Workers 是与主网页进程分离的进程,用于在后台运行慢操作而不阻塞 UI 线程,Web Workers 与主进程的内存隔离,Spectre 漏洞导致浏览器需要安全上下文和跨源隔离才能使用
SharedArrayBuffer
,需要设置Cross-Origin-*
头。 - 不要阻塞主线程!:通过 Web Worker 解决多线程计算阻塞主线程的问题,主脚本负责与用户交互和发送计算请求,Worker 负责计算并返回结果,展示了使用 Web Worker 优化多线程程序的方法。
- 回调函数:实现接受另一个函数作为参数的库函数,在 JavaScript 中通过
addFunction
和UTF8ToString
等 Emscripten 函数将 JavaScript 函数转换为 C 函数指针,展示了回调函数的使用方法和相关编译器标志的设置。 - 持久存储:通过使用 IndexedDB API 将数据持久存储在浏览器的缓存中,介绍了 Emscripten 的文件系统 API 及其不同的后端,使用
--lidbfs.js
编译器选项激活IDBFS
后端,通过 JavaScript 代码设置和同步虚拟文件系统,展示了如何在 Web 应用程序中实现持久存储。 - 总结思考:作者讨论了在使用 Emscripten 构建 Web 应用程序过程中所学的知识,包括一些 C++特定的功能,如
EMBIND()
和emscripten::val
,并总结了对抽象的理解,即所有抽象都有泄漏,Emscripten 虽然抽象了 Web 相关的细节,但在代码复杂度增加时仍需要了解底层系统。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。