Singletons and multiple crate versions

I’ve read quite a few articles (both here and elsewhere) about singletons. Often not the best design pattern, but sometimes necessary because that’s just inherently the nature of the system you’re interacting with. One thing I’ve never seen mentioned is the issue of crate versions! Things like lazy_static, or static Cell, or static mut, or whatever solution, as far as I can tell all have a single common problem: you can have two simultaneous instances of the object if your depgraph pulls in two versions of the crate that contains the lazy_static or whatever (because e.g. your binary and one of its dependencies depend on semver-incompatible versions).

Has anyone come up with a solution that handles this?

I think failing to compile would be a reasonable outcome. After all, the proper way in which the singletons should be used is that e.g. my_binary and my_intermediate_library both depend on my_library_with_a_singleton, but my_binary does the singleton-take operation and my_intermediate_library only accepts the singleton passed in by the caller. If my_binary and my_intermediate_library end up depending on different versions of my_library_with_a_singleton, then this properly written code will fail to compile because my_library_with_a_singleton(v1.0)::Singleton is not the same type as my_library_with_a_singleton(v2.0)::Singleton and therefore cannot be passed as a function parameter in the relevant place.

The concern is that, if my_intermediate_library were written to take the singleton itself instead, you’d end up with this perverse outcome where if only a single version is pulled into the depgraph then everything blows up at runtime (as it ought to, since two things are trying to take the singleton), but if two versions are pulled in, then nothing explodes and you get whatever badness the singleton was trying to prevent.

You can use (or abuse) the links field for this. It requires a build script too, but that can be a no-op fn main() {}.

Hm, yes, that might work. It looks like that would be a violation of “When using the links key, the package must have a build script, and the build script should use the rustc-link-lib instruction to link the library” (here) but I suppose that’s only a SHOULD, not a MUST.