0

A C++ app has this exe/dll layout:

Main.exe, Framework.dll, PluginA.dll, PluginB.dll, ..., PluginN.dll

Both Main.exe and Framework.dLL provide functions to the Plugin#.dll.

The Plugins are depedent on Main.exe and Framework.dll, but not the other way around. Framework.dll depends on functions provided by Main.exe

Now, the problem is that there is a circular dependency between Main.exe and Framework.dll because Main.exe depends on 1 class in Framework.dll that it uses to manage the lifecycle of Framework.dll

So, in Main.exe, it would be something like this:

#include "Framework.hpp"

int main() {
    Framework fw;
    fw.Init();
    
    while (Quit() == false) {
        fw.Begin();
        DoWork();
        fw.End();
        MoreWork();
    }
    
    fw.Shutdown();

    return 0;
}

So, Main.exe depends on only 1 class from Framework.dll, but that's enough to create their circular dependency.

Is there a way to still use that one Framework class from Main.exe while still breaking the circular dependency? Specifically, so that Main.exe doesn't require the export library Framework.lib to build.

Dess
  • 2,064
  • 19
  • 35
  • 2
    It seems unhealthy to me for any of your DLLs to be calling functions defined in `main.exe` (in fact I'm not even sure how one does that). Can you change that? – Paul Sanders Jun 16 '22 at 17:35
  • 1
    Could you elaborate on why the dependencies are the way they are? I'd expect inverse dependencies. How come the executable implements ***any*** dependencies for other binaries? – fabian Jun 16 '22 at 17:36
  • An executable is just a library with an entry point. Nothing weird about that. The exe has access to things like keyboard and mouse input, state of the current window, and other things that need to be managed every frame. The dlls need to query for those things, like keyboard and mouse. – Dess Jun 16 '22 at 17:41
  • The plugin dlls are dynamically loaded, I assume? – fabian Jun 16 '22 at 17:50
  • @fabian: correct – Dess Jun 16 '22 at 17:55
  • If the DLLs contained calls to functions in the .exe and contained calls to specific addresses, it means a modified .exe could not load and effectively use your DLL. That makes the point of having a DLL completely moot. – Jeffrey Jun 16 '22 at 17:57
  • @Jeffrey -- It doesn't make it moot. It just means that when the exe is modified, the dlls need to be rebuilt. The opposite is not true: modifying the dlls doesn't necessitate an exe rebuild. I'm ok with this. – Dess Jun 16 '22 at 18:01
  • 2
    Just provide an abstract interface for any functionality from the main that needs to be accessed in the framework dll and then pass the implementation during initialization of the interface. This way the binary will still depend on the framework dll, but the framework does not depend on the exe, only on the abstract interface it provides itself... – fabian Jun 16 '22 at 18:30
  • Hi, fabian, I think the method you described is the same as this answer: https://stackoverflow.com/a/71306689/154911 – ollydbg23 Aug 18 '22 at 06:04

1 Answers1

1

The usual solution to this (although it's usually used when two libraries have a circular dependency) is to create a 'dummy' version of one of them that defines all the relevant entry points but is not in any way dependent on the other and doesn't need to link against it. That can then be used as a kind of 'bootstrap'.

So in your case, you might create yourself a dummy_framework.cpp file that you can build to provide a framework.lib that main can then link against. Once you've done that, you can compile the 'real' framework to generate the 'real' framework.dll and you should then have a fully functional version of your app. (You can rebuild main if you want, but there shouldn't actually be any need.)

This is all perfectly viable so long as the API of framework is reasonably stable, but even if it isn't, you'll get compiler or (more likely) linker errors when you try to build dummy_framework so you can update it then.

Paul Sanders
  • 24,133
  • 4
  • 26
  • 48