【问题标题】:Load-time dynamic link library dispatching加载时动态链接库调度
【发布时间】:2016-11-28 04:23:25
【问题描述】:

我希望我的 Windows 应用程序能够引用包含在 DLL 中的大量类和函数,但我需要能够引导应用程序在加载该 DLL 之前选择正确版本。我熟悉使用 dllexport / dllimport 和生成导入库来完成加载时动态链接,但我似乎无法在互联网上找到任何关于可能在导入库本身中找到某种入口点函数的信息,所以具体来说,我可以使用 CPUID 来检测主机 CPU 配置,并根据该信息决定加载特定的 DLL。更具体地说,我想构建 DLL 的 2 个版本,一个使用 /ARCH:AVX 构建并充分利用 SSE - AVX 指令,另一个假设没有比 SSE2 更新的版本。

一个要求:要么必须在加载时链接 DLL,要么需要一种超级简单的方法来手动绑定从 DLL 外部引用的函数,并且有很多,主要是封装在类中。

额外问题:由于我的库将是跨平台的,是否有基于 Linux 的共享对象的等价物?

【问题讨论】:

  • 使用工厂模式来获得你想要的任何实现?
  • 我会用自定义的helper function 查看delay-loaded DLLs。帮助程序应该能够在运行时确定要加载哪个 DLL。
  • 一个更简单的选择:在应用程序启动期间将延迟加载与调用SetDllDirectory/AddDllDirectory结合起来。不太灵活,因为所有相关的 DLL 必须共享相同的名称,并且位于不同的目录中。
  • 我阅读了一些关于延迟加载的内容,但很明显我必须将其设置为可执行应用程序中的链接器设置(真的?),我宁愿不这样做,但也许没关系,因为我可以在其使用中记录该要求。

标签: c++ windows dll load-time cpuid


【解决方案1】:

我建议您尽可能避免从可执行文件中动态解析 DLL,因为它只会让您的生活变得艰难,特别是因为您有很多暴露的接口而且它们不是纯 C。

可能的解决方法

创建一个“选择器”进程,提供必要的 UI 以决定您需要哪个 DLL,或者它甚至可以自动确定它。让该进程将已决定的任何 DLL 移动到您的主要可执行文件所期望的标准位置(和名称)。然后让选择器进程启动您的主要可执行文件;它将从您的标准位置获取其 DLL,而无需知道那里的 DLL 版本。没有延迟加载,没有不稳定,没有额外的编码;很容易。

如果这不是您的选择,那么这里是您延迟加载 DLL 的起点。这是一条崎岖不平的道路。

Windows

Linux

【讨论】:

  • 应该注意possible workaround 将不允许应用程序的两个实例在不同的DLL 选择下同时运行。
  • 好点,虽然听起来 OP 每次都会根据机器配置做出相同的决定。在最坏的情况下,您可以通过在启动主可执行文件之前让选择器 exe 修改 LD_LIBRARY_PATH(和 Windows 等效)环境变量来使其工作,这会将其指向包含所选 DLL 的新目录;新目录将根据进程 ID 或随机 ID 命名。
  • 潜在的行为变化非常非常不可能。一方面,延迟加载的辅助函数是documented。他们只改变了一次(Changes in the DLL Delayed Loading Helper Function Since Visual C++ 6.0)。 VC++6 于 1998 年发布。Constraints of Delay Loading DLLs 可能不是 OP 的问题。
  • 好的,所以提供 UI 不是一个选项,因为我将为开发人员提供运行时 SDK,所以最好加入链接。如果我使用延迟加载,1)我可以在不使用函数指针的情况下保持我的类和函数定义相同,这意味着我的定义会延迟链接吗? 2) 如果导入库是静态链接的,是否在 exe 链接器设置中指定延迟加载的 DLL 会阻止 DLL 被提前加载,还是我需要卸载它并重新加载?
  • 我有几分钟的时间来玩这个。似乎它应该很容易,只需启用从主机应用程序延迟加载,并在确定要传递给它的 dll 之后使用 __HrLoadAllImportsForDll 。我认为这实际上会很好。我可以将标头、库和 dll 以及少量示例代码或准备好的 cpp 打包到 SDK 中,以便开发人员可以从某些机器上获得额外的性能(如果他们选择),否则将加载最低公分母 dll默认情况下,这也很好。谢谢大家!
【解决方案2】:

要添加到 qexyn 的答案,可以通过生成一个小型静态存根库来模拟 Linux 上的延迟加载,该库在第一次调用它的任何函数时将 dlopen 然后将实际执行转发到共享库。此类存根库的生成可以通过自定义项目特定脚本或Implib.so自动生成:

# Generate stub
$ implib-gen.py libxyz.so
# Link it instead of -lxyz
$ gcc myapp.c libxyz.tramp.S libxyz.init.c

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-07-07
    • 1970-01-01
    • 2012-06-28
    • 1970-01-01
    • 2014-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多