Go down a rabbit hole of trying to statically compile on linux

main
Sean Hickey 2022-09-30 01:30:25 -07:00
parent b2d3111d7c
commit 56ba80c935
8 changed files with 153 additions and 33 deletions

14
Dockerfile Normal file
View File

@ -0,0 +1,14 @@
FROM alpine:latest
RUN apk add --no-cache \
gcc musl-dev make go \
alsa-lib libxrandr \
sdl2-dev sdl2_mixer-dev sdl2_image-dev sdl2_ttf-dev
WORKDIR /home
COPY . .
#RUN make release_static
#COPY ./project-ely ./project-ely-static

View File

@ -1,42 +1,52 @@
EXECUTABLE=project-ely
GO=go
MINGW64=x86_64-w64-mingw32-gcc
MINGW32=i686-w64-mingw32-gcc
MUSL_GCC="${HOME}/musl/bin/musl-gcc -static"
GO_BUILD=build -x -v
GO_BUILD_DEBUG=${GO_BUILD} -gcflags=all="-N -l"
GO_BUILD_RELEASE=${GO_BUILD} -trimpath -tags static -ldflags "-s -w"
GO_BUILD_RELEASE_WINDOWS=${GO_BUILD} -trimpath -tags static -ldflags "-s -w -H windowsgui"
GO_BUILD_RELEASE=${GO_BUILD} -trimpath -ldflags '-s -w'
GO_BUILD_RELEASE_STATIC=${GO_BUILD} -trimpath -ldflags '-s -w -linkmode external -extldflags "-static"'
all: release
dependencies:
${GO} mod tidy
debug: linter dependencies
prebuild: dependencies
debug: prebuild
${GO} ${GO_BUILD_DEBUG}
release: linter dependencies
release: prebuild
${GO} ${GO_BUILD_RELEASE}
# release_static only works on Alpine, see the Dockerfile
release_static: prebuild
CGO_ENABLED=1 \
CGO_LDFLAGS="-Wl,-rpath -L${HOME}/pkg/lib -L/usr/lib -L/usr/lib/x86_64-linux-gnu" \
${GO} ${GO_BUILD_RELEASE_STATIC}
linter:
golangci-lint run
clean:
rm -f ${EXECUTABLE}
rm -f ${EXECUTABLE}-*
rm -f output.log
rm -f cpu.prof
cross_windows:
CGO_ENABLED=1 \
CC=x86_64-w64-mingw32-gcc \
GOOS=windows \
GOARCH=amd64 \
${GO} ${GO_BUILD_RELEASE}
CC=${MINGW64} \
NAME=${EXECUTABLE} \
./scripts/build-windows-amd64.sh
cross_windows_x86:
CGO_ENABLED=1 \
CC=i686-w64-mingw32-gcc \
GOOS=windows \
GOARCH=386 \
${GO} ${GO_BUILD_RELEASE}
CC=${MINGW32} \
NAME=${EXECUTABLE} \
./scripts/build-windows-386.sh
goimports_everything:
find . -name "*.go" -exec goimports -w {} \;

View File

@ -0,0 +1,51 @@
# Linux Static Release Build
Because we're depending on SDL and X11 libraries, we can't easily
build a completely statically-linked binary using musl unless we
recompile those library dependencies also using musl. I was able to
build something that was mostly statically-linked except for libc, but
then it didn't run in a base Fedora Docker container.
The workaround for this is to use something where everything is
already compiled with musl, like an Alpine Linux Docker container.
To build a fully statically-linked binary, use the `Dockerfile` in the
root directory.
```sh
docker build -t project-ely-build .
```
This should spit out an executable called `project-ely-static`.
## Attempts on Debian
I tried installing musl on Debian.
I installed it to my home directory. I also specified my pkgsrc version of GCC.
```sh
CC=$HOME/pkg/gcc10/bin/gcc
./configure --disabled-shared --prefix=$HOME/musl
make -j4
make install
```
Then I had to symlink the X11 include dir.
```sh
cd musl-install/include
ln -s /usr/include/X11 X11
```
I ran into an issue where it was unable to find many basic libraries
like Xrandr and asound. But then I hit that same issue with the Alpine
container =(
## References
Before giving up and using Alpine, I found these cool links that
suggest you could do this more easily if we only depended on the C std
library stuff, no external dependencies like X11 and SDL.
* https://honnef.co/posts/2015/06/statically_compiled_go_programs__always__even_with_cgo__using_musl/
* https://github.com/golang/go/issues/26492

View File

@ -0,0 +1,16 @@
# Windows Static Release Build
You can build a statically-linked binary on Windows that should run
without requiring the SDL `*.dll` files.
```sh
go build -x -v -trimpath -tags static -ldflags "-s -w -H windowsgui"
```
There is a script called [build-windows-static.sh][1] in the scripts
folder to make this easy from Git Bash.
The Makefile supports cross-compiling for this from Linux with the
`cross_windows` target.
[1]: scripts/build-windows-static.sh

View File

@ -0,0 +1,5 @@
#!/usr/bin/env sh
. common-build-windows.sh
build windows 386

View File

@ -0,0 +1,5 @@
#!/usr/bin/env sh
. common-release-build.sh
build windows amd64

View File

@ -1,19 +0,0 @@
#!/usr/bin/env sh
# This is intended to run in Git Bash on Windows.
# This builds a statically-linked release version of the binary ready to be deployed.
OUTPUT=project-ely
build(){
OS=$1
ARCH=$2
CGO_ENABLED=1 \
CC=gcc \
GOOS=$OS \
GOARCH=$ARCH \
go build -x -v -trimpath -tags static -ldflags="-s -w -H windowsgui" -o "${OUTPUT}-${OS}-${ARCH}.exe"
}
build windows amd64

View File

@ -0,0 +1,38 @@
# This is a generalized function to build a statically-linked release binary.
# It specifies all the Go flags needed to make that happen depending on the platform.
build(){
OS=$1
ARCH=$2
if [ -z $NAME ]
then
NAME=output
fi
if [ -z "${CC}" ]
then
export CC=gcc
fi
LDFLAGS_WIN=""
EXE=""
if [ "${OS}" == "windows" ]
then
# Hide the windows console popup for SDL
LDFLAGS_WIN="-H windowsgui"
EXE=".exe"
fi
OUTPUT="${NAME}-${OS}-${ARCH}${EXE}"
export CGO_ENABLED=1
export CC="${CC}"
export GOOS=$OS
export GOARCH=$ARCH
go build -x -v \
-trimpath \
-tags static \
-ldflags="-s -w ${LDFLAGS_WIN}" \
-o "${OUTPUT}"
}