静态库创建

0 前言

最近工作需要将源码中的算法剥离出来,做成静态库,防止其他组偷我们的AI算法源码。所以开始研究相关的工作

1 CRT

首先引入一个概念CRT,CRT = C runtime Library, 也就是C运行时库

CRT是你的 C++ 程序运行时所依赖的一套基础设施。

C运行时库提供了很多C/C++的基础代码,比如:

  • 程序启动、调用 main()、程序退出
  • malloc/free、部分 new/delete 运行时支持
  • printf/scanf、fopen/fclose
  • 字符串、数学、时间、区域设置
  • 异常处理、RTTI、运行时检查
  • Debug 模式下的堆检查和内存泄漏检测程序启动、调用 main()、程序退出

现代 MSVC 的运行库实际拆分为 UCRT、VCRuntime 和 C++ 标准库等部分

CRT的链接方式

参数 CRT 链接方式 版本 典型用途
/MT 静态链接 CRT Release 独立程序、希望减少对 VC Runtime DLL 的部署依赖
/MTd 静态链接 Debug CRT Debug /MT 项目的本地调试
/MD 动态链接 CRT DLL Release EXE + DLL、插件、组件化项目
/MDd 动态链接 Debug CRT DLL Debug /MD 项目的本地调试

这是 MSVC 对四个选项的正式定义:/MT/MTd 使用静态运行库,/MD/MDd 使用 DLL 版本的运行库;后缀 d 表示 Debug 版本

/MT  = 静态 + Release
/MTd = 静态 + Debug

/MD  = 动态 + Release
/MDd = 动态 + Debug

/MT:每个模块自带一份 CRT

使用 /MT 时,CRT 的代码会静态链接进最终的 EXE 或 DLL:

App.exe
├── 业务代码
├── 第三方代码
└── 自己的一份 CRT

假设一个进程包含:

App.exe    /MT
PluginA.dll /MT
PluginB.dll /MT

那么它们通常各自带有一份独立的 CRT:

App.exe      → CRT #1
PluginA.dll  → CRT #2
PluginB.dll  → CRT #3

这些 CRT 实例拥有各自的运行时状态。微软文档明确指出,静态 CRT 的状态对于每个 EXE/DLL 实例是独立的,因此微软不建议在 DLL 中随意静态链接 CRT,除非开发者清楚了解后果。

/MT 的优点

  • 减少对 Visual C++ Runtime DLL 的部署依赖
  • 单个 EXE 更容易复制到其他机器
  • 不容易因为目标机器缺少特定 VC Runtime DLL 而启动失败
  • 适合边界清晰、相对独立的命令行工具或桌面程序
    /MT 的缺点
  • 每个 EXE/DLL 都可能包含一份运行库代码
  • 文件通常会更大
  • 不同模块可能拥有不同的 CRT 状态和内存管理环境
  • 跨 DLL 传递 CRT 对象或释放内存时容易出问题

因此 App.exe 和 Plugin.dll 各自有一份,不会在运行时共同使用同一份静态库。不过,并不是整个 .lib 都会被无脑复制进去。一个 .cpp 通常生成一个 .obj;静态库默认先按 .obj 取用,再视优化设置按函数进一步裁剪

/MD:多个模块使用动态 CRT

使用 /MD 时,程序通过 DLL 使用运行库:

App.exe      ─┐
PluginA.dll  ─┼─→ UCRT / VCRuntime / MSVC C++ Runtime DLL
PluginB.dll  ─┘

这通常更适合:

主程序 EXE
    +
多个业务 DLL
    +
插件 DLL
    +
第三方组件

当所有模块使用兼容的 /MD 配置时,它们可以使用同一套动态加载的 CRT。微软也建议:需要让进程中的多个组件使用相同 CRT DLL 时,应统一使用 /MD,并保持工具集和相关属性一致。

/MD 的优点

  • 各模块不需要重复静态包含完整运行库
  • 通常可以减小各个二进制文件的体积
  • 更适合 EXE、DLL、插件组成的组件化系统
  • 对跨模块 CRT 状态和内存管理相对友好
    /MD 的缺点
  • 目标机器需要具备对应的 Visual C++ Runtime 组件
  • 部署时需要安装或携带相应的 VC Redistributable
  • 运行库版本或部署配置错误时,程序可能无法启动
posted @ 2026-07-16 15:00  wenli7363  阅读(1)  评论(0)    收藏  举报