1

我们一直在将我们的 Java 和 .NET API 库转换为 C++,并试图找出将编译版本分发给其他开发人员以与他们的自定义应用程序一起使用的最佳方式。应该是静态库还是动态库?

我们需要为 Win32 和 Win64 创建(我想每个目标操作系统都有一个 Debug 和 Release 版本)。考虑到我在尝试确保所有引用的库都匹配(/MT 与 /MD)时遇到的所有挫折,我想知道是否有一个决定在这里为其他开发人员简化它。

当我dumpbin /all <static library file name> | find /i "msvc在静态库上运行时,我看不到任何运行时引用(与我在 .exe 或 .dll 上执行相同操作时不同)。这是否表明运行时尚未链接,这让开发人员在开发和构建自己的应用程序时可以更灵活地制作 /MT 或 /MD?

哪种方法会使开发人员的生活更轻松?

4

2 回答 2

4

静态库和动态(共享)库都有显着的优势。也许您的一个选择是分发这两种类型的库,并让库用户决定使用哪一种。

对于我自己,我通常使用静态库,除非我认为动态库的优势对项目有意义。

静态库的优点包括:

  • 一旦库的用户在编译时链接进来,库中的代码总是在需要调用它的同一个模块中。所以没有 DLL 地狱,也没有并行地狱。由于没有安装正确版本的 MSVC 运行时 (DLL),我无法计算我尝试在 Windows 上运行程序但失败的次数。这确实是一种痛苦,如果可以避免,它会让每个人的生活更轻松。
  • 同样,库中代码的符号最终会出现在调用该库的模块的 .pdb 中,而不是您必须跟踪、复制的另一个 .pdb(.dll 的 .pdb)中, ETC。
  • 这是次要的,但对于静态库,只有您需要链接它的函数/数据最终会出现在可执行文件中。而对于 DLL,它就是整个辣酱玉米饼馅。

动态库的优点之一

  • 明显的优势是它允许库在运行时被替换,即使是最终用户,也不需要重新链接。
  • 这在大多数环境中是次要的,但如果有很多可执行文件链接库,拥有 DLL 意味着更少的磁盘空间,因为相同的数据/代码不会在每个可执行文件中重复。
  • 一些不总是被欣赏的东西:如果库要同时由多个进程加载,则将其作为 DLL 提供意味着 - 理想情况下 - 只有一个只读数据的副本(甚至是可写数据,直到和除非它是由特定进程写入的)需要在内存中。运行时链接 DLL 的所有进程在内存中共享相同的字节。共享的内存是虚拟内存(RAM+页面文件)物理内存。然而,这只是最好的情况——如果 DLL 不能在两个进程中加载​​到相同的虚拟地址,它们就不能共享它。
于 2013-08-02T19:13:48.763 回答
4

静态库更容易创建,但更难分发。客户端程序员会将它们链接到他的程序中,因此您的编译设置与他的兼容非常重要。您必须分发至少 4 个版本,对应于 4 个不同的 CRT 版本(/MD、/MDd、/MT、/MTd)。您需要将其乘以常用的 Visual Studio 版本数。如果您不知道客户端程序员将使用什么,那么这可能是一个非常大的列表。

DLL 没有问题,您只需为导出的函数声明提供一个 .h,一个 .lib 是 DLL 的导入库(无代码,仅包含名称)和 .dll 本身。

然而,为您的 DLL 创建一个可从任何 C 或 C++ 编译器使用的接口更加困难。您不能公开任何标准 C++ 库类,例如返回 std::string 是行不通的。您不能创建任何分配需要由调用者释放的内存的函数。通常,您不能跨边界抛出异常。做任何这些事情都会导致客户端程序员很难诊断运行时问题,这是由不匹配的内存分配器和类对象布局差异引起的。COM 对象模型就是这种接口的一个例子。

这不是静态库会遇到的问题。有点意外,它们需要运行时和编译器版本匹配。如果客户端程序员坚持使用错误风格的静态库,那么他也会遇到所有这些问题。和更多。静态库就像青少年性行为。你犯了一个错误,并最终在你的余生中支持它。

于 2013-08-02T19:30:32.477 回答