I have a circular dependency between two functions. I would like each of these functions to reside in its own dll. Is it possible to build this with visual studio?
foo(int i)
{
if (i > 0)
bar(i -i);
}
-> should compile into foo.dll
bar(int i)
{
if (i > 0)
foo(i - i);
}
-> should compile into bar.dll
I have created two projects in visual studio, one for foo and one for bar. By playing with the 'References' and compiling a few times, I managed to get the dll's that I want. I would like to know however whether visual studio offers a way to do this in a clean way.
If foo changes, bar does not need to be recompiled, because I only depend on the signature of bar, not on the implementation of bar. If both dll's have the lib present, I can recompile new functionality into either of the two and the whole system still works.
The reason I am trying this is that I have a legacy system with circular dependencies, which is currently statically linked. We want to move towards dll's for various reasons. We don't want to wait until we clean up all the circular dependencies. I was thinking about solutions and tried out some things with gcc on linux and there it is possible to do what I suggest. So you can have two shared libraries that depend on each other and can be built independent of each other.
I know that circular dependencies are not a good thing to have, but that is not the discussion I want to have.
It is not possible to do cleanly. Because they both depend on each other, if A changes, then B must be recompiled. Because B was recompiled, it has changed and A needs to be recompiled and so on.
That is part of the reason circular dependencies are bad and whether you want to or not, you cannot leave that out of the discussion.
I deeply sympathise with your situation (as clarified by your edit), but as a firm believer in doing the correct thing, not the thing which works for now, if there's any possibility at all I think you need to refactor these projects.
Fix the problem not the symptom.
The reason it works on Unix-like systems is because they perform actual linking resolution at load time. A shared library does not know where its function definition will come from until it's loaded into a process. The downside of this is that you don't know either. A library can find and call functions in any other library (or even the main binary that launched the process in the first place). Also by default everything in a shared library is exported.
Windows doesn't work like that at all. Only explicitly exported things are exported, and all imports must be resolved at library link-time, by which point the identity of the DLL that will supply each imported function has been determined. This requires an import library to link against.
However, you can (with some extra work) get around this. Use
LoadLibrary
to open any DLL you like, and then useGetProcAddress
to locate the functions you want to call. This way, there are no restrictions. But the restrictions in the normal method are there for a reason.As you want to transition from static libraries to DLLs, it sounds like you're assuming that you should make each static library into a DLL. That's not your only option. Why not start moving code into DLLs only when you identify it as a self-contained module that fits into a layered design with no circularity? That way you can begin the process now but still attack it a piece at a time.
You need to decouple the two DLLs, placing the interfaces and implementation in two different DLLs, and then using late binding to instantiate the class.
The "Factory" classes are technically not necessary, but it's much nicer to say:
in application code than:
because of the following reasons:
-- Kenneth Kasajian
Visual Studio will enforce the dependencies, generally speaking, since function addresses may change within the newly-compiled DLL. Even though the signature may be the same, the exposed address may change.
However, if you notice that Visual Studio typically manages to keep the same function addresses between builds, then you can use one of the "Project Only" build settings (ignores dependencies). If you do that and get an error about not being able to load the dependency DLL, then just rebuild both.
How about this:
Project A
Public Class A Implements C.IA
End Class
Project B
Public Class B Implements C.IB
End Class
Project C
Project D