The dominant libc for Linux, glibc, says "static linking is highly discouraged", see [1] among many other sources for the subtle problems it causes.
There are solutions like [2], [3], and [4] but they all have downsides and don't compare at all to e.g., the go (or even rust) single-executable story.
---
[1] https://stackoverflow.com/questions/57476533/why-is-statical...
[2] Link glibc anyway and try to avoid the pitfalls.
[3] Link glibc dynamically but everything else static, and build your exe using an ancient toolchain (or better, a new toolchain built for an ancient libc) so that it works on most distros.
[4] Give up on glibc and statically link an alternative libc like musl.
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).
It gets even worse for C++.
But yeah that's pretty rare tbh.
> [3] Link glibc dynamically but everything else static
Go does this. Zig links musl [4] by default but gives you the option to link glibc. I don't know about Rust.
I don't think so: they only make it ABI backwards compatible (compile against old glibc, run against new) and API compatible (recompile your source against different versions should work).
I just checked by glibc and it had > 200 symbols versioned 2.34 which is the current glibc version. If you use any of those you can't run against older glibc.
Ok, I can see what I have written that could read this way, but the context is completely about backward compatibility. Forward compatibility isn't a concept that appears often in software.
E.g., you might use a relatively recent distro in your GitHub action (or whatever) to build this binary, but then anyone running CentOS or whatever can't run it because they ship an older libc version and required symbols aren't available.
You seem to want some way to have your code run on any platform whatever features you use in it. That you can't have. Of course if you want to support CentOS 6, you have to avoid any new symbol.
It's true, though. Proof of that is how many tools are made basically because no one wants to deal with Makefiles and autotools. I'd argue that even Docker fits this category of tools made to hide C/C++ builds away
no one wants to deal with Makefiles and autotools because as of 2022 they don't support spaces in paths and the most used desktop OS on the planet happens to have spaces in the default path for installing software
Also why would you be using autotools in 2022? CMake has been the de facto standard for about a decade now.
Combine that with the multiplicity of build systems, and it's easier to just use dynamic linking. Go and Rust solve that by having a standard build system.
If the app has assets it gets a little crazy quite quickly.
[0] Which of course came from NeXT Application Bundles, which is also where OSX Application Bundles came from.
I always wish that’d taken off.
I guess AppImage isn’t dissimilar in that it appends a squashfs image to be mounted with FUSE.
> C/C++: certainly possible, but you'll need on retainer a UNIX graybeard, or at least an autotools-foo master
I don't understand this. The "C/C++ is black magic!!" meme just never seems to go away.
They both support static linking and always have. It mostly comes down whether you dependencies will work with it, and setting appropriate compiler flags. In other words, not terribly different than anything other supporting language.