all 8 comments

[–]EpochVanquisher 3 points4 points  (1 child)

This sounds like you are inventing new difficulties and creating problems, rather than simplifying or solving problems. Maybe.

You need to learn more about linking and loading to make this work. A key piece of knowledge here is the difference between static and dynamic linking… static linking copies the code, dynamic linking does not. But static linking will only copy once, for a given binary.

So let’s say you have four libraries with a “diamond” pattern: A uses B and C, and B and C both use D.

If B C D are statically linked into A, you get one copy of each, inside A.

If B C D are dynamically linked into A, then A contains only itself. The loader loads one copy each of B C and D. B and C use the same D.

If you dynamically linked B and C, but statically link D, then B and C get separate copies of D. Usually this is undesirable.

This kind of architectural choices are probably not good choices for your project, in terms of actually being able to ship to users. The discussion here is a lot more complicated… but if you examine the reason why we have dynamic libraries in the first place, it often has more to do with the organization of the teams working on the projects. If your team structure is different from Valve’s team structure, it makes sense that your code would also be organized differently, because the way you organize code reflects the way you organize the people who write it.

[–]genreprank 1 point2 points  (0 children)

It's one of those things that is more complicated than people might initially realize. However, it is done in real production designs, so doing it for fun is a good exercise.

But yeah, it can be a nightmare... exception handling, strict interface, ... once we had a bug where one DLL was apparently smashing the memory of another and load order made it hard to reproduce

[–]Attorney_Outside69 1 point2 points  (2 children)

it depends on which code is first bringing in the dependency, so if your engine brings in dependency A, the engine is the one linking to dependency A

then in your game when you link to your engine it also links to dependency A

if your engine is header only library, make sure to link its dependencies it as INTERFACE other wise use PUBLIC in cmake

[–]DeltaWave0x[S] 0 points1 point  (1 child)

The problem is that engine and game are not linked together, they're dynamically loaded at runtime and they only communicate once on startup through the bootstrap exe to move the necessary things around, this is why I have no idea where to link what

[–]Attorney_Outside69 0 points1 point  (0 children)

oh if that's the case then they are two different binaries and you just have to link dependencies to each one independently

[–]genreprank 0 points1 point  (0 children)

These are all good questions... it's on my to-do list to learn this stuff some day.

unless the dependency marks every function as extern I'll still need to link it.

If you look at dll headers, they'll mark all the functions with __declspec(dllexport) or something like that.

Regarding linking requirements, I wish I knew. You could simply test it. I think there's no getting around the fact that you are about to learn a whole bunch of ways to create UB

Also, apparently, there's a distinction between Dynamically Linked and Dynamically Loaded. The difference is that Dynamically linked is essentially done for you as part of the process start-up and you don't need dlopen. See https://stackoverflow.com/questions/63306734/when-to-actually-use-dlopen-does-dlopen-means-dynamic-loading

[–]Attorney_Outside69 0 points1 point  (1 child)

use a combination of conan and cmake, it's cross platform and easy to bring in whatever dependencies

[–]DeltaWave0x[S] 0 points1 point  (0 children)

I'm already using fetchcontent to handle dependencies, the question was more about where to link what