Top
Best
New

Posted by khazit 12/7/2025

Go is portable, until it isn't(simpleobservability.com)
153 points | 129 commentspage 2
CGamesPlay 3 days ago|
Use dlopen? I haven’t tried this in Go, but if you want a binary that optionally includes features from an external library, you want to use dlopen to load it.
immibis 3 days ago|
It only works in a dynamically-linked binary, because the dynamic linker needs to be loaded.
CGamesPlay 2 days ago||
That makes sense. Some digging turns up some workarounds; the best I found was https://github.com/jart/cosmopolitan/releases/tag/3.1
immibis 5 hours ago||
You can write your own dynamic loader, or port the one from libc, or attempt to statically link it (against its wishes). Nothing stops you opening a .so file and mmapping the appropriate sections - that's what the dynamic loader does, and it's just normal user-space code, after all. However, the libc dynamic loader definitely prefers to be your program's entry point. You're swimming against the current by doing it any other way.
kccqzy 4 days ago||
Interesting that it uses the C API to collect journals. I would’ve thought to just invoke journalctl CLI. On platforms like macOS where the CLI doesn’t exist it’s an error when you exec, not a build time error.
ajross 4 days ago||
That's really not such a weird choice. The systemd library is pervasive and compatible.

The weird bit is the analysis[1], which complains that a Go binary doesn't run on Alpine Linux, a system which is explicitly and intentionally (also IMHO ridiculously, but that's editorializing) binary-incompatible with the stable Linux C ABI as it's existed for almost three decades now. It's really no more "Linux" than is Android, for the same reason, and you don't complain that your Go binaries don't run there.

[1] I'll just skip without explaination how weird it was to see the author complain that the build breaks because they can't get systemd log output on... a mac.

khazit 3 days ago||
The macOS bit wasn’t about trying to get systemd logs on mac. The issue was that the build itself fails because libsystemd-dev isn’t available. We (naively) expected journal support to be something that we can detect and handle at runtime.
ajross 3 days ago||
Well... yeah. It's a Linux API for a Linux feature only available on Linux systems. If you use a platform-specific API on a multiplatform project, the portability work falls on you. Do you expect to be able to run your Swift UI on Windows? Same thing!
LtWorf 3 days ago|||
I did this a while ago but it only reads journal files sequentially and I didn't implement the needed stuff to use the indexes.

https://github.com/appgate/journaldreader

amiga386 3 days ago||
That's also what gopsutils does, IIRC: it tries to look up process information with kernel APIs but can fall back to invoking /usr/bin/ps (which is setuid root on most systems) at the cost of being much less performant.
hollow-moe 3 days ago||
Hashicorp's Vault go binary is a whopping 512Mb beast. Recently considered using its agent mode to grab secrets for applications in containers but the size of the layer it adds is unviably big. And they don't seem interested into making a split server/client binary either...
Rucadi 3 days ago||
If you really need a portable binary that uses shared libraries I would recommend building it with nix, you get all the dependencies including dynamic linker and glibc.
ghola2k5 4 days ago||
I’ve had some success using Zig for cross compiling when CGO is required.
dilyevsky 3 days ago||
There's still some bugs when interacting with gold and cross-compiling to linux/arm64 but fixable with some workarounds...
hansvm 4 days ago||
That's Uber's approach, right?
sgt 3 days ago||
Is Uber using Zig for other things by now?
hansvm 3 days ago||
I haven't heard.
arianvanp 3 days ago||
FWIW I maintain an official implementation of the journal wire format in go now.

https://github.com/systemd/slog-journal so you can at least log to the journal now without CGO

But that's just the journal Wire format which is a lot simpler than the disk format.

I think a journal disk format parser in go would be a neat addition

mbrock 3 days ago|
I've got a pure Go journald file writer that works to some extent—it doesn't split, compress, etc, but it produces journal files that journalctl/sdjournal can read, concurrently. Only stress tested by running a bunch of parallel integration tests, will most likely not maintain it seriously, total newbie garbage, etc, but may be of interest to someone. I haven't really seen any other working journald file writers.

https://github.com/lessrest/swash/tree/main/pkg/journalfile

