DLL 通常如何与应用程序一起打包? 问题

问题描述

我有很多关于 DLL 以及如何将第三方库与您的软件捆绑在一起的基本问题,但我在搜索时找到的大部分内容都特定于 C#(例如 this 问题),我正在寻找有关 DLL 的工作原理及其用途的更多一般信息。


例如,我有一个 CMake 管理的 C++ 应用程序,它链接一个或多个第三方 DLL。

他们的 DLL 安装到 C:/Program Files/Intel/SomeLibrary/bin/somelibrary.dll。通过让环境变量负责查找它们的标头,我可以很好地构建我的应用。

显然,我实际上无法开箱即用地运行我的可执行文件,因为找不到 somelibrary.dll。我必须将它复制到与可执行文件相同的文件夹中,或者将 Intel/SomeLibrary/bin 添加到我的路径中。

问题

  1. 其他程序如何链接到它们所需的 DLL?他们是否只是将他们使用的所有第三方 DLL 的副本与自己的软件打包在一起?

  2. 对于某些第三方库来说,这是一个不同的过程吗?例如,您可能会与软件捆绑在一起的英特尔库,但对于 Microsoft's VS Redistributables,您需要用户安装它们?如果它们不存在,看起来您的 installer(WiX 示例)会处理安装它们(然后它是否为需要它们的每个软件安装一个新副本?)。

  3. 您的计算机上是否可能有同一个 DLL 的多个副本,因为一堆单独的程序需要它,但无法知道您是否已经在某处拥有它?

    换句话说,由不同人编写的两个程序可以链接到同一个 DLL 文件吗?他们如何找到该 DLL,或者如果它不存在则安装它?


对于我在询问这些问题时所造成的任何基本误解,我提前道歉 - 我对打包已经构建的软件的想法还很陌生。

解决方法

简短的回答是 dll 加载器将在本地应用程序文件夹中查找 dll,然后搜索一堆系统位置。清单、SafeDllSearchMode 功能(影响目录搜索顺序)以及开发人员通过覆盖 (LoadLibraryEx) 和其他几个(见下文)从自定义位置加载 dll 都存在复杂性。

依赖类型:dll依赖有多种类型:Module / dll dependencies mind map


Dynamic-Link Library Search Order:以下是关于该主题的 Microsoft Docs 摘录:“一个系统可以包含同一个动态链接库 (DLL) 的多个版本。应用程序可以从通过指定完整路径或使用其他机制(例如清单)来加载 DLL。”

换句话说,您可以1)从特定位置加载 dll 或 2) 您可以让操作系统通过以下方式为您找到它标准机制。 "SafeDllSearchMode" 注册表设置会影响搜索用户当前目录的时间。它现在默认为打开,但可以禁用。有关权威详细信息,请参阅上面的链接。 注意操作系统更改和安全修复 - 所有这些都会在未来影响此顺序


Q1:始终使用为您的依赖 dll 提供的运行时(如果可用)。如果不应该,不要只包含几个 dll。

Q2:运行时通常非常不同是正确的。有时它们只是一个或几个 dll,您可以将它们安装在本地应用程序文件夹中。其他时候,您安装运行时设置,将文件安装到适当的文件夹以供共享使用。有些运行时作为“合并模块”提供,可以将文件合并到您自己的 MSI 安装程序中,有些作为单独的 MSI 安装程序或 setup.exe 安装程序提供。

Q3:使用 dlls 的整个想法本质上是能够将相同的二进制组件加载到多个进程中,以便能够更新一个单独的 dll 来修复 dll 的所有“消费者”中的问题,并在内存中共享它们(在内存很少的日子里很重要)。 Dll 也可以“延迟加载”——这意味着它们在需要之前不会被加载——避免内存膨胀。反正就是这个想法。


Windows 操作系统版本:要加载的正确 dll 的搜索顺序(在磁盘上搜索的位置)是一个非常复杂的话题。操作系统加载器机制如何定位 DLL 会受到多种因素的影响,例如 1) 操作系统版本、2) 清单、3) 硬编码更改的加载路径 (LoadLibraryEx),或 4) dll redirects{{1} } 之前在内存中加载的dll(这里是dragons)等...

UWP 和 .NET:还有关于 UWP applications 的新发展。对于 .NET 程序集,分辨率再次不同(您声明),请参阅这篇文章:How the Runtime Locates Assemblies

WinSxS:清单是 Windows 中较新的概念 - 在过去没有这样的东西,搜索顺序会更简单,但不太灵活。随着清单和并行 Win32 程序集(安装在不同版本中的相同 dll 的多个版本)的出现,清单被嵌入到可执行文件中(或从外部添加)并告诉二进制文件在哪里寻找运行时dll - 在 Windows 的 5) 文件夹层次结构中(通常:WinSxS),其中可以驻留相同 dll 的多个版本(在不同的子文件夹中)。

大多数 Microsoft 运行时 - 基本上所有现代运行时 - 都驻留在此处,因此需要一个清单来指示二进制文件要查找和加载的版本。也有一些方法可以重定向此类清单... "Publisher Configuration Files"2。叹气...当旧版本不希望使用时,这可用于强制执行某个新的运行时版本。未使用的运行时也可以通过缩小 WinSxS 文件夹的方式进行“垃圾收集”(See this answer - 部分“清理/让 WinSxS 节食”)...嗯...从不难WinSxS 的代码路径。


DLL 搜索顺序: The old and outdated tool Dependency Walker 有一个过时,但在其 {{ 3}}。

提示更新的文档是:help file。但是,要大致了解搜索顺序,您只需启动 Microsoft Docs: Module Search Order for Desktop Applications 并选择:C:\Windows\WinSxS Options =>。然后确保取消选择 Configure Module Search Order... 按钮。您所看到的 - 可能已经过时 - 有助于回忆模块搜索顺序的工作原理:

Dependency Walker


链接: