{
  "schemaVersion": "0.11.0",
  "canonical": "https://www.pystone.net/notes/cpp-windows-linking/",
  "atlas": "https://www.pystone.net/?node=cpp-windows-linking#knowledge-atlas",
  "markdown": "https://www.pystone.net/notes/cpp-windows-linking.md",
  "context": "https://www.pystone.net/notes/cpp-windows-linking.context.json",
  "knowledgeVersion": "224c990773de.5fa8af6e39fa",
  "build": {
    "siteCommit": "224c990773de166d23a886306577dd90379529ce",
    "notesCommit": "5fa8af6e39fa3891d1b9b4832bfa6c4e0ecaaf0a",
    "builtAt": "1970-01-01T00:00:00.000Z",
    "version": "224c990773de.5fa8af6e39fa"
  },
  "id": "note:cpp-windows-linking",
  "slug": "cpp-windows-linking",
  "title": "Windows链接",
  "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": "Windows链接",
  "contentRole": "unspecified",
  "isMoc": false,
  "mocRecognition": "none",
  "generated": false,
  "attribution": "unspecified",
  "domain": "10-计算机、信息技术与工程",
  "tags": [],
  "mocs": [],
  "contentHash": "8dc29a62f1c0770a1ce036365de8a80c31f54f880ecb0449a5418a292c2a450a",
  "assets": [],
  "headings": [
    {
      "depth": 1,
      "text": "Windows链接",
      "anchor": "windows链接",
      "citation": "https://www.pystone.net/notes/cpp-windows-linking/#windows%E9%93%BE%E6%8E%A5"
    },
    {
      "depth": 2,
      "text": "1）从“编译到运行”的链路全貌",
      "anchor": "1从编译到运行的链路全貌",
      "citation": "https://www.pystone.net/notes/cpp-windows-linking/#1%E4%BB%8E%E7%BC%96%E8%AF%91%E5%88%B0%E8%BF%90%E8%A1%8C%E7%9A%84%E9%93%BE%E8%B7%AF%E5%85%A8%E8%B2%8C"
    },
    {
      "depth": 3,
      "text": "A. 编译（Compile）",
      "anchor": "a-编译compile",
      "citation": "https://www.pystone.net/notes/cpp-windows-linking/#a-%E7%BC%96%E8%AF%91compile"
    },
    {
      "depth": 3,
      "text": "B. 链接（Link）",
      "anchor": "b-链接link",
      "citation": "https://www.pystone.net/notes/cpp-windows-linking/#b-%E9%93%BE%E6%8E%A5link"
    },
    {
      "depth": 4,
      "text": "1）静态链接（Static link）",
      "anchor": "1静态链接static-link",
      "citation": "https://www.pystone.net/notes/cpp-windows-linking/#1%E9%9D%99%E6%80%81%E9%93%BE%E6%8E%A5static-link"
    },
    {
      "depth": 4,
      "text": "2）动态链接（Dynamic link，基于 DLL）",
      "anchor": "2动态链接dynamic-link基于-dll",
      "citation": "https://www.pystone.net/notes/cpp-windows-linking/#2%E5%8A%A8%E6%80%81%E9%93%BE%E6%8E%A5dynamic-link%E5%9F%BA%E4%BA%8E-dll"
    },
    {
      "depth": 2,
      "text": "2）“库文件”到底分哪些？（Windows 视角）",
      "anchor": "2库文件到底分哪些windows-视角",
      "citation": "https://www.pystone.net/notes/cpp-windows-linking/#2%E5%BA%93%E6%96%87%E4%BB%B6%E5%88%B0%E5%BA%95%E5%88%86%E5%93%AA%E4%BA%9Bwindows-%E8%A7%86%E8%A7%92"
    },
    {
      "depth": 3,
      "text": "1）DLL：动态链接库（运行时实体）",
      "anchor": "1dll动态链接库运行时实体",
      "citation": "https://www.pystone.net/notes/cpp-windows-linking/#1dll%E5%8A%A8%E6%80%81%E9%93%BE%E6%8E%A5%E5%BA%93%E8%BF%90%E8%A1%8C%E6%97%B6%E5%AE%9E%E4%BD%93"
    },
    {
      "depth": 3,
      "text": "2）LIB：.lib 不是一种“库类型”，而是两种不同东西的容器名（关键）",
      "anchor": "2liblib-不是一种库类型而是两种不同东西的容器名关键",
      "citation": "https://www.pystone.net/notes/cpp-windows-linking/#2liblib-%E4%B8%8D%E6%98%AF%E4%B8%80%E7%A7%8D%E5%BA%93%E7%B1%BB%E5%9E%8B%E8%80%8C%E6%98%AF%E4%B8%A4%E7%A7%8D%E4%B8%8D%E5%90%8C%E4%B8%9C%E8%A5%BF%E7%9A%84%E5%AE%B9%E5%99%A8%E5%90%8D%E5%85%B3%E9%94%AE"
    },
    {
      "depth": 4,
      "text": "A) 静态库（static library）",
      "anchor": "a-静态库static-library",
      "citation": "https://www.pystone.net/notes/cpp-windows-linking/#a-%E9%9D%99%E6%80%81%E5%BA%93static-library"
    },
    {
      "depth": 4,
      "text": "B) 导入库（import library）",
      "anchor": "b-导入库import-library",
      "citation": "https://www.pystone.net/notes/cpp-windows-linking/#b-%E5%AF%BC%E5%85%A5%E5%BA%93import-library"
    },
    {
      "depth": 2,
      "text": "Android与Windows的区别",
      "anchor": "android与windows的区别",
      "citation": "https://www.pystone.net/notes/cpp-windows-linking/#android%E4%B8%8Ewindows%E7%9A%84%E5%8C%BA%E5%88%AB"
    },
    {
      "depth": 3,
      "text": "1）为什么 Android 平台很少听说 “import lib”？",
      "anchor": "1为什么-android-平台很少听说-import-lib",
      "citation": "https://www.pystone.net/notes/cpp-windows-linking/#1%E4%B8%BA%E4%BB%80%E4%B9%88-android-%E5%B9%B3%E5%8F%B0%E5%BE%88%E5%B0%91%E5%90%AC%E8%AF%B4-import-lib"
    },
    {
      "depth": 4,
      "text": "Android/Linux 的常规做法",
      "anchor": "androidlinux-的常规做法",
      "citation": "https://www.pystone.net/notes/cpp-windows-linking/#androidlinux-%E7%9A%84%E5%B8%B8%E8%A7%84%E5%81%9A%E6%B3%95"
    },
    {
      "depth": 4,
      "text": "Windows 的常规做法",
      "anchor": "windows-的常规做法",
      "citation": "https://www.pystone.net/notes/cpp-windows-linking/#windows-%E7%9A%84%E5%B8%B8%E8%A7%84%E5%81%9A%E6%B3%95"
    },
    {
      "depth": 3,
      "text": "2）两边动态链接的“工程形态”差异总结",
      "anchor": "2两边动态链接的工程形态差异总结",
      "citation": "https://www.pystone.net/notes/cpp-windows-linking/#2%E4%B8%A4%E8%BE%B9%E5%8A%A8%E6%80%81%E9%93%BE%E6%8E%A5%E7%9A%84%E5%B7%A5%E7%A8%8B%E5%BD%A2%E6%80%81%E5%B7%AE%E5%BC%82%E6%80%BB%E7%BB%93"
    },
    {
      "depth": 4,
      "text": "Windows（PE/COFF）",
      "anchor": "windowspecoff",
      "citation": "https://www.pystone.net/notes/cpp-windows-linking/#windowspecoff"
    },
    {
      "depth": 4,
      "text": "Android/Linux（ELF）",
      "anchor": "androidlinuxelf",
      "citation": "https://www.pystone.net/notes/cpp-windows-linking/#androidlinuxelf"
    },
    {
      "depth": 3,
      "text": "3）CMakeLists 写法有什么差异？",
      "anchor": "3cmakelists-写法有什么差异",
      "citation": "https://www.pystone.net/notes/cpp-windows-linking/#3cmakelists-%E5%86%99%E6%B3%95%E6%9C%89%E4%BB%80%E4%B9%88%E5%B7%AE%E5%BC%82"
    },
    {
      "depth": 4,
      "text": "A. 链接一个“系统库/平台库”的差异",
      "anchor": "a-链接一个系统库平台库的差异",
      "citation": "https://www.pystone.net/notes/cpp-windows-linking/#a-%E9%93%BE%E6%8E%A5%E4%B8%80%E4%B8%AA%E7%B3%BB%E7%BB%9F%E5%BA%93%E5%B9%B3%E5%8F%B0%E5%BA%93%E7%9A%84%E5%B7%AE%E5%BC%82"
    },
    {
      "depth": 4,
      "text": "B. 链接一个第三方动态库的差异（你自己带的库）",
      "anchor": "b-链接一个第三方动态库的差异你自己带的库",
      "citation": "https://www.pystone.net/notes/cpp-windows-linking/#b-%E9%93%BE%E6%8E%A5%E4%B8%80%E4%B8%AA%E7%AC%AC%E4%B8%89%E6%96%B9%E5%8A%A8%E6%80%81%E5%BA%93%E7%9A%84%E5%B7%AE%E5%BC%82%E4%BD%A0%E8%87%AA%E5%B7%B1%E5%B8%A6%E7%9A%84%E5%BA%93"
    },
    {
      "depth": 4,
      "text": "C. “我不想硬依赖某个动态库”的写法差异（SDK 很常用）",
      "anchor": "c-我不想硬依赖某个动态库的写法差异sdk-很常用",
      "citation": "https://www.pystone.net/notes/cpp-windows-linking/#c-%E6%88%91%E4%B8%8D%E6%83%B3%E7%A1%AC%E4%BE%9D%E8%B5%96%E6%9F%90%E4%B8%AA%E5%8A%A8%E6%80%81%E5%BA%93%E7%9A%84%E5%86%99%E6%B3%95%E5%B7%AE%E5%BC%82sdk-%E5%BE%88%E5%B8%B8%E7%94%A8"
    }
  ],
  "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++中的“Windows链接”导航项",
      "citation": "https://www.pystone.net/notes/programming-languages-and-runtimes/#c"
    }
  ],
  "contentMarkdown": "# Windows链接\n\n﻿# Windows链接\n\n\n1. 静态链接（static）\n\n* `.lib`（静态库） → 代码被拷进最终产物\n* 不产生对该库 DLL 的运行时依赖\n\n2. 动态链接（dynamic）分两种\n\n* 隐式动态链接：`.lib`（导入库） + `.dll`（运行时） → 产物导入表依赖 DLL\n* 显式动态链接：运行时 `LoadLibrary/GetProcAddress` → 不在导入表里硬依赖\n*\n## 1）从“编译到运行”的链路全貌\n\n### A. 编译（Compile）\n\n* 输入：`.c/.cpp`\n* 输出：`.obj`（目标文件）\n* 里面有什么：\n\n  * 机器码（函数实现）\n  * 符号表（这个 obj 里定义了哪些函数/变量、引用了哪些外部符号）\n* 此时 **还没有把所有外部函数地址确定**，比如你调用 `GetProcessMemoryInfo`，编译器只会记一个“外部符号引用”。\n\n### B. 链接（Link）\n\n* 输入：很多 `.obj` + 若干 `.lib`（库）+ 以及一些默认系统库\n* 输出：`.exe` 或 `.dll`\n* 链接器做两件大事：\n\n  1. **符号解析**：把“外部符号引用”匹配到“某个地方的定义”\n  2. **地址重定位**：把最终要调用/访问的地址关系安排好\n\n链接有两条主要路径：\n\n#### 1）静态链接（Static link）\n\n* 你链接到的是 **静态库 .lib（里面真的包含实现代码）**\n* 链接器会把需要的 `.obj` 代码**复制**到最终 exe/dll 里\n* 结果：\n\n  * 最终产物 **不需要那个库的 DLL**（因为代码已经被带进来）\n  * 文件可能更大\n  * 每个使用方都有一份拷贝（除非 LTO/COMDAT 合并等优化）\n\n#### 2）动态链接（Dynamic link，基于 DLL）\n\n动态链接又分两种“建立依赖”的方式：\n\n* **隐式动态链接（Implicit dynamic linking）**\n\n  * 你在链接时使用一个 **导入库 import lib（也是 .lib）**\n  * 链接器不会把实现代码拷进来，而是生成 **Import Table（导入表）**\n  * 程序启动/模块加载时，Windows Loader 会加载对应 `.dll` 并把函数地址填入 IAT\n  * 如果 DLL 缺失，可能导致**加载失败/进程启动失败**（取决于该模块什么时候被加载）\n\n* **显式动态链接（Explicit dynamic linking）**\n\n  * 运行时你自己调用：\n\n    * `LoadLibrary(\"xxx.dll\")`\n    * `GetProcAddress(\"Func\")`\n  * 这时链接器不需要 import lib（或只需要 kernel32 的这些 API）\n  * 如果 DLL 缺失，你可以选择**优雅降级**，不会因为导入表缺失而加载失败\n\n---\n\n## 2）“库文件”到底分哪些？（Windows 视角）\n\n### 1）DLL：动态链接库（运行时实体）\n\n* `.dll` 是真正的动态库文件，装着实现代码\n* 运行时会被加载到进程地址空间里\n\n### 2）LIB：`.lib` 不是一种“库类型”，而是两种不同东西的容器名（关键）\n\n在 MSVC/Windows 生态里，`.lib` 可能是：\n\n#### A) 静态库（static library）\n\n* 里面包含真实的 `.obj` 代码（实现）\n* 用于静态链接：代码会被拷进最终 exe/dll\n\n#### B) 导入库（import library）\n\n* 里面**通常不包含实现代码**（或只包含很小的跳板/描述信息）\n* 它告诉链接器：某些符号来自某个 DLL\n* 用于隐式动态链接：最终 exe/dll 里会生成导入表，运行时需要对应 DLL\n\n> 所以：**“.lib 既可能是静态库，也可能是导入库”**\n> 光看扩展名看不出来，必须结合来源/用途/工具检查（dumpbin 等）。\n\n---\n\n\n## Android与Windows的区别\n是的，这里确实体现了 **Windows vs Android 在“动态链接”工程化形态上的差异**。但本质机制并不矛盾：两边都可以“链接到动态库”，只是**Windows 把“链接到 DLL”通常分成了两件文件（.lib + .dll）**，而 Android/Linux 通常直接用 `.so` 及其符号/SONAME 体系，不需要“import lib”这种额外壳。\n\n下面按你关心的点说明：**import lib 是什么、为什么 Android 没这个概念、两边动态链接流程差异、CMakeLists 写法差异**。\n\n---\n\n### 1）为什么 Android 平台很少听说 “import lib”？\n\n#### Android/Linux 的常规做法\n\n* 动态库是 **`.so`**，里面既有实现代码，也包含**动态符号表**（可供其他模块在链接/运行时解析）。\n* 链接一个共享库时，链接器用的是：\n\n  * `libxxx.so`（或 `libxxx.so` 的 *linker stub*）\n  * 生成可执行文件/共享库里的 **DT_NEEDED** 依赖条目\n* 运行时由 dynamic loader（`linker`/`ld-android.so`）加载 `.so`，按 ELF 机制做重定位与符号解析。\n\n#### Windows 的常规做法\n\n* 动态库是 **`.dll`**，但 MSVC 的链接器通常不直接用 `.dll` 做链接输入。\n* MSVC 使用一个配套的 **导入库（import library）`xxx.lib`**：\n\n  * 它像“链接期说明书”，告诉链接器：这些符号来自哪个 DLL、如何生成导入表（IAT）。\n* 运行时由 Windows Loader 根据导入表加载 `.dll` 并填充 IAT。\n\n\n### 2）两边动态链接的“工程形态”差异总结\n\n#### Windows（PE/COFF）\n\n* **链接期**：通常用 `xxx.lib`（import lib）来链接\n* **运行期**：加载 `xxx.dll`\n* **显式动态加载**：`LoadLibrary` + `GetProcAddress`\n\n#### Android/Linux（ELF）\n\n* **链接期**：用 `libxxx.so`（或开发包提供的 stub so）\n* **运行期**：加载 `libxxx.so`\n* **显式动态加载**：`dlopen` + `dlsym`\n\n---\n\n### 3）CMakeLists 写法有什么差异？\n\n#### A. 链接一个“系统库/平台库”的差异\n\n**Windows：**\n\n```cmake\ntarget_link_libraries(my_target PRIVATE psapi)\n```\n\n* 这会让链接器去找 `psapi.lib`（import lib），最终运行时依赖 `psapi.dll`。\n* 如果你写了 `#pragma comment(lib,\"psapi.lib\")`，那是 MSVC 私有的做法；CMake 更推荐用 `target_link_libraries`。\n\n**Android：**\n\n```cmake\ntarget_link_libraries(my_target PRIVATE log android)\n```\n\n* Android NDK 里 `log` / `android` 等是系统 so（实际是 `liblog.so` / `libandroid.so`）。\n* 不存在“额外 import lib”的概念。\n\n---\n\n#### B. 链接一个第三方动态库的差异（你自己带的库）\n\n**Android：**\n你通常直接链接 `.so`：\n\n```cmake\nadd_library(foo SHARED IMPORTED)\nset_target_properties(foo PROPERTIES\n  IMPORTED_LOCATION \"${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/libfoo.so\"\n)\ntarget_link_libraries(my_target PRIVATE foo)\n```\n\n**Windows：**\n第三方库通常给你一套：`foo.dll + foo.lib`\n\n* 你链接的是 `.lib`，运行时需要 `.dll`：\n\n```cmake\nadd_library(foo SHARED IMPORTED)\nset_target_properties(foo PROPERTIES\n  IMPORTED_IMPLIB  \"${CMAKE_SOURCE_DIR}/libs/foo.lib\"   # 链接期用\n  IMPORTED_LOCATION \"${CMAKE_SOURCE_DIR}/bin/foo.dll\"   # 运行时用（可选写）\n)\ntarget_link_libraries(my_target PRIVATE foo)\n```\n\n> 关键差别：Windows 下 CMake 要区分 `IMPORTED_IMPLIB`（导入库）和 `IMPORTED_LOCATION`（DLL 本体）。Android 下通常只要 `IMPORTED_LOCATION` 指向 `.so`。\n\n---\n\n#### C. “我不想硬依赖某个动态库”的写法差异（SDK 很常用）\n\n**Windows 显式加载：**\n\n* 不在 CMake 链接 `psapi`（也不 `#pragma comment(lib)`）\n* 运行时：\n\n  * `LoadLibraryW(L\"psapi.dll\")`\n  * `GetProcAddress(...)`\n* 好处：缺失时可降级，不影响模块加载/进程启动。\n\n**Android 显式加载：**\n\n* 不在 CMake 链接 `libxxx.so`\n* 运行时：\n\n  * `dlopen(\"libxxx.so\", RTLD_NOW)`\n  * `dlsym(...)`\n* 同样是可降级策略。\n\n---\n"
}
