Yes. But I want to make clear that you are still using global state for all uses within the project itself. The library can be implemented in whatever way. For example, setting the pointer in a global variable on API entry ;-)
> That doesn't solve the problem at all.
WHICH problem? I don't think there is one.
> Indeed, and they're seen as bad practice for the same reason as global state in general.
This is foolish. There is no problem with global state. Global state is a fact of life. Your process has one address space. It has (probably) one server socket for listening to incoming request. It has (probably) one graphics window to show its state. Whenever you have more (e.g. file descriptors, memory mappings, ...), well then you have a set of that thing, but you have ONE set :-). And so on.
You are not writing a thousand pseudo-isolated programs. But ONE. One entity composed of a fixed number of parts (i.e. modules, code files) that work together to do what must be done.
Why add indirection? Why make it hard to iterate over all open file descriptors? Why thread a window handle through 15 layers of function calls when you have only one graphics window? It adds a lot of boilerplate. It even brings some people to invent hard to digest concepts like monads or objects just to make that terrible code manageable. It makes the code unclear. Someone once described it with this analogy, "I don't say ''I'm meeting one of my wives tonight'', unless I have more than one".