ksajadi 3 days ago||
I tink the title is a bit misleading. This is about very low level metrics collection from the system which by definition is very system dependent. The term “portable” in a programming language usually means portability for applications but this more portability of utilities.

Expecting a portable house and a portable speaker to have the same definition of portable is unfair.

necovek 12/7/2025||
This seems to imply that Go's binaries are otherwise compatible with multiple platforms like amd64 and arm64, other than the issue with linking dynamic libraries.

I suspect that's not true either even if it might be technically possible to achieve it through some trickery (and why not risc-v, and other architectures too?).

khazit 12/7/2025||
Of course you still need one binary per CPU architecture. But when you rely on a dynamic link, you need to build from the same architecture as the target system. At that point cross-compiling stops being reliable.
necovek 12/8/2025|||
I am complaining about the language (phrasing) used: a Python, TypeScript or Java program might be truly portable across architectures too.

Since architectures are only brought up in relation to dynamic libraries, it implied it is otherwise as portable as above languages.

With that out of the way, it seems like a small thing for the Go build system if it's already doing cross compilation (and thus has understanding of foreign architectures and executable formats). I am guessing it just hasn't been done and is not a big lift, so perhaps look into it yourself?

arccy 4 days ago||
they're only portable if you don't count the architecture specific runtime that you need to somehow obtain...

go doesn't require dynamic linking for C, if you can figure out the right C compiler flags you can cross compile statically linked go+c binaries as well.

vbezhenar 4 days ago||||
Is it some tooling issue? Why is is an issue to cross-compile programs with dynamic linking?
cxr 4 days ago|||
It's a tooling issue. No one has done the work to make things work as smoothly as they could.

Traditionally, cross-compilers generally didn't even work the way that the Zig and Go toolchains approach it—achieving cross-compilation could be expected to be a much more trying process. The Zig folks and the Go folks broke with tradition by choosing to architect their compilers more sensibly for the 21st century, but the effects of the older convention remains.

dekhn 4 days ago|||
In general, cross compilers can do dynamic linking.
spijdar 4 days ago||
In my experience, the cross-compiler will refuse to link against shared libraries that "don't exist", which they usually don't in a cross compiler setup (e.g. cross compiling an aarch64 application that uses SDL on a ppc64le host with ppc64le SDL libraries)

The usual workaround, I think, is to use dlopen/dlsym from within the program. This is how the Nim language handles libraries in the general case: at compile time, C imports are converted into a block of dlopen/dl* calls, with compiler options for indicating some (or all) libraries should be passed to the linker instead, either for static or dynamic linking.

Alternatively I think you could "trick" the linker with a stub library just containing the symbol names it wants, but never tried that.

dwattttt 3 days ago|||
You just need a compiler & linker that understand the target + image format, and a sysroot for the target. I've cross compiled from Linux x86 clang/lld to macOS arm64, all it took was the target SDK & a couple of env vars.

Clang knows C, lld knows macho, and the SDK knows the target libraries.

1718627440 2 days ago|||
Well, you need to link against them and you can't do that when they don't exist. I don't understand the purpose of a stub library, it is also only a file and if you need to provide that, you can also provide the real thing right away.
swills 4 days ago|||
I happily and reliably cross build Go code that uses CGO and generate static binaries on amd64 for arm64.
cxr 3 days ago|||
For a single binary that will actually run across both architectures, see <https://cosmo.zip/>.

Original discussion: <https://news.ycombinator.com/item?id=24256883>.

t43562 3 days ago||
Systemd. Binary logs are wonderful aren't they?
LtWorf 3 days ago|
It's not that hard to read them without linking their library. The format is explained on their documentation.

https://github.com/appgate/journaldreader

nasretdinov 3 days ago|
Go was never truly portable on Linux unfortunately due to its dependency on libc for DNS and user name resolution (because of PAM and other C-only API). Sure, pure Go implementation exists, but it doesn't cover all cases, so, in order to build a "good" binary for Linux you still needed to build the binary on (oldest supported) Linux distro.

If your production doesn't have any weird PAM or DNS then you can indeed just cross-compile everything and it works

More comments...