我正在尝试处理具有多个动态库的项目,在库中创建一些全局对象并将其注册到列表中,以便可执行文件可以使用它们来构建其他东西。在可执行文件中,没有引用任何库的任何函数,它只需要对象,然后它知道该怎么做。这些库旨在像在链接时选择的插件一样工作。
理想情况下,在编译时ExecutableProject
我链接LibraryA
,创建一个类型为 A
的对象(由库中编译的一些代码),并ExecutableProject
使用它,使用 LibraryA
中的函数。相反,如果我链接LibraryB
则创建B
类型的对象并发生其他事情。
问题是,由于 ExecutableProject 不直接使用库中的任何函数或类,因此不会加载库,并且永远不会创建对象。
我找到了一些解决方法:
- 我可以在编译
ExecutableProject
时在链接时使用/INCLUDE:symbol
,其中符号是以LibraryA
或LibraryB
导出的任何符号。我不喜欢这样,因为我必须知道库中函数的装饰名称,而该名称并不总是可用。而且,它并不优雅。 - 我可以使用虚拟变量。我可以把
__declspec(dllexport) int force_link_A_or_B;
放在LibraryA
和LibraryB
,__declspec(dllimport) extern int force_link_A_or_B;
放在ExecutableProject
.我不喜欢这样,因为如果我有更多的库,我必须为每个库添加一个变量。基本上,虽然ExecutableProject
中的代码不知道哪些库将被链接,但它仍然需要知道其中有多少可以链接在一起。
在Linux上,使用gcc和ld,解决这个问题非常容易,只需要一个简单的链接器标志-Wl,--no-as-needed
。有没有办法使用Visual Studio来做到这一点?如果有一些东西像/INCLUDE
一样工作,但使用整个库而不是符号并且不需要装饰名称,我会很高兴。
谢谢
编辑:我被要求澄清这个设计是如何工作的。 理想情况下,当我编译ExecutableProject
时,我链接LibraryA
或B
并创建一个对象。
`ClassA A;`
它放置在用 LibraryA
编译的源文件中的所有函数之外。同样的事情发生在LibraryB
.这里的关键是,ClassA
和ClassB
继承自ExecutableProject
熟悉的BaseClass
。创建对象时,将运行 BaseClass
构造函数,并在其中保存指向this
(因此派生对象)的BaseClass*
指针,ExecutableProject
使用该指针。它不需要知道任何关于派生类的信息,因为它只使用一个BaseClass
指针,但是当它从中调用虚函数时,会根据指向对象的实际类型执行不同的函数。如果有更多的对象而不是两个替代方案,我会在列表或地图中保存BaseClass
指针,并让ExecutableProject
访问它。
不要尝试这个。该设计存在根本缺陷。
特别是,由于您没有对 DLL 进行任何显式调用,因此您将仅依赖于通过对 DllMain
的隐式调用创建的对象A
。
但是根据Windows规则,您被禁止在DllMain
中或从中做任何有趣的事情,因此对象A
不能很有用。