Hacker News new | ask | show | jobs
by withinboredom 744 days ago
Go started it. Or at least, popularized the static build, single binary docker files.

Naturally, you’ve been able to do this since forever with many languages like C/C++ etc.

1 comments

Among people that have used nothing besides scripting languages.
To be honest, it was and is pretty rare to see C/C++/etc. self-contained static binaries on Linux. Glibc doesn't even properly support static linking, and musl does not have 1:1 parity with glibc, so it's challenging to even give a "single binary" for C/C++ programs on Linux, less in the past before musl and during musl's infancy. The more popular thing to do on Linux is something more like AppImages where you bundle a bunch of stuff into a single self-executing file, and that ultimately still is a dynamic binary depending on system libraries (and therefore can't be e.g. plopped in an empty Docker container.)

(And yes, Windows and macOS, and probably most of the BSDs, don't really suffer too badly from this issue, since dynamically linking to system libraries/libc is not a problem. Still, not needing libc remains a big advantage for Go since it is possible to cross-compile self-contained Go binaries to any platform Go can target from any other platform; this is challenging to do with C/C++, especially for targets like macOS.)

Even if you do get past the code though, there's the assets. For C/C++, bundling static assets into an executable is oddly challenging. There's been a bunch of different bin2c-type programs over the years, yet somehow not really many "standard" approaches to doing it, and many of them suffer from bad performance (especially approaches that go to a source file instead of an object file). Just now, finally, in the past couple years, there is #embed in C... for embedding a resource file. Meanwhile, Go has had several good options in the ecosystem for embedding entire directory trees and using them inside of VFS layers for ages, and since Go 1.16 (2021) it has support for that as part of the toolchain.

Go didn't invent the concept of making a single self-contained executable, it did however push the status quo quite far. I contend that I have the experience to make this claim.

P.S.: To be clear, I'm definitely not saying you literally can't, and I am aware of Cosmpolitan libc and APE, which are pretty cool. Of course, with effort, you absolutely can make static binaries using C/C++. I just recently did this with a C++ and Rust program using musl; it's tricky, especially since many build setups don't really support these kinds of deviations, but it's possible. One major problem I have with this is that I don't really feel very confident in the stability of the resulting binaries; if something calls dlopen with static musl, it will crash, and behavior of certain things like DNS resolution also changes in ways that may break some programs. The reason why Go's contributions matter is that for basically as long as I can remember, the way to do this in Go is to install the toolchain and run `go build`, any host platform, any target platform, and it's well-supported by virtually everything because it is the default behavior. (And if anything, Zig is closer to bringing this to C than any of the C/C++ toolchains...)

All self inflected problems in the GNU/Linux ecosystem, that don't change the fact the computing world since FORTRAN was introduced as first compiled language in 1957, static compilation was a thing.

Also embedded resources has been a solved problem in most non UNIX platforms for decades.

Self-inflicted or not, this is what Go solved. 1957 FORTRAN binaries don't really detract from what Go did: nobody is claiming Go invented self-contained binaries, we are claiming it solved problems with single-file deployments that other language ecosystems still struggle with, and I stand by this 100%.