加载时动态 link 库调度
Load-time dynamic link library dispatching
我希望我的 Windows 应用程序能够引用一组广泛的 类 和包装在 DLL 中的函数,但我需要能够引导应用程序选择此 DLL 加载前的正确版本。我熟悉使用 dllexport / dllimport 和生成导入库来完成加载时动态链接,但我似乎无法在互联网上找到任何关于可能在导入库本身中找到某种入口点函数的信息,所以具体来说,我可以使用 CPUID 检测主机 CPU 配置,并根据该信息决定加载特定的 DLL。更具体地说,我想构建一个 DLL 的 2 个版本,一个是使用 /ARCH:AVX
构建并充分利用 SSE - AVX 指令,另一个假设没有比 SSE2 更新的东西。
一个要求:要么 DLL 必须在加载时链接,要么需要有一种超级简单的方法来手动绑定从 DLL 外部引用的函数,并且有很多,大部分都包含在里面 类.
额外问题:由于我的库将是跨平台的,是否有基于 Linux 的共享对象的等效项?
我建议您尽可能避免从可执行文件中动态解析 DLL,因为这只会让您的生活变得艰难,尤其是因为您有很多暴露的接口,而且它们不是纯 C 语言。
可能的解决方法
创建一个 "chooser" 进程来提供必要的 UI 来决定您需要哪个 DLL,或者它甚至可以自动确定它。让该过程将已确定的任何 DLL 移动到您的主要可执行文件所期望的标准位置(和名称)。然后让选择器进程启动您的主要可执行文件;它将从您的标准位置获取其 DLL,而不必知道那里有哪个版本的 DLL。没有延迟加载,没有不稳定,没有额外的编码;很简单。
如果这不适合您,那么这里是您延迟加载 DLL 的起点。这是一条更崎岖的道路。
Windows
- LoadLibrary() 获取内存中的 DLL:https://msdn.microsoft.com/en-us/library/windows/desktop/ms684175(v=vs.85).aspx
- GetProcAddress() 获取指向函数的指针:https://msdn.microsoft.com/en-us/library/windows/desktop/ms683212(v=vs.85).aspx
- 或可能使用自定义辅助函数的特殊延迟加载 DLL 功能,尽管存在限制和潜在的行为变化。我自己从未尝试过:https://msdn.microsoft.com/en-us/library/151kt790.aspx(由 Igor Tandetnik 建议,似乎合理)。
Linux
- dlopen() 获取内存中的 SO:http://pubs.opengroup.org/onlinepubs/009695399/functions/dlopen.html
- dladdr() 获取指向函数的指针:http://man7.org/linux/man-pages/man3/dladdr.3.html
要添加到 qexyn 的答案中,可以通过生成一个小型静态存根库来模拟 Linux 上的延迟加载,该库将 dlopen
在第一次调用它的任何函数时转发实际执行到共享库。此类存根库的生成可以通过自定义 project-specific 脚本或 Implib.so:
自动生成
# Generate stub
$ implib-gen.py libxyz.so
# Link it instead of -lxyz
$ gcc myapp.c libxyz.tramp.S libxyz.init.c
我希望我的 Windows 应用程序能够引用一组广泛的 类 和包装在 DLL 中的函数,但我需要能够引导应用程序选择此 DLL 加载前的正确版本。我熟悉使用 dllexport / dllimport 和生成导入库来完成加载时动态链接,但我似乎无法在互联网上找到任何关于可能在导入库本身中找到某种入口点函数的信息,所以具体来说,我可以使用 CPUID 检测主机 CPU 配置,并根据该信息决定加载特定的 DLL。更具体地说,我想构建一个 DLL 的 2 个版本,一个是使用 /ARCH:AVX
构建并充分利用 SSE - AVX 指令,另一个假设没有比 SSE2 更新的东西。
一个要求:要么 DLL 必须在加载时链接,要么需要有一种超级简单的方法来手动绑定从 DLL 外部引用的函数,并且有很多,大部分都包含在里面 类.
额外问题:由于我的库将是跨平台的,是否有基于 Linux 的共享对象的等效项?
我建议您尽可能避免从可执行文件中动态解析 DLL,因为这只会让您的生活变得艰难,尤其是因为您有很多暴露的接口,而且它们不是纯 C 语言。
可能的解决方法
创建一个 "chooser" 进程来提供必要的 UI 来决定您需要哪个 DLL,或者它甚至可以自动确定它。让该过程将已确定的任何 DLL 移动到您的主要可执行文件所期望的标准位置(和名称)。然后让选择器进程启动您的主要可执行文件;它将从您的标准位置获取其 DLL,而不必知道那里有哪个版本的 DLL。没有延迟加载,没有不稳定,没有额外的编码;很简单。
如果这不适合您,那么这里是您延迟加载 DLL 的起点。这是一条更崎岖的道路。
Windows
- LoadLibrary() 获取内存中的 DLL:https://msdn.microsoft.com/en-us/library/windows/desktop/ms684175(v=vs.85).aspx
- GetProcAddress() 获取指向函数的指针:https://msdn.microsoft.com/en-us/library/windows/desktop/ms683212(v=vs.85).aspx
- 或可能使用自定义辅助函数的特殊延迟加载 DLL 功能,尽管存在限制和潜在的行为变化。我自己从未尝试过:https://msdn.microsoft.com/en-us/library/151kt790.aspx(由 Igor Tandetnik 建议,似乎合理)。
Linux
- dlopen() 获取内存中的 SO:http://pubs.opengroup.org/onlinepubs/009695399/functions/dlopen.html
- dladdr() 获取指向函数的指针:http://man7.org/linux/man-pages/man3/dladdr.3.html
要添加到 qexyn 的答案中,可以通过生成一个小型静态存根库来模拟 Linux 上的延迟加载,该库将 dlopen
在第一次调用它的任何函数时转发实际执行到共享库。此类存根库的生成可以通过自定义 project-specific 脚本或 Implib.so:
# Generate stub
$ implib-gen.py libxyz.so
# Link it instead of -lxyz
$ gcc myapp.c libxyz.tramp.S libxyz.init.c