I don't know about Go, but Rust doesn't promote it. Rust compiles a whole binary at once (for full program optimisation), but that binary can be a dynamic library or executable. How you then build the operating system on top of that is up to you.
Recently, ripgrep was on the frontpage. It says "Linux binaries are static executables" [0]. If I run ldd on cargo, it spits out the usually glibc dependencies, but Rust libraries are statically linked. It seems to be the default behavior of cargo? I would describe that as "promote static linking".
Personally, I don't judge this as good or bad. There is no simple answer. Static linking has clear disadvantage wrt security patches. On the other hand, it makes little sense to dynamically link tiny libraries, e.g. a queue data structure.
> It says "Linux binaries are static executables" [0].
They are. Running `ldd` on cargo doesn't confirm or deny this. You need to run `ldd` on the binary distributed:
$ curl -sLO 'https://github.com/BurntSushi/ripgrep/releases/download/0.2.1/ripgrep-0.2.1-x86_64-unknown-linux-musl.tar.gz'
$ tar xf ripgrep-0.2.1-x86_64-unknown-linux-musl.tar.gz
$ ldd ./ripgrep-0.2.1-x86_64-unknown-linux-musl/rg
not a dynamic executable
By default, Rust statically links all Rust code. However, glibc isn't usually statically linked, so Rust doesn't either. You can use musl instead of glibc to get 100% statically linked binaries.
The problem here is that the choice is one extreme or the other, never the happy medium.
The extremes are statically linked everything and dynamically linked everything.
Bryan Cantrill deplores this part of the design of Go. He decries the fact that rather than sitting on top of a HLL-function-call binary interface, with the portability layer being HLL function calls like read(), write(), close(), socket(), execve(), Go produces executables that hardwire one specific instruction set's kernel system call traps.
GCC allows one to selectively statically link various libraries in an otherwise dynamically linked executable. (clang had yet to achieve this functionality, last that I checked a year or so ago.)
Bryan would have to elaborate an awful lot on the evilness of using system calls to make that a more general argument. (we're not supposed to use the kernel now for some reason?) It looks like it was just kind of a pain in the ass for the Joyent guys because of what they were doing specifically, which was pretty specialized.
(there's a mean and almost clinically insane blog post about Go by one of the other Joyent guys, who retired a week or two after writing it, which also doesn't shed much light but is funnier. You've got to wonder what their deal is with the Go guys, exactly...)
Yeah, on Linux, the system call interface is the supported interface for interacting with the kernel. Of course we are going to use it since 1) it's supported, 2) it's stable, more stable than e.g. glibc has ever been, not to mention we're not locked to a particular libc vendor, it just works on embedded systems which don't use glibc, 3) it allows us to make system calls without going through all the cgo machinery and without having to switch stacks.
On Solaris, the system call interface is not a supported public interface, so I made the Solaris port use libc through cgo.
Solaris made the decision that the supported public interface is through libc. That's a fine decision to make if you are the sole vendor of libc. But, that doesn't mean there's anything wrong with different operating systems making different decisions.
On Linux we use the Linux rules, and on Solaris we use the Solaris rules.
I will tell you this though, having done numerous Go ports and having written many Go compiler targets several times, it's much, much simpler to port Go if your target is something that allows static executables and making system calls.
Having done linux/arm64 and solaris/sparc64, I know exactly how much harder is one versus the other.