Or just dynamic link to libc and static link the rest as much as you can. If a binary dynamically links to libc, but is otherwise statically linked, all good no?
Yes, that was option [3]. The problem is that glibc symbols are versioned and update fairly regularly, so your binary likely won't run on anything with a much older glibc, and glibc versions vary a lot across distros (e.g., some are much slower moving so use very old glibc).
To work around this you need to try to build on an old of a distro as possible, so you use only old symbols... but you don't want to build on an ancient compiler since it might not support the language version or compiler flags you need, so you first build a new old toolchain on the old distro against the old libc, or find a docker container from someone who has already gone though this pain.
Of course, this also means you can't use new libc features: libc is more than just the C runtime, it's also the shim layer between userspace and the kernel, so you might miss out on newer system calls (or have to write the wrappers manually, etc).
The major library version number (e.g., 5 vs 6) isn't enough: the symbols even within lib.so.6 are versions and some may update every glibc version, so in general you may have problems building against a new libc 6 then running on a system with an old libc 6 (you'll get a runtime error from the dynamic loader complaining a missing versioned symbol).