对于Windows和POSIX,我有一些关于动态初始化(即main之前的构造函数)和DLL链接排序的问题。
为了便于讨论,我将定义几个术语:
加载时间库:已经过链接的库#34;在编译 时间,当系统加载我的应用程序时,它们会被加载 在自动。 (即放在CMake的target_link_libraries中的那些 命令)。
运行时库:我通过dlopen或手动加载的库 等价物。出于本次讨论的目的,我只说我 在main中使用dlopen手动加载库,所以这应该 简化事情。
动态初始化:如果您不熟悉C ++规范 对此的定义,请不要试图回答这个问题。
好的,我们假设我有一个应用程序(MyAwesomeApp),它链接到动态库(MyLib1),而动态库又链接到另一个库(MyLib2)。所以依赖树是:
MyAwesomeApp - > MyLib1 - > MyLib2
对于这个例子,让我们说MyLib1和MyLib2都是Load-Time Libraries。
上面的初始化顺序是什么?显而易见的是,所有静态初始化(包括导出/导入函数的链接(仅限窗口))都将首先发生......但动态初始化会发生什么?我期待整体订购:
所有导入/导出符号链接
所有静态初始化
所有MyLib2的动态初始化
所有MyLib1的动态初始化
所有MyAwesomeApp的动态初始化
MyAwesomeApp的main()函数
但是我无法找到任何要求这样做的规格。我看到了暗示它的小精灵的东西,但我需要在规格中找到保证,让我做一些我想做的事情。
为了确保我的想法清楚,我希望图书馆加载的工作方式非常类似于在Python中导入,如果它还没有加载,那么它就会被加载。我会在做任何事情之前完全加载(包括任何初始化)......如果它已被加载,那么我只是链接到它。
提供一个更复杂的示例,以确保我的第一个示例的另一个定义产生不同的响应:
MyAwesomeApp依赖于MyLib1& MyLib2 MyLib1依赖于MyLib2
我希望进行以下初始化:
所有导入/导出符号链接
所有静态初始化
所有MyLib2的动态初始化
所有MyLib1的动态初始化
所有MyAwesomeApp的动态初始化
MyAwesomeApp的main()函数
我喜欢任何帮助,指出说它是这样的规格。或者,如果这是错误的,任何说明真正发生的规范!
提前致谢!
-Christopher
答案 0 :(得分:3)
C ++标准中没有任何内容要求动态链接如何工作。
话虽如此,Visual Studio附带了C Runtime(又名CRT)源,您可以在dllcrt0.c中看到静态初始化器的运行位置。
如果您考虑运行每个阶段需要满足哪些约束,您还可以推导出操作的相对顺序:
第1步& 2不要相互依赖,所以它们可以独立发生。步骤3需要1&每个.dll都有2个,所以它必须在1和1之后发生。 2。
因此,满足上述约束的任何特定加载顺序都是有效的加载顺序。
换句话说,如果您需要关心特定步骤的特定顺序,那么您可能正在做一些危险的事情,这些事情依赖于在OS的主要或次要修订版本中不会保留的实现特定细节。例如,加载程序锁对.dll的工作方式在各种版本的Windows中发生了显着变化。