For set-once global variables there's OnceCell. I understand it's super frustrating if you don't know it exists, and DIYing it from first principles requires knowledge of both Rust's low-level primitives as well as OS/multithreading techniques.
OTOH it is an example how thread-safety extends to everything in Rust, and you can't be surprised by some function somewhere unsafely mutating global state.
If you read the topic, you would see that even OnceCell did not work (unless you wrapped thing into mutex, or implemented deep copy, which is again what I did not want).
You haven't provided more details beyond "doesn't work, wants Copy", which sounds to me like you've tried to move data from behind a reference, or perhaps expected a placement-new style initialization. You could post your code on users.rust-lang.org to get a solution.
It's super common for programmers coming from C to have a blind spot around strict static ownership, equate references with pointers and try to use them for "not copying", while in Rust they mean "not owning". This desire to avoid copies instead results in needless fights with ownership and the borrow checker. Rust moves never do deep copies, but Rust approaches this differently than C, and it takes practice to internalize that.
Everyone in that thread told you OnceCell would work, because it really would. People do write huge programs in Rust every day. There's a steep learning curve, but once you know the Rust-specific programming patterns, rather than try to write C in Rust, it goes smoothly.
Expect the person who tried to do it as well (first telling me OnceCell and RWLock would work) in the end could not get it working either and gave up in half a hour. In the end I moved on, I still program in rust, but it's not a good language when you have to work on the memory level and avoid copying data, even with unsafe, which is sad because unsafe could be more powerful if it actually gave you the power to actually instruct the borrow checker at the end of unsafe block what the state of things should be now, when it can't figure it out itself.
Assigning to RwLock is trivial, so if nobody was able to do that, then shared^mutable limitation was a red herring, and your issue wasn't with thread safety at all. HN-comment-based blind debugging of your program is getting pretty far from the topic of the thread and TFA…
The next most common footgun C-style expectations get you in Rust is self-referential structs, when you create a new object and then take (temporary scope-bound) references to inside of it, and try to store them long-term in unrestricted scope. That is a thing safe Rust doesn't guarantee without Rc/Arc, regardless whether it's thread-safe or not (moves can trivially invalidate such structs in single-threaded code too).
OTOH it is an example how thread-safety extends to everything in Rust, and you can't be surprised by some function somewhere unsafely mutating global state.