C++ DLL - 打破循环依赖

标签 c++ dll circular-dependency

我正在重构一个 5.5k 行的 C++ DLL,将其拆分为多个较小的 DLL。不幸的是,很多代码是捆绑在一起的,在拆分 GiantDLL 的过程中,我引入了几个循环引用。

更具体地说,

//In emergeOSLib.h:
DLL_EXPORT std::wstring ELGetProcessIDApp(DWORD processID, bool fullName);

//In a couple of functions in emergeOSLib.cpp:
ELMessageBox(GetDesktopWindow(), messageText, (WCHAR*)TEXT("Emerge Desktop"),                       ELMB_OK|ELMB_ICONERROR|ELMB_MODAL);

//In emergeUtilityLib.h:
DLL_EXPORT int ELMessageBox(HWND hwnd, std::wstring messageText, std::wstring messageTitle, DWORD msgFlags);

//In a function in emergeUtilityLib.cpp:
out << ELGetProcessIDApp(GetCurrentProcessId(), false) << TEXT(": ") << debugText << std::endl;

瞧,一个循环引用。我很确定还有更多,这只是我现在正在处理的一个。

我做了一些研究,发现前向声明似乎是可行的方法:
Resolve header include circular dependencies
Circular Dependency in C++

第二个链接甚至建议前向声明更可取#include

此时我有两个问题。首先,如何前向声明另一个 DLL 中的函数?我的理解是编译器仍然无法找到前向声明的函数(因为它没有将第二个 DLL 编译为第一个 DLL 的一部分)并且会报错。其次,#include 语句或前向声明哪个通常被认为是更好的做法?

最佳答案

前向声明 vs #include 只有助于声明循环。但是你有定义循环。如果您将所有定义链接在一起,多 channel 链接器会解决这个问题……但您没有。

基本上有两种方法可以做到这一点。首先,您可以将 ELGetProcessIDApp 更改为实用程序库中的函数指针。最初它指向实用程序库中的某个 stub 值,当操作系统支持库加载时,它会用特定于操作系统的实现覆盖该函数指针。

或者,您可以在 DLL 实际存在之前使用链接器定义文件构建导入库。这将通过创建一组循环依赖的 DLL 来解决您的链接器问题。它可以工作,但它也可能导致令人惊讶的加载顺序效果并表现出全局初始化顺序失败。

或者,只使用单个 DLL,并将重构限制为拆分源文件。

关于C++ DLL - 打破循环依赖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19698889/

相关文章:

c++ - C++ 教程上的机器语言指令

C++:检查表达式是否编译的模板

c++ - 将 SDL_Surface Blit 到另一个 SDL_Surface 并应用颜色键

c++ - DLL 创建类型

dart - Dart-初始化静态字段时的循环依赖

python - 没有导入导致循环依赖?

dependency-injection - CDI 注入(inject)回路

c++ - 如何在不导入表的情况下编译C++ Windows exe

c# - 将 DLL 嵌入已编译的可执行文件中

java - 使用 JNA 从 java 调用 VB DLL 文件的函数