Dynamic loading, intertwining crates

As programs grow, at some point it becomes desirable to load components only on demand, taking advantage of the fact that not all components are needed at the same time.

Let there be an object system which also serves as an interface. Now the problem emerges that the plug-in crate needs data types of the main crate. In further consequence it happens that the plug-in crate should also have knowledge of the type id (trait Any) and virtual tables (type dyn TraitT) of types of the main crate.

I believe the problem could be partially solved by providing a third crate, only providing the abstract interface types and shared functionality. By assuming a fixed ABI (for a while), the crates can then refer to this interface. But it seems, this would not allow for reusing dyn TraitT, unless the needed types become part of the shared functionality. About type ids I don't know. The system would end up in such a dependency graph:

     libshared-functionality.so (dylib)
  libplugin1.so (dylib)    │

Actually the intertwining of the main system with the shared functionality could be so deep that it makes no sense to state an extra interface. Thus the main system and the plug-in should depend on each other:

libsystem.so (dylib) <───> libplugin1.so (dylib)