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 containers.
Since I have made the change, I have not had anyone open any issues saying they had problems running it on their machines. (Unlike when I was using AppImages, which caused much more trouble than I expected)
[0] https://github.com/mmulet/term.everything look at distribute.sh and the makefile to see how I did it.
[1]in a podman or docker container
[2] -ldflags '-extldflags "-static"'
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.
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.> do the build process on alpine linux and […] statically link musl libc
IIRC it used to be common to do builds on an old version of RHEL or CentOS and dynamically link an old version of glibc. Binaries would then work on newer systems because glibc is backwards compatible.
Does anyone still use that approach?
Note that you don't have to compile on an Alpine system to achieve this. These instructions should work on most distros:
> and even bare containers.
Strange, i thought the whole point of containers was to solve this problem.
Huh. Does term.everything just work, or are there some gotchas? This seems like it could be supremely useful!
I didn't see an explanation in the README that part of what the first GIF[1] shows is an effect created by video editing software (and not a screencapture that's just demonstrating the program actually running). "Screen images simulated" are the words usually chosen to start off the disclaimers in fine print shown at the bottom of the screen when similar effects appear in commercials. I think that it would make sense to adopt a similar explanation wrt the effect used for the GIF.
1. <https://github.com/mmulet/term.everything/blob/main/resource...>
IMO this is the best approach, but it is worth noting that musl libc is not without its caveats. I'd say for most people it is best to tread carefully and make sure that differences between musl libc and glibc don't cause additional problems for the libraries you are linking to.
There is a decent list of known functional differences on the musl libc wiki:
https://wiki.musl-libc.org/functional-differences-from-glibc...
Overall, though, the vast majority of software works perfectly or near perfectly on musl libc, and that makes this a very compelling option indeed, especially since statically linking glibc is not supported and basically does not work. (And obviously, if you're already using library packages that are packaged for Alpine Linux in the first place, they will likely already have been tested on musl libc, and possibly even patched for better compatibility.)