Live data from Hacker News

Go is portable, until it isn't

simpleobservability.com

61–70 of 138 posts

Re: Go is portable, until it isn't

#61
I think this is true for nearly all compiled languages. I had the same fun with rust and openSSL and glibC. OP didn’t mentioned the fun with glib-c when compiling on a fairly recent distro and trying it to run on an older one. There is the “many Linux” project which provides docker images with a minimum glib c version installed so it’s compatible with newer ones. The switch to a newer open ssl version on Debian/Ubuntu created some issues for my tool. I replaced it with rust tls to remove the dynamic linked library. I prefer complete statically linked binaries though. But that is really hard to do and damn near impossible on Apple systems.

Re: Go is portable, until it isn't

#63

Once you use CGO, portability is gone. Your binary is no longer staticly compiled. This can happen subtley without you knowing it. If you use a function in the standard library that happens to call into a CGO function, you are no longer static. This happens with things like os.UserHomeDir or some networking things like DNS lookups. You can "force" go to do static compiling by disabling CGO, but that means you can't u…

> Which may not work if you require it for certain things like sqlite. there is cgo-less sqlite implementation https://github.com/glebarez/go-sqlite it seems to not be maintained much tho

You're linking to a different version - this is the one that most people use https://github.com/modernc-org/sqlite

Re: Go is portable, until it isn't

#65

Earlier quoted context omitted.

> Which may not work if you require it for certain things like sqlite. there is cgo-less sqlite implementation https://github.com/glebarez/go-sqlite it seems to not be maintained much tho

You're linking to a different version - this is the one that most people use https://github.com/modernc-org/sqlite

Yes and no, the package above is a popular `database/sql` driver for the same SQLite port you linked.

Re: Go is portable, until it isn't

#66
post #9

I ran into this issue when porting term.everything[0] from typescript to go. I had some c library dependencies that I did need to link, so I had to use cgo. My solution was to do the build process on alpine linux[1] and use static linking[2]. This way it statically links musl libc, which is much friendlier with static linking than glibc. Now, I have a static binary that runs in alpine, Debian, and even bare container…

That is a nice approach. I'll have to give that a try with rclone. I tried lots of things in the past but not using Alpine which is a great idea

Another alternative is

https://github.com/ebitengine/purego

You can use this to dynamic load shared objects / DLLs so in the OP example they could disable systemd support if the systemd shared object did not load.

This technique is used in the cgofuse library ( https://github.com/winfsp/cgofuse ) rclone uses which means rclone can run even if you don't have libfuse/winfsp installed. However the rclone mount subcommand won't work.

The purego lib generalizes this idea. I haven't got round to trying this yet but it looks very promising.

Re: Go is portable, until it isn't

#67
post #28
post #15

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.

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…

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.

Re: Go is portable, until it isn't

#68
post #9

I ran into this issue when porting term.everything[0] from typescript to go. I had some c library dependencies that I did need to link, so I had to use cgo. My solution was to do the build process on alpine linux[1] and use static linking[2]. This way it statically links musl libc, which is much friendlier with static linking than glibc. Now, I have a static binary that runs in alpine, Debian, and even bare container…

> and even bare containers.

Strange, i thought the whole point of containers was to solve this problem.

Re: Go is portable, until it isn't

#70
post #9

I ran into this issue when porting term.everything[0] from typescript to go. I had some c library dependencies that I did need to link, so I had to use cgo. My solution was to do the build process on alpine linux[1] and use static linking[2]. This way it statically links musl libc, which is much friendlier with static linking than glibc. Now, I have a static binary that runs in alpine, Debian, and even bare container…

I use `-ldflags '-extldflags "-static"` as well.

From the .go file, you just do `// #cgo LDFLAGS: -L. -lfoo`.

You definitely do not need Alpine Linux for this. I have done this on Arch Linux. I believe I did not even need musl libc for this, but I potentially could have used it.

I did not think I was doing something revolutionary!

In fact, let me show you a snippet of my build script:

  # Build the Go project with the static library
  if go build -o $PROG_NAME -ldflags '-extldflags "-static"'; then
    echo "Go project built with static library linkage"
  else
    echo "Error: Failed to build the Go project with static library"
    exit 1
  fi

  # Check if the executable is statically linked
  if nm ./$PROG_NAME | grep -q "U "; then
    echo "Error: The generated executable is dynamically linked"
    exit 1
  else
    echo "Successfully built and verified static executable '$PROG_NAME'"
  fi
And like I said, the .go file in question has this:

  // #cgo LDFLAGS: -L. -lfoo
It works perfectly, and should work on any Linux distribution.
Post reply on HN