DLL 通常如何与应用程序打包在一起?
How are DLLs usually packaged with applications?
我有很多关于 DLL 以及如何将 third-party 库与您的软件捆绑在一起的基本问题,但我在搜索时发现的大多数内容都是特定于 C# 的(例如 this 问题)和我正在寻找有关 DLL 如何工作及其用途的更多一般信息。
例如,我有一个 CMake-managed C++ 应用程序 link 到一个或多个 third-party DLL。
他们的 DLL 安装到 C:/Program Files/Intel/SomeLibrary/bin/somelibrary.dll
。我可以通过让环境变量负责查找它们的 headers.
来构建我的应用程序
显然,我实际上无法 运行 我的可执行文件开箱即用,因为找不到 somelibrary.dll
。我必须将它复制到与可执行文件相同的文件夹中,或者将 Intel/SomeLibrary/bin
添加到我的路径中。
问题
其他程序如何 link 到他们需要的 DLL?他们是否只是将他们在自己的软件中使用的所有 third-party DLL 的副本打包?
一些 third-party 库是否有不同的过程 - 就像您可能与软件捆绑在一起的英特尔库,但对于 Microsoft's VS Redistributables you'd require the user to install them? It looks like your installer(WiX 示例)在它们不存在时处理安装(然后它是否为每个需要它们的软件安装一个新副本?)。
您的计算机上是否可能有同一个 DLL 的多个副本,因为一堆单独的程序需要它,但无法知道您是否已经在某处安装了它?
换句话说,两个由不同人编写的程序是否可以 link 到同一个 DLL 文件?他们如何找到该 DLL,或者如果它不存在则安装它?
对于我在提出这些问题时所造成的任何基本误解,我提前表示歉意 -- 我对打包 already-built 软件的想法还很陌生。
The short answer is that the dll loader will look for dlls in the local application folder and then searching a bunch of system locations. There are complexities with manifests, the SafeDllSearchMode
feature (affects directory search order) and developers loading dlls from custom locations by override (LoadLibraryEx) and several others (see below).
Dependencty Types: There are many types of dll dependencies: Module / dll dependencies mind map.
Dynamic-Link Library Search Order: Here is an extract from Microsoft Docs 主题:“一个系统可以包含同一个动态-link 库 (DLL) 的多个版本。应用程序可以控制 DLL 所在的位置通过指定完整路径或使用其他机制(如清单)加载。"
换句话说,您可以 1)
从特定位置加载 dll 或者 2)
让 OS 通过标准机制为您找到它。 "SafeDllSearchMode"
注册表设置会影响搜索用户当前目录的时间。它现在默认为打开,但可以禁用。有关权威详细信息,请参见上面的 link。 注意 OS 更改和安全修复 - 将来都会影响此订单。
Q1:始终使用为依赖的 dll 提供的运行时(如果可用)。不要只包含一些不应该的 dll。
Q2:运行时通常非常不同是正确的。有时它们只是一个或几个 dll,您可以将它们安装在本地应用程序文件夹中。其他时候,您安装运行时设置,将文件安装到适当的文件夹以供共享。有些运行时作为“合并模块”出现,可以将文件合并到您自己的 MSI 安装程序中,有些运行时作为单独的 MSI 安装程序或 setup.exe 安装程序出现。
Q3:使用dlls的整个想法本质上是能够将相同的二进制组件加载到多个处理以便能够更新单个 dll 以修复 dll 的所有“消费者”中的问题,并在内存中共享它们(这在内存很少的时候很重要)。 Dll 也可以“延迟加载”——这意味着它们只有在需要时才会加载——避免内存膨胀。反正就是这个主意。
Windows OS Version: 正确的搜索顺序(在磁盘上搜索的位置)要加载的 dll 是一个相当复杂的话题。 OS 加载器机制如何定位 DLL 会受到许多因素的影响,例如 1)
OS 版本, 2)
清单,3)
硬编码改变的加载路径(LoadLibraryEx), or 4)
dll redirects,和 5)
以前在内存中加载的 dll(这里是龙)等...
UWP & .NET:UWP applications. For .NET assemblies the resolution is different again (which you state), please see this article: How the Runtime Locates Assemblies.
也有新进展
WinSxS:清单是 Windows 中的一个较新概念 - 在过去没有这样的东西并且搜索顺序会更简单,但不太灵活。随着清单和并排 Win32 程序集(同一 dll 的多个版本安装在不同版本中)的出现,清单嵌入到可执行文件中(或从外部添加),它告诉二进制文件在哪里寻找运行时dlls - 在 Windows 的 WinSxS
文件夹层次结构中(通常:C:\Windows\WinSxS
),其中可以驻留同一个 dll 的多个版本(在不同的子文件夹中) ).
大多数 Microsoft 运行时 - 基本上所有现代运行时 - 都驻留在此处,因此需要清单来指示二进制文件要查找和加载的版本。也有重定向此类清单的方法... "Publisher Configuration Files" and 2. Sigh... This can be used to enforce a certain new runtime version when the old one is undesired for use. Unused runtimes can also be "garbage collected" via ways to shrink the WinSxS folders (See this answer - 部分 “清理/节食 WinSxS”)...嗯...永远不要硬编码路径WinSxS.
Dll搜索顺序: The old and outdated tool Dependency Walker has an outdated, but very good description of the DLL Search Order in its help file.
提示:更新后的文档是:Microsoft Docs: Module Search Order for Desktop Applications. However, to get a rough idea of search order, you can just launch Dependency Walker 和 select : Options
=>
Configure Module Search Order...
。然后确保 Expand
按钮已取消select。您看到的内容 - 尽管可能已经过时 - 可以帮助回忆模块搜索顺序的工作原理:
链接:
- DLL search on windows(关于同一主题的旧 Whosebug 答案)
- The path-searching algorithm is not a backtracking algorithm
- The case of the DLL that refuses to load
我有很多关于 DLL 以及如何将 third-party 库与您的软件捆绑在一起的基本问题,但我在搜索时发现的大多数内容都是特定于 C# 的(例如 this 问题)和我正在寻找有关 DLL 如何工作及其用途的更多一般信息。
例如,我有一个 CMake-managed C++ 应用程序 link 到一个或多个 third-party DLL。
他们的 DLL 安装到 C:/Program Files/Intel/SomeLibrary/bin/somelibrary.dll
。我可以通过让环境变量负责查找它们的 headers.
显然,我实际上无法 运行 我的可执行文件开箱即用,因为找不到 somelibrary.dll
。我必须将它复制到与可执行文件相同的文件夹中,或者将 Intel/SomeLibrary/bin
添加到我的路径中。
问题
其他程序如何 link 到他们需要的 DLL?他们是否只是将他们在自己的软件中使用的所有 third-party DLL 的副本打包?
一些 third-party 库是否有不同的过程 - 就像您可能与软件捆绑在一起的英特尔库,但对于 Microsoft's VS Redistributables you'd require the user to install them? It looks like your installer(WiX 示例)在它们不存在时处理安装(然后它是否为每个需要它们的软件安装一个新副本?)。
您的计算机上是否可能有同一个 DLL 的多个副本,因为一堆单独的程序需要它,但无法知道您是否已经在某处安装了它?
换句话说,两个由不同人编写的程序是否可以 link 到同一个 DLL 文件?他们如何找到该 DLL,或者如果它不存在则安装它?
对于我在提出这些问题时所造成的任何基本误解,我提前表示歉意 -- 我对打包 already-built 软件的想法还很陌生。
The short answer is that the dll loader will look for dlls in the local application folder and then searching a bunch of system locations. There are complexities with manifests, the
SafeDllSearchMode
feature (affects directory search order) and developers loading dlls from custom locations by override (LoadLibraryEx) and several others (see below).
Dependencty Types: There are many types of dll dependencies: Module / dll dependencies mind map.
Dynamic-Link Library Search Order: Here is an extract from Microsoft Docs 主题:“一个系统可以包含同一个动态-link 库 (DLL) 的多个版本。应用程序可以控制 DLL 所在的位置通过指定完整路径或使用其他机制(如清单)加载。"
换句话说,您可以 1)
从特定位置加载 dll 或者 2)
让 OS 通过标准机制为您找到它。 "SafeDllSearchMode"
注册表设置会影响搜索用户当前目录的时间。它现在默认为打开,但可以禁用。有关权威详细信息,请参见上面的 link。 注意 OS 更改和安全修复 - 将来都会影响此订单。
Q1:始终使用为依赖的 dll 提供的运行时(如果可用)。不要只包含一些不应该的 dll。
Q2:运行时通常非常不同是正确的。有时它们只是一个或几个 dll,您可以将它们安装在本地应用程序文件夹中。其他时候,您安装运行时设置,将文件安装到适当的文件夹以供共享。有些运行时作为“合并模块”出现,可以将文件合并到您自己的 MSI 安装程序中,有些运行时作为单独的 MSI 安装程序或 setup.exe 安装程序出现。
Q3:使用dlls的整个想法本质上是能够将相同的二进制组件加载到多个处理以便能够更新单个 dll 以修复 dll 的所有“消费者”中的问题,并在内存中共享它们(这在内存很少的时候很重要)。 Dll 也可以“延迟加载”——这意味着它们只有在需要时才会加载——避免内存膨胀。反正就是这个主意。
Windows OS Version: 正确的搜索顺序(在磁盘上搜索的位置)要加载的 dll 是一个相当复杂的话题。 OS 加载器机制如何定位 DLL 会受到许多因素的影响,例如 1)
OS 版本, 2)
清单,3)
硬编码改变的加载路径(LoadLibraryEx), or 4)
dll redirects,和 5)
以前在内存中加载的 dll(这里是龙)等...
UWP & .NET:UWP applications. For .NET assemblies the resolution is different again (which you state), please see this article: How the Runtime Locates Assemblies.
也有新进展WinSxS:清单是 Windows 中的一个较新概念 - 在过去没有这样的东西并且搜索顺序会更简单,但不太灵活。随着清单和并排 Win32 程序集(同一 dll 的多个版本安装在不同版本中)的出现,清单嵌入到可执行文件中(或从外部添加),它告诉二进制文件在哪里寻找运行时dlls - 在 Windows 的 WinSxS
文件夹层次结构中(通常:C:\Windows\WinSxS
),其中可以驻留同一个 dll 的多个版本(在不同的子文件夹中) ).
大多数 Microsoft 运行时 - 基本上所有现代运行时 - 都驻留在此处,因此需要清单来指示二进制文件要查找和加载的版本。也有重定向此类清单的方法... "Publisher Configuration Files" and 2. Sigh... This can be used to enforce a certain new runtime version when the old one is undesired for use. Unused runtimes can also be "garbage collected" via ways to shrink the WinSxS folders (See this answer - 部分 “清理/节食 WinSxS”)...嗯...永远不要硬编码路径WinSxS.
Dll搜索顺序: The old and outdated tool Dependency Walker has an outdated, but very good description of the DLL Search Order in its help file.
提示:更新后的文档是:Microsoft Docs: Module Search Order for Desktop Applications. However, to get a rough idea of search order, you can just launch Dependency Walker 和 select : Options
=>
Configure Module Search Order...
。然后确保 Expand
按钮已取消select。您看到的内容 - 尽管可能已经过时 - 可以帮助回忆模块搜索顺序的工作原理:
链接:
- DLL search on windows(关于同一主题的旧 Whosebug 答案)
- The path-searching algorithm is not a backtracking algorithm
- The case of the DLL that refuses to load