We actually have two lightweight compatibility layers we maintain at Wētā FX:
First, a runtime one which is things that all versions of the OS have in LD_LIBRARY_PATH. This has a few things in it (I see 40 files and a symlink), the most important being the newest libstdc++ trying to stay ahead of both the O.S. and the newest compiler we are supporting. For example, I think we're on libstdc++.so for gcc 12.x - so technically ahead of the VFX reference platform and the O.S. but just so we don't have to update quite as often. Given the symbol versioning in libstdc++, this is safe and really smooths out most of the compatibility issues we've had in the past. Similarly, libraries like the address sanitizer / gcc / gfortran / etc. come along with that. Then we provide an OpenMP that attempts to deal with the varied implementations of that (clang / gcc / intel) and their varied level of support.
One reference platform-specific thing of note here: we are also starting to do that same trick for libraries like TBB which provides a backwards compatible shared object, enabling people to mix TBB versions in an environment more easily. Basically, a solution born out of practicality when mixing environments with different versions of tools. The inline headers and all that layer of TBB remain reference platform consistent, this is only the shared object.
Then we have recently added a second compatibility layer which is O.S. version specific, such that we can support legacy DCC tools and such which need older shared object versions that they don't provide in their distributions. Normally, this might be handled by having a "compat" version from the O.S. but we have been finding it less frustrating to construct this set manually, as occasionally this involves relinking to avoid sprawl and keep the layer as light touch as possible and not just replicating entire old versions of an O.S.. That currently has 60 or so shared objects and about the same number of symlinks for Ubuntu 22.04, so not horrible to maintain.
Both of these sets of shared objects are then added to our environments universally via LD_LIBRARY_PATH since we have that mechanism and it allows us to test different setups. Although once settled, they don't change very frequently so might easily be able to do something less environment variable dependent, via something like overlay FS, OCI container, or simple package with ld.so.conf changes.
We have separately done something similarly for jemalloc, as different DCCs have different methods of compiling jemalloc - basically the function names that are exposed, but share the same SO name. So when we want to use jemalloc in our own tools, which may provide libraries for use in a particular DCC, we provide a jemalloc which provides all the symbols (as symbol aliases). This is not yet included in the above, but managed separately, although we may look at that in the future.
Happy to provide more details as needed.
best,
Kimball