{
  "schemaVersion": "0.11.0",
  "canonical": "https://www.pystone.net/notes/emscripten-cpp-compile-workflow/",
  "atlas": "https://www.pystone.net/?node=emscripten-cpp-compile-workflow#knowledge-atlas",
  "markdown": "https://www.pystone.net/notes/emscripten-cpp-compile-workflow.md",
  "context": "https://www.pystone.net/notes/emscripten-cpp-compile-workflow.context.json",
  "knowledgeVersion": "224c990773de.5fa8af6e39fa",
  "build": {
    "siteCommit": "224c990773de166d23a886306577dd90379529ce",
    "notesCommit": "5fa8af6e39fa3891d1b9b4832bfa6c4e0ecaaf0a",
    "builtAt": "1970-01-01T00:00:00.000Z",
    "version": "224c990773de.5fa8af6e39fa"
  },
  "id": "note:emscripten-cpp-compile-workflow",
  "slug": "emscripten-cpp-compile-workflow",
  "title": "Emscripten-C++编译流程",
  "type": "note",
  "visibility": "public",
  "idStability": "rename-stable",
  "author": {
    "name": "Perrin Yong",
    "profile": "https://www.pystone.net/profile/"
  },
  "publisher": {
    "name": "Perrin Yong",
    "profile": "https://www.pystone.net/profile/"
  },
  "aliases": [],
  "summary": "Emscripten C++编译流程",
  "contentRole": "unspecified",
  "isMoc": false,
  "mocRecognition": "none",
  "generated": false,
  "attribution": "unspecified",
  "domain": "10-计算机、信息技术与工程",
  "tags": [],
  "mocs": [],
  "contentHash": "3e5c7f75a8305916db146684d64187822f8273deef2f3d156a732944232baebb",
  "assets": [],
  "headings": [
    {
      "depth": 1,
      "text": "Emscripten-C++编译流程",
      "anchor": "emscripten-c编译流程",
      "citation": "https://www.pystone.net/notes/emscripten-cpp-compile-workflow/#emscripten-c%E7%BC%96%E8%AF%91%E6%B5%81%E7%A8%8B"
    },
    {
      "depth": 2,
      "text": "Emscripten-C++ 编译流水线",
      "anchor": "emscripten-c-编译流水线",
      "citation": "https://www.pystone.net/notes/emscripten-cpp-compile-workflow/#emscripten-c-%E7%BC%96%E8%AF%91%E6%B5%81%E6%B0%B4%E7%BA%BF"
    },
    {
      "depth": 3,
      "text": "0 · 驱动入口",
      "anchor": "0-驱动入口",
      "citation": "https://www.pystone.net/notes/emscripten-cpp-compile-workflow/#0-%E9%A9%B1%E5%8A%A8%E5%85%A5%E5%8F%A3"
    },
    {
      "depth": 3,
      "text": "1 · 预处理（与传统一致，简述）",
      "anchor": "1-预处理与传统一致简述",
      "citation": "https://www.pystone.net/notes/emscripten-cpp-compile-workflow/#1-%E9%A2%84%E5%A4%84%E7%90%86%E4%B8%8E%E4%BC%A0%E7%BB%9F%E4%B8%80%E8%87%B4%E7%AE%80%E8%BF%B0"
    },
    {
      "depth": 3,
      "text": "2 · 前端解析 → LLVM IR（与传统一致，简述）",
      "anchor": "2-前端解析-llvm-ir与传统一致简述",
      "citation": "https://www.pystone.net/notes/emscripten-cpp-compile-workflow/#2-%E5%89%8D%E7%AB%AF%E8%A7%A3%E6%9E%90-llvm-ir%E4%B8%8E%E4%BC%A0%E7%BB%9F%E4%B8%80%E8%87%B4%E7%AE%80%E8%BF%B0"
    },
    {
      "depth": 3,
      "text": "3 · LLVM IR → Wasm Relocatable Object（差异重点）",
      "anchor": "3-llvm-ir-wasm-relocatable-object差异重点",
      "citation": "https://www.pystone.net/notes/emscripten-cpp-compile-workflow/#3-llvm-ir-wasm-relocatable-object%E5%B7%AE%E5%BC%82%E9%87%8D%E7%82%B9"
    },
    {
      "depth": 3,
      "text": "4 · 归档静态库（与传统基本一致，简述）",
      "anchor": "4-归档静态库与传统基本一致简述",
      "citation": "https://www.pystone.net/notes/emscripten-cpp-compile-workflow/#4-%E5%BD%92%E6%A1%A3%E9%9D%99%E6%80%81%E5%BA%93%E4%B8%8E%E4%BC%A0%E7%BB%9F%E5%9F%BA%E6%9C%AC%E4%B8%80%E8%87%B4%E7%AE%80%E8%BF%B0"
    },
    {
      "depth": 3,
      "text": "5 · 链接：wasm-ld + Binaryen（差异重点）",
      "anchor": "5-链接wasm-ld-binaryen差异重点",
      "citation": "https://www.pystone.net/notes/emscripten-cpp-compile-workflow/#5-%E9%93%BE%E6%8E%A5wasm-ld-binaryen%E5%B7%AE%E5%BC%82%E9%87%8D%E7%82%B9"
    },
    {
      "depth": 3,
      "text": "6 · Glue 代码与打包（差异重点）",
      "anchor": "6-glue-代码与打包差异重点",
      "citation": "https://www.pystone.net/notes/emscripten-cpp-compile-workflow/#6-glue-%E4%BB%A3%E7%A0%81%E4%B8%8E%E6%89%93%E5%8C%85%E5%B7%AE%E5%BC%82%E9%87%8D%E7%82%B9"
    },
    {
      "depth": 3,
      "text": "7 · 整体回顾",
      "anchor": "7-整体回顾",
      "citation": "https://www.pystone.net/notes/emscripten-cpp-compile-workflow/#7-%E6%95%B4%E4%BD%93%E5%9B%9E%E9%A1%BE"
    },
    {
      "depth": 2,
      "text": "WebAssembly程序的一些特点",
      "anchor": "webassembly程序的一些特点",
      "citation": "https://www.pystone.net/notes/emscripten-cpp-compile-workflow/#webassembly%E7%A8%8B%E5%BA%8F%E7%9A%84%E4%B8%80%E4%BA%9B%E7%89%B9%E7%82%B9"
    },
    {
      "depth": 3,
      "text": "内存模型简述",
      "anchor": "内存模型简述",
      "citation": "https://www.pystone.net/notes/emscripten-cpp-compile-workflow/#%E5%86%85%E5%AD%98%E6%A8%A1%E5%9E%8B%E7%AE%80%E8%BF%B0"
    },
    {
      "depth": 3,
      "text": "虚拟文件系统",
      "anchor": "虚拟文件系统",
      "citation": "https://www.pystone.net/notes/emscripten-cpp-compile-workflow/#%E8%99%9A%E6%8B%9F%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F"
    },
    {
      "depth": 3,
      "text": "多线程",
      "anchor": "多线程",
      "citation": "https://www.pystone.net/notes/emscripten-cpp-compile-workflow/#%E5%A4%9A%E7%BA%BF%E7%A8%8B"
    },
    {
      "depth": 3,
      "text": "压缩与体积优化",
      "anchor": "压缩与体积优化",
      "citation": "https://www.pystone.net/notes/emscripten-cpp-compile-workflow/#%E5%8E%8B%E7%BC%A9%E4%B8%8E%E4%BD%93%E7%A7%AF%E4%BC%98%E5%8C%96"
    }
  ],
  "claims": [],
  "outgoing": [
    {
      "id": "note:cpp-compilation-pipeline",
      "title": "C++ 编译流程",
      "url": "https://www.pystone.net/notes/cpp-compilation-pipeline/",
      "atlas": "https://www.pystone.net/?node=cpp-compilation-pipeline#knowledge-atlas",
      "label": "C++ 编译流程",
      "origin": "explicit",
      "humanReviewed": true,
      "context": "Emscripten-C++编译流程中的“C++ 编译流程”导航项",
      "citation": "https://www.pystone.net/notes/emscripten-cpp-compile-workflow/#emscripten-c%E7%BC%96%E8%AF%91%E6%B5%81%E7%A8%8B"
    }
  ],
  "incoming": [
    {
      "id": "note:game-graphics-and-runtime",
      "title": "游戏图形与运行时",
      "url": "https://www.pystone.net/notes/game-graphics-and-runtime/",
      "atlas": "https://www.pystone.net/?node=game-graphics-and-runtime#knowledge-atlas",
      "label": "游戏图形与运行时",
      "origin": "explicit",
      "humanReviewed": true,
      "context": "WebGL中的“Emscripten-C++编译流程”导航项",
      "citation": "https://www.pystone.net/notes/game-graphics-and-runtime/#webgl"
    }
  ],
  "contentMarkdown": "# Emscripten-C++编译流程\n\n[C++ 编译流程](5%20信息技术领域/编程语言及特性/C++%20编译流程.md)\n\n\n## Emscripten-C++ 编译流水线\n\n> **目标**：将 C/C++ 源文件构建为可在浏览器或 Node.js 中运行的 **WebAssembly (.wasm)**。\n> 传统 C++ 流程的 **预处理、AST 生成、IR 优化** 与此处完全一致，以下仅作一行提及；其余 **与原生 ELF/PE 流程不同的环节** 逐步展开。\n\n---\n\n### 0 · 驱动入口\n\n```bash\nemcc hello.cpp -O2 -sSTANDALONE_WASM=1 -o hello.wasm\n```\n\n`emcc` 是官方 Python 封装脚本，内部调用 **Clang → wasm-ld → Binaryen** 这条 LLVM-系工具链。流程如下。\n\n---\n\n### 1 · 预处理（与传统一致，简述）\n\n```bash\nemcc -E hello.cpp -o hello.i\n```\n\n* 展开宏与头文件，得到 `hello.i`（纯文本）。\n* 与 GCC/Clang 原生流程完全相同，故不再赘述。\n\n---\n\n### 2 · 前端解析 → LLVM IR（与传统一致，简述）\n\n```bash\nemcc -emit-llvm -S hello.cpp -o hello.ll\n```\n\n* Clang 生成 **LLVM IR**（文本 `.ll` 或二进制 `.bc`）。\n* 若启用 `-flto`，Bitcode 在稍后链接阶段参与全局优化。\n\n```cpp\n; ModuleID = 'hello.cpp'\nsource_filename = \"hello.cpp\"\ntarget datalayout = \"...\"\ntarget triple = \"x86_64-unknown-linux-gnu\"\n\n@_ZSt4cout = external dso_local global %class.std::ostream, align 8\n\n; 定义 square\ndefine dso_local i32 @_Z6squarei(i32 %x) #0 {\nentry:\n  %mul = mul nsw i32 %x, %x\n  ret i32 %mul\n}\n\n; 定义 main\ndefine dso_local i32 @_Z4main() #0 {\nentry:\n  ; 调用 square(3)\n  %call = call i32 @_Z6squarei(i32 3)\n  ; 打印\n  %0 = call %class.std::ostream* @_ZStlsISt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKc(\n            %class.std::ostream* @_ZSt4cout, i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str, i32 0, i32 0))\n  ; ...\n  ret i32 0\n}\n\n```\n\n---\n\n### 3 · LLVM IR → **Wasm Relocatable Object**（差异重点）\n\n```bash\nemcc -c hello.cpp -o hello.o          # 默认 -sWASM_OBJECT_FILES=1\n```\n\n**目标后端切换**\n   * LLVM 选用 `wasm32-unknown-emscripten` 后端，将 SSA-IR 翻译为 **WebAssembly 指令流**，而非 x86/AArch64 机器码。\n**封装格式**\n   * 产物 `hello.o` 是 **Wasm Relocatable Object**（非 ELF）：\n\n     * 含 `.text` (函数)、`.data` (静态数据) 等节区；\n     * 保留重定位表，供后续链接器合并。\n     * 内部仍是 LLVM IR bitcode，但用 Wasm 格式封装。\n\n*调试查看\n\n```bash\nllvm-objdump -d hello.o        # 反汇编 Wasm 指令\n```\n\n> LLVM Wasm 后端自 3.37+ 版本起已默认稳定，可直接生成可链接对象文件。([github.com][1])\n\n---\n\n### 4 · 归档静态库（与传统基本一致，简述）\n\n```bash\nemar rcs libhello.a hello.o\n```\n\n* `emar` 行为等同 GNU `ar`，成员可为 `.o` 或 `.bc`。\n* 若希望在链接阶段做 **ThinLTO**，可直接归档 `.bc` 文件而非 `.o`。\n\n* **Bitcode Archive**（Emscripten 默认）：当 bitcode 构建开启时，`libhello.a` 的成员是 LLVM IR bitcode 模块（`.bc` 或 `.o` 内含 bitcode）。\n- 用 `ar t libhello.a` 可以列出成员文件；`file <member>` 能区分是 ELF 还是 LLVM bitcode。\n\n```text\nllvm-objdump --headers xxx.a\n```\n\n```python\nIdx Name                Size     VMA      Type\n  0 TYPE                00000073 00000000\n  1 IMPORT              000009d7 00000000\n  2 FUNCTION            00000627 00000000\n  3 ELEM                000000c2 00000000\n  4 DATACOUNT           00000002 00000000\n  5 CODE                000430ba 00000000 TEXT\n  6 DATA                00001221 00000000 DATA\n  7 .debug_loc          000000ae 00000000\n  8 .debug_abbrev       00000b32 00000000\n  9 .debug_info         00034bde 00000000\n 10 .debug_ranges       000031d8 00000000\n 11 .debug_str          00058a86 00000000\n 12 .debug_line         00016596 00000000\n 13 linking             000471de 00000000\n 14 reloc.CODE          0000a78f 00000000\n 15 reloc.DATA          00000543 00000000\n 16 reloc..debug_loc    0000001d 00000000\n 17 reloc..debug_info   0001ee19 00000000\n 18 reloc..debug_ranges 00004e9f 00000000\n 19 reloc..debug_line   000029d2 00000000\n 20 producers           00000086 00000000\n 21 target_features     0000000d 00000000\n```\n\n### 5 · 链接：**wasm-ld + Binaryen**（差异重点）\n\n```bash\nemcc main.o libhello.a -O2 -sSTANDALONE_WASM=1 -o hello.wasm\n```\n\n1. **wasm-ld**\n   * 解析符号、执行 LTO（若输入为 `.bc`）。\n   * 完成地址布局与重定位，输出初步 `a.out.wasm`。([stackoverflow.com][2])\n1. **wasm-opt（Binaryen）**\n   * 根据 `-O0/1/2/3/s/z` 级别进行 Wasm-SSA 优化、栈化、死码删除、SIMD 展开等。\n   * 体积与性能的最后一跳压缩。([github.com][1], [web.dev][3])\n\n生成结果：\n- `hello.wasm` —— 纯二进制 WebAssembly。不包含它那一套运行时 glue（文件系统、SDL、堆内存管理等 JS 接口），只输出一个自洽的 `.wasm` 模块。\n- 适合在你自己的加载器（或 Node.js、Unity、嵌入式）里直接用 `WebAssembly.instantiate`。\n\n### 6 · Glue 代码与打包（差异重点）\n\n```bash\n# Emscripten-C++编译流程\nemcc hello_wasm.o \\\n     -O2 \\\n     --emit-symbol-map \\\n     -o hello.html\n```\n\n* **输出名决定打包形式**\n\n| `-o` 目标      | 生成文件                      | 说明                           |\n| :--------------- | :--------------------- | :-------------------------------- |\n| `hello.wasm` | 仅 `.wasm`                 | 纯 Wasm，适合自行加载                |\n| `hello.js`   | `.wasm` + `.js`           | JS 加载器（含 Emscripten runtime） |\n| `hello.html` | `.wasm` + `.js` + `.html` | 可即点即开的测试页                    |\n\n- `.js` 文件里包含了 Emscripten runtime（堆管理、文件 I/O、C 库接口）\n- `.html` 只是给你一个“点它就能跑”的 demo 页面\n\n* **运行示例（纯 Wasm）**\n\n```bash\nnode --experimental-wasi-unstable-preview1 -e \"const fs=require('fs');const wabt=require('wabt')\"\n## 或在浏览器中通过 `<script type=\"module\">...</script>` 手动 fetch & instantiate\n```\n\n---\n\n### 7 · 整体回顾\n\n1. **相同步骤（仅简述）**\n   预处理 → AST/IR 生成 → IR 优化 → （可选）静态库归档。\n2. **关键差异（已详细）**\n\n   * LLVM wasm 后端输出 **Wasm Relocatable .o**；\n   * 链接器换成 **wasm-ld**，随后由 **Binaryen wasm-opt** 做指令级压缩与改写；\n   * 产物不再是 ELF，可选择纯 `.wasm` 或附带 JS/HTML Glue。\n\n按照以上流程，即可从标准 C/C++ 代码生成满足 Web 平台运行约束、并经过专用优化的 WebAssembly 文件。\n\n[1]: https://github.com/WebAssembly/binaryen?utm_source=chatgpt.com \"GitHub - WebAssembly/binaryen: Optimizer and compiler/toolchain library ...\"\n[2]: https://stackoverflow.com/questions/72894208/error-linking-o-file-to-wasm-with-wasm-ld?utm_source=chatgpt.com \"Error linking .o file to .wasm with wasm-ld - Stack Overflow\"\n[3]: https://web.dev/articles/binaryen?utm_source=chatgpt.com \"Compiling to and optimizing Wasm with Binaryen - web.dev\"\n[4]: https://emscripten.org/docs/compiling/WebAssembly.html?utm_source=chatgpt.com \"Building to WebAssembly — Emscripten 4.0.11-git (dev) documentation\"\n\n\n## WebAssembly程序的一些特点\n\n### 内存模型简述\n\n* WebAssembly 只有一块 **线性内存**，按页（64 KB）扩展。\n* 分段：静态区 + 栈 + 堆；JS 侧通过 `HEAP8/HEAP32/...` 视图直接访问。\n* 想让堆自动增长：`-sALLOW_MEMORY_GROWTH=1`。\n\n---\n\n### 虚拟文件系统\n\n* 内置 **MEMFS**（纯内存）、**IDBFS**（落盘到 IndexedDB）、**WORKERFS** 等。\n* 静态打包：`--preload-file` / `--embed-file`。\n* 运行期挂载：`FS.mount(FS.filesystems.IDBFS, {}, '/data')`。\n\n---\n\n### 多线程\n\n* 通过 **PThreads ↔ Web Workers** 转译。\n* 关键开关：`-sUSE_PTHREADS=1`（同时要在目标环境启用 SharedArrayBuffer）。\n* Unity WebGL 构建需在 Player Settings 勾选 “Threads Support”。\n\n\n### 压缩与体积优化\n\n* Emscripten 本身不压缩输出。\n* Unity WebGL 会额外生成 `.wasm.br / .wasm.gz` 并在启动脚本中自解压。\n* 部分小程序平台（如微信小游戏）不支持自解压启动，需要关闭 Unity 的压缩或自行在服务器侧压缩后手动解压。\n\n---\n"
}
