Until now, I have been simply working off SDL2/OpenGL on Linux. However, now I am trying to implement multiple platform layers and have seem to hit a problem.
(For the record, I am using the "OS Virtualization" approach that Casey mentioned as it seemed appropriate. If it turns out that it is causing all the trouble, I don't have a problem in switching to what Casey actually used.)
Let's take an exaggerated example: say I want to write a platform layer for Linux that will be compatible with maximum number of machines. So, I use Xlib and OpenGL; however, possibly in future, Wayland might become the BIG thing and might not have proper X11 emulation. So, now I have Xlib/OpenGL and Wayland/OpenGL. And Ubuntu is working on Mir, so Mir/OpenGL is in there too. But X can be used on MacOS too (I think) so let's add a Xlib/OpenGL-MacVersion. And when we are at it, Cocoa/OpenGL, Cocoa/Metal and Xlib/Metal don't sound bad either. On the other hand, Windows support OpenGL; so, Win32/OpenGL is in mix along with Win32/D3D and potentially Win32/Vulkan. And of course, we need OpenGL 2.0/3.3/4.4, DX 9/11/12 and please save me!
What I tried to do was compile a "partial-platform layer" with each of these APIs into DLLs and the idea was that I could interop them. However, after much headbutting, that doesn't seem to be working as each of these combination might have a slightly different interface (example: some of these APIs might want window handles, some might not, some might want special data/context extracted using window handles, etc). So, the question is: how can I manage this kind of chaos? I could simply reduce the support to one API pair per OS but are there any better solutions to this problem?
Wayland is already big, especially in embedded Linux world.
Mir is dead. Ubuntu this week announced they will be dropping Unity and Mir.
Nobody sane uses X on macOS anymore. You can, but why?
Now back to the topic - the main question would be what is your use case for all this? Does your game layer really want to use render API directly? Usually answer is no. Typically game cares about high level API. So abstract renderer API like HH does away. And use only one render API per platform. For Windows it would be D3D, for macOS it would be Metal, etc.. In worst case you'll have maybe only 2 API's (like OpenGL and Vulkan for Linux).
You can isolate the platform specific parts of opengl. Move the platform specific context creation and making it current into the OS specific layer and ensure that every time the opengl.dll gets called the context is current.
Same for vulkan, the only platform specific part is loading the loader lib and getting the vkSurface. That is small enough to move to the OS specific layer.
XLib support isn't going to go away, it's far too entrenched to be disposed of within the next few decades.
As for different version/API I would simply pick a lowest common denominator and implement just that, only add a newer version/other api if it would give a serious performance boost. Like going full AZDO opengl or vulkan instead of the ubiquitous openglES2.0.