Question

I'm working on refactoring a 5.5k-line C++ DLL, splitting it into a number of smaller DLLs. Unfortunately, a lot of the code is tied together, and in the process of splitting the GiantDLL I introduced a couple of circular references.

More specifically,

//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;

And voila, one circular reference. I'm pretty sure there are more, this is just the one I'm dealing with right now.

I've done some research and found that forward declarations seem to be the way to go:
Resolve header include circular dependencies
Circular Dependency in C++

The second link even suggests forward declarations are preferable to #includes.

I have two questions at this point. First, how do I go about forward-declaring a function that's in another DLL? My understanding is that the compiler still won't be able to find the forward-declared function (since it's not compiling the second DLL as part of the first) and will complain. Second, which is generally considered better practice, #include statements or forward declarations?

Was it helpful?

Solution

Forward declarations vs #include only help with declaration circularity. But you have definition circularity. A multi-pass linker would resolve this if you were linking all the definitions together... but you aren't.

There are basically two ways to do this. First, you can change ELGetProcessIDApp to a function pointer inside your utility library. Initially it points to some stub value in the utility library, and when the OS support library loads, it overwrites that function pointer with the OS-specific implementation.

Or, you can use a linker definition file to build an import library before the DLL actually exists. This will fix your linker problems by creating a set of circularly dependent DLLs. It can work, but it may also cause surprising load order effects and exhibits the global initialization ordering fiasco.

Or, just go with a single DLL, and limit your refactoring to splitting source files.

OTHER TIPS

how do I go about forward-declaring a function that's in another DLL?

You dont, it doesn't work. You can declare it, but the link stage will fail.

Instead, have DLL A linking against DLL B normally, and DLL B receiving function pointers (or objects featuring virtual functions) from DLL A at runtime.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top