{
  "schemaVersion": "0.11.0",
  "canonical": "https://www.pystone.net/notes/cpp-compilation-pipeline/",
  "atlas": "https://www.pystone.net/?node=cpp-compilation-pipeline#knowledge-atlas",
  "markdown": "https://www.pystone.net/notes/cpp-compilation-pipeline.md",
  "context": "https://www.pystone.net/notes/cpp-compilation-pipeline.context.json",
  "knowledgeVersion": "224c990773de.5fa8af6e39fa",
  "build": {
    "siteCommit": "224c990773de166d23a886306577dd90379529ce",
    "notesCommit": "5fa8af6e39fa3891d1b9b4832bfa6c4e0ecaaf0a",
    "builtAt": "1970-01-01T00:00:00.000Z",
    "version": "224c990773de.5fa8af6e39fa"
  },
  "id": "note:cpp-compilation-pipeline",
  "slug": "cpp-compilation-pipeline",
  "title": "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": "C++ 编译流程",
  "contentRole": "unspecified",
  "isMoc": false,
  "mocRecognition": "none",
  "generated": false,
  "attribution": "unspecified",
  "domain": "10-计算机、信息技术与工程",
  "tags": [],
  "mocs": [],
  "contentHash": "49dc13556a8f81b352f17d2e0a1af165c163e67e796186dcad5cd0ce83ff550a",
  "assets": [],
  "headings": [
    {
      "depth": 1,
      "text": "C++ 编译流程",
      "anchor": "c-编译流程",
      "citation": "https://www.pystone.net/notes/cpp-compilation-pipeline/#c-%E7%BC%96%E8%AF%91%E6%B5%81%E7%A8%8B"
    },
    {
      "depth": 2,
      "text": "传统 C++ 编译五阶段",
      "anchor": "传统-c-编译五阶段",
      "citation": "https://www.pystone.net/notes/cpp-compilation-pipeline/#%E4%BC%A0%E7%BB%9F-c-%E7%BC%96%E8%AF%91%E4%BA%94%E9%98%B6%E6%AE%B5"
    },
    {
      "depth": 4,
      "text": "1. 预处理（Preprocessing）",
      "anchor": "1-预处理preprocessing",
      "citation": "https://www.pystone.net/notes/cpp-compilation-pipeline/#1-%E9%A2%84%E5%A4%84%E7%90%86preprocessing"
    },
    {
      "depth": 4,
      "text": "2. 编译（Front-end Compilation）",
      "anchor": "2-编译front-end-compilation",
      "citation": "https://www.pystone.net/notes/cpp-compilation-pipeline/#2-%E7%BC%96%E8%AF%91front-end-compilation"
    },
    {
      "depth": 4,
      "text": "3. 目标级优化（Machine-code Optimization，可选）",
      "anchor": "3-目标级优化machine-code-optimization可选",
      "citation": "https://www.pystone.net/notes/cpp-compilation-pipeline/#3-%E7%9B%AE%E6%A0%87%E7%BA%A7%E4%BC%98%E5%8C%96machine-code-optimization%E5%8F%AF%E9%80%89"
    },
    {
      "depth": 4,
      "text": "4. 汇编（Assembly，可选显式步）",
      "anchor": "4-汇编assembly可选显式步",
      "citation": "https://www.pystone.net/notes/cpp-compilation-pipeline/#4-%E6%B1%87%E7%BC%96assembly%E5%8F%AF%E9%80%89%E6%98%BE%E5%BC%8F%E6%AD%A5"
    },
    {
      "depth": 4,
      "text": "5. 链接 / 归档",
      "anchor": "5-链接-归档",
      "citation": "https://www.pystone.net/notes/cpp-compilation-pipeline/#5-%E9%93%BE%E6%8E%A5-%E5%BD%92%E6%A1%A3"
    },
    {
      "depth": 2,
      "text": "示例：从源文件到库 / 可执行",
      "anchor": "示例从源文件到库-可执行",
      "citation": "https://www.pystone.net/notes/cpp-compilation-pipeline/#%E7%A4%BA%E4%BE%8B%E4%BB%8E%E6%BA%90%E6%96%87%E4%BB%B6%E5%88%B0%E5%BA%93-%E5%8F%AF%E6%89%A7%E8%A1%8C"
    },
    {
      "depth": 3,
      "text": "（1） 预处理",
      "anchor": "1-预处理",
      "citation": "https://www.pystone.net/notes/cpp-compilation-pipeline/#1-%E9%A2%84%E5%A4%84%E7%90%86"
    },
    {
      "depth": 3,
      "text": "（2） 编译（词法→语法→AST→目标代码）",
      "anchor": "2-编译词法语法ast目标代码",
      "citation": "https://www.pystone.net/notes/cpp-compilation-pipeline/#2-%E7%BC%96%E8%AF%91%E8%AF%8D%E6%B3%95%E8%AF%AD%E6%B3%95ast%E7%9B%AE%E6%A0%87%E4%BB%A3%E7%A0%81"
    },
    {
      "depth": 4,
      "text": "词法/语法分析 → AST",
      "anchor": "词法语法分析-ast",
      "citation": "https://www.pystone.net/notes/cpp-compilation-pipeline/#%E8%AF%8D%E6%B3%95%E8%AF%AD%E6%B3%95%E5%88%86%E6%9E%90-ast"
    },
    {
      "depth": 4,
      "text": "生成 LLVM IR 文本（.ll）",
      "anchor": "生成-llvm-ir-文本ll",
      "citation": "https://www.pystone.net/notes/cpp-compilation-pipeline/#%E7%94%9F%E6%88%90-llvm-ir-%E6%96%87%E6%9C%ACll"
    },
    {
      "depth": 4,
      "text": "生成 LLVM Bitcode（.bc）",
      "anchor": "生成-llvm-bitcodebc",
      "citation": "https://www.pystone.net/notes/cpp-compilation-pipeline/#%E7%94%9F%E6%88%90-llvm-bitcodebc"
    },
    {
      "depth": 4,
      "text": "优化（目标代码级）",
      "anchor": "优化目标代码级",
      "citation": "https://www.pystone.net/notes/cpp-compilation-pipeline/#%E4%BC%98%E5%8C%96%E7%9B%AE%E6%A0%87%E4%BB%A3%E7%A0%81%E7%BA%A7"
    },
    {
      "depth": 3,
      "text": "（3） 汇编（生成机器码/目标机器文件 .o）",
      "anchor": "3-汇编生成机器码目标机器文件-o",
      "citation": "https://www.pystone.net/notes/cpp-compilation-pipeline/#3-%E6%B1%87%E7%BC%96%E7%94%9F%E6%88%90%E6%9C%BA%E5%99%A8%E7%A0%81%E7%9B%AE%E6%A0%87%E6%9C%BA%E5%99%A8%E6%96%87%E4%BB%B6-o"
    },
    {
      "depth": 4,
      "text": "可手动生成可读的汇编指令",
      "anchor": "可手动生成可读的汇编指令",
      "citation": "https://www.pystone.net/notes/cpp-compilation-pipeline/#%E5%8F%AF%E6%89%8B%E5%8A%A8%E7%94%9F%E6%88%90%E5%8F%AF%E8%AF%BB%E7%9A%84%E6%B1%87%E7%BC%96%E6%8C%87%E4%BB%A4"
    },
    {
      "depth": 3,
      "text": "（4） 链接（将 .o 组装成可执行/库）",
      "anchor": "4-链接将-o-组装成可执行库",
      "citation": "https://www.pystone.net/notes/cpp-compilation-pipeline/#4-%E9%93%BE%E6%8E%A5%E5%B0%86-o-%E7%BB%84%E8%A3%85%E6%88%90%E5%8F%AF%E6%89%A7%E8%A1%8C%E5%BA%93"
    },
    {
      "depth": 4,
      "text": "打包静态库 (.a)",
      "anchor": "打包静态库-a",
      "citation": "https://www.pystone.net/notes/cpp-compilation-pipeline/#%E6%89%93%E5%8C%85%E9%9D%99%E6%80%81%E5%BA%93-a"
    },
    {
      "depth": 4,
      "text": "链接成可执行程序",
      "anchor": "链接成可执行程序",
      "citation": "https://www.pystone.net/notes/cpp-compilation-pipeline/#%E9%93%BE%E6%8E%A5%E6%88%90%E5%8F%AF%E6%89%A7%E8%A1%8C%E7%A8%8B%E5%BA%8F"
    },
    {
      "depth": 2,
      "text": "编译和汇编步骤的关系",
      "anchor": "编译和汇编步骤的关系",
      "citation": "https://www.pystone.net/notes/cpp-compilation-pipeline/#%E7%BC%96%E8%AF%91%E5%92%8C%E6%B1%87%E7%BC%96%E6%AD%A5%E9%AA%A4%E7%9A%84%E5%85%B3%E7%B3%BB"
    }
  ],
  "claims": [],
  "outgoing": [],
  "incoming": [
    {
      "id": "note:programming-languages-and-runtimes",
      "title": "编程语言与运行时",
      "url": "https://www.pystone.net/notes/programming-languages-and-runtimes/",
      "atlas": "https://www.pystone.net/?node=programming-languages-and-runtimes#knowledge-atlas",
      "label": "编程语言与运行时",
      "origin": "explicit",
      "humanReviewed": true,
      "context": "本层中的“C++ 编译流程”导航项",
      "citation": "https://www.pystone.net/notes/programming-languages-and-runtimes/#%E6%9C%AC%E5%B1%82"
    },
    {
      "id": "note:emscripten-cpp-compile-workflow",
      "title": "Emscripten-C++编译流程",
      "url": "https://www.pystone.net/notes/emscripten-cpp-compile-workflow/",
      "atlas": "https://www.pystone.net/?node=emscripten-cpp-compile-workflow#knowledge-atlas",
      "label": "Emscripten-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"
    }
  ],
  "contentMarkdown": "# C++ 编译流程\n\n\n## 传统 C++ 编译五阶段\n\n#### 1. 预处理（Preprocessing）\n\n* **工作**：宏展开、条件编译、头文件插入。\n* **命令示例**：`clang -E hello.cpp -o hello.i`\n* **产物**：`hello.i` —— 纯文本 C/C++ 源码，所有 `#include` 与宏均已解析。\n\n#### 2. 编译（Front-end Compilation）\n\n* **工作**：词法分析 → 语法分析 → 语义检查 → 生成内部 IR（GCC：GIMPLE/RTL；Clang：LLVM IR）。\n* **命令示例**：`clang -c hello.i -o hello.o`\n* **产物**：若未显式输出汇编，则直接得到 **目标文件** `hello.o`（ELF relocatable object，包含机器指令、符号表、重定位记录）。\n\n- Clang 前端把 AST 降低成 LLVM IR（隐式在内存中，不写磁盘）。\n- LLVM 后端再把 IR 直接**翻译成机器指令**（对应您如果输出汇编会看到的那些助记符）。\n\n\n#### 3. 目标级优化（Machine-code Optimization，可选）\n\n* **工作**：寄存器分配、指令调度、内联、常量合并等。\n* **触发方式**：`-O1/-O2/-O3` 等优化级别。\n* **产物**：优化后的 `.o`，与步骤 2 同一格式但指令序列已改写。\n\n#### 4. 汇编（Assembly，可选显式步）\n\n* **目的**：生成人类可读汇编文本或从汇编文本生成 `.o`。\n* **查看汇编**：`clang -S hello.cpp -o hello.s`\n* **再汇编**：`as hello.s -o hello_asm.o`\n* **差异**：`.s` 为助记符文本；`.o` 为二进制机器码。\n\n- LLVM 后端会“就地”组装（assemble）这些指令成**机器码字节**，连同符号表／重定位信息一起打包进 `.o`。\n\n#### 5. 链接 / 归档\n\n* **可执行**：`clang hello.o -o hello` → 链接器分配地址、解析外部符号并合并库。\n* **静态库**：`ar rcs libhello.a hello.o` → 仅把多个 `.o` 归档，无地址分配。\n\n\n## 示例：从源文件到库 / 可执行\n\n源文件 `hello.cpp`：\n```cpp\n// hello.cpp\n#include <cstdio>\n#define SQUARE(x) ((x)*(x))\n\nstatic const char* MSG = \"3² = %d\\n\";\n\nint square(int x) {\n    return x * x;\n}\n\nint main() {\n    int v = square(3);\n    std::printf(MSG, v);\n    return 0;\n}\n```\n\n\n### （1） 预处理\n\n```bash\nclang -E hello.cpp -o hello.i\n```\n\n**产物：** `hello.i`（文本），所有的 `#include`、宏都已展开，可能看起来像：\n\n```c\n# C++ 编译流程\n## 1 \"<built-in>\"\n## 1 \"<command-line>\"\n## 1 \"hello.cpp\"\nstatic const char* MSG = \"3² = %d\\n\";\n\nint square(int x) {\n    return x * x;\n}\n\nint main() {\n    int v = square(3);\n    std::printf(\"3² = %d\\n\", v);\n    return 0;\n}\n```\n\n* **宏** `SQUARE(3)` 已被直接替换为 `((3)*(3))`（本例没用到）；\n* **头文件** `<cstdio>` 展开为底层实现和声明（大量代码，已被剥掉示例）。\n\n\n### （2） 编译（词法→语法→AST→目标代码）\n\n```bash\nclang -O2 -c hello.cpp -o hello.o\n```\n\n`hello.o` 已含机器指令，可用 `objdump -d hello.o` 反汇编查看。\n\n1. **词法分析**：把源文本切成一连串 token（标识符、字面量、操作符……）\n2. **语法分析**：把 token 按 C++ 语法规则组装成 AST（抽象语法树）\n3. **语义检查**：类型检查、名称解析、模板实例化\n4. **生成“目标代码”**：Clang 会在内存中直接把 AST 降低为机器指令的中间数据结构（GCC 用 GIMPLE/RTL，Clang 用 LLVM IR 或内部指令序列），但它不会再产出一个文件，除非你指定输出。\n\n如果你让它直接产出一个“目标”文件：\n\n```bash\nclang -O0 -c hello.i -o hello.o\n```\n\n* **结果**：`hello.o` 是一个 **ELF relocatable object**（或在 Emscripten 下是 Wasm relocatable object），里面已经包含了机器指令、符号表、重定位信息。\n* Clang 并不会产出可读的中间文本，这里的“目标代码”实际就是**硬编码在二进制**的机器指令。\n\n\n对该步骤进行进一步拆分如下:\n#### 词法/语法分析 → AST\n- **AST（抽象语法树）**：Clang 内部表示，不直接生成到磁盘。\n\n```bash\nclang -cc1 -ast-dump hello.cpp -fsyntax-only\n```\n- 上面命令会在终端输出类似：\n\n```text\nTranslationUnitDecl ...\n ├─FunctionDecl square\n │   ├─ParmVarDecl x\n │   └─CompoundStmt\n │       └─ReturnStmt\n │           └─BinaryOperator '*'\n └─FunctionDecl main\n     ├─CompoundStmt\n     │   └─CXXOperatorCallExpr '<<'\n     │       ├─...\n\n```\n\n#### 生成 LLVM IR 文本（`.ll`）\n\n```bash\nclang -O0 -emit-llvm -S hello.cpp -o hello.ll\n```\n\n**查看 `hello.ll`**\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- `.ll` 是**人可读**的 LLVM IR。\n- 包含函数签名（mangled name）、基本块、指令（`mul`, `call`, `ret`）等。\n- LLVM IR 是一种**SSA 形式**的中间表示，既包含类型信息，又支持跨平台优化。\n\n#### 生成 LLVM Bitcode（`.bc`）\n\n```text\nclang -O0 -emit-llvm -c hello.cpp -o hello.bc\n```\n- `hello.bc` 是**二进制**形式的 LLVM IR（bitcode），比 `.ll` 更紧凑。\n- 可以通过 `llvm-dis hello.bc -o hello_dis.ll` “反编译”回文本形式；`file hello.bc` 会显示 “LLVM IR bitcode”。\n\n#### 优化（目标代码级）\n\n在上一步，你可以加 `-O2` 或者使用链接时的 LTO：\n\n```bash\nclang -O2 -c hello.i -o hello_opt.o\n## 或者\nclang -flto -O2 -c hello.i -o hello_lto.o\n```\n\n* **作用**：编译器会对刚生成的指令作 **寄存器分配、指令调度、常量合并、内联** 等优化，甚至在 `-flto` 模式下跨不同 `.o` 文件做优化。\n* **产物**：仍然是一个 `.o`，但机器指令序列已经被重写以提高性能或减小体积。\n\n\n### （3） 汇编（生成机器码/目标机器文件 `.o`）\n\n从源到 ELF 对象\n```bash\nclang -O2 -c hello.cpp -o hello.o\n```\n- `hello.o` 是一个 ELF relocatable object，包含已编译的机器码（x86_64 指令）、符号表、本地/全局符号、重定位信息。\n\n- 可用 `readelf -h hello.o` / `readelf -S hello.o` 查看节区 (`.text`, `.data`, `.rela.text`, etc.)；\n\n- 用 `nm hello.o` 查看符号列表（包括 `_Z6squarei`, `_Z4main` 等）。\n\n#### 可手动生成可读的汇编指令\n如果你想看到可读的汇编指令，可以让编译器先输出汇编再汇编成 `.o`：\n\n```bash\n## 先生成汇编代码\nclang -O2 -S hello.i -o hello.s\n\n## hello.s （示例 x86-64 汇编）\n    .text\n    .globl square\nsquare:\n    movl    %edi, %eax\n    imull   %edi, %eax\n    ret\n\n    .globl main\nmain:\n    pushq   %rbp\n    movq    %rsp, %rbp\n    subq    $16, %rsp\n    movl    $3, -4(%rbp)            # int v = 3;\n    movl    -4(%rbp), %edi\n    call    square\n    movl    %eax, -8(%rbp)         # v = square(3)\n    movl    -8(%rbp), %esi\n    leaq    .LC0(%rip), %rdi       # address of format string\n    movl    $0, %eax\n    call    printf\n    movl    $0, %eax\n    leave\n    ret\n\n    .section    .rodata\n.LC0:\n    .string \"3² = %d\\n\"\n\n## 再汇编成机器码\nas hello.s -o hello.o\n```\n\n* `hello.s` 是**人可读的汇编语言**，每条指令对应一条固定模式的机器指令。\n* `as`（汇编器）把汇编指令翻译成**二进制机器码**、打包进 `.o`，并生成重定位表与符号表。\n\n\n### （4） 链接（将 `.o` 组装成可执行/库）\n\n\n#### 打包静态库 (`.a`)\n\n```bash\nar rcs libhello.a hello.o\n```\n\n* **ELF 静态库**：`libhello.a` 是一个普通的 UNIX `.ar` archive，成员是 ELF `.o`。`ar` 只是把若干 `.o` 打包成一个 `.a` archive，不做地址分配，只保存重定位记录与符号，留待用户的链接阶段使用。\n\n\n#### 链接成可执行程序\n\n```bash\n## 可执行\nclang hello.o -o hello\n```\n* **可执行**：链接器（ld）会把所有需要的 `.o` 和系统库（`libc`、`libm` 等）合并，**重定位**所有外部符号，把机器码铺到最终内存地址，然后产出 ELF 可执行文件 `hello`。\n\n\n## 编译和汇编步骤的关系\n当执行\n\n```bash\nclang -O2 -c hello.cpp -o hello.o\n```\n\nClang 做了下面两件事：\n- **Codegen**：把 C++ 源码（经过 AST 和 IR）“编译”成汇编层面上的指令序列（相当于您看到的 `hello.s` 内容）。\n- **Assemble & Pack**：再把那些“汇编指令”**翻译成机器码**，并生成一个包含了这些码流的目标文件 `hello.o`。\n\n**逻辑上是两步，实践中常被合并**\n- **编译 (front-end + back-end)**\n    - 前端：词法 / 语法 / 语义分析，生成 LLVM IR（Clang）或等价内部表示。\n    - 后端：将 IR 翻译成目标体系结构的指令序列，并**立即调用内部汇编器**把指令装配成目标文件。\n    - 触发方式：`clang -c foo.cpp -o foo.o`\n\n\n如果进行显示汇编:\n- 先用 `-S` 将指令序列写出为人可读汇编文本 `.s`；\n- 再手动调用 `as`（或 `clang -c foo.s -o foo.o`）生成目标文件。\n"
}
