Go down a rabbit hole of trying to statically compile on linux
parent
b2d3111d7c
commit
56ba80c935
|
@ -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
|
38
Makefile
38
Makefile
|
@ -1,42 +1,52 @@
|
||||||
EXECUTABLE=project-ely
|
EXECUTABLE=project-ely
|
||||||
|
|
||||||
GO=go
|
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=build -x -v
|
||||||
GO_BUILD_DEBUG=${GO_BUILD} -gcflags=all="-N -l"
|
GO_BUILD_DEBUG=${GO_BUILD} -gcflags=all="-N -l"
|
||||||
GO_BUILD_RELEASE=${GO_BUILD} -trimpath -tags static -ldflags "-s -w"
|
GO_BUILD_RELEASE=${GO_BUILD} -trimpath -ldflags '-s -w'
|
||||||
GO_BUILD_RELEASE_WINDOWS=${GO_BUILD} -trimpath -tags static -ldflags "-s -w -H windowsgui"
|
GO_BUILD_RELEASE_STATIC=${GO_BUILD} -trimpath -ldflags '-s -w -linkmode external -extldflags "-static"'
|
||||||
|
|
||||||
all: release
|
all: release
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
${GO} mod tidy
|
${GO} mod tidy
|
||||||
|
|
||||||
debug: linter dependencies
|
prebuild: dependencies
|
||||||
|
|
||||||
|
debug: prebuild
|
||||||
${GO} ${GO_BUILD_DEBUG}
|
${GO} ${GO_BUILD_DEBUG}
|
||||||
|
|
||||||
release: linter dependencies
|
release: prebuild
|
||||||
${GO} ${GO_BUILD_RELEASE}
|
${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:
|
linter:
|
||||||
golangci-lint run
|
golangci-lint run
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f ${EXECUTABLE}
|
rm -f ${EXECUTABLE}
|
||||||
|
rm -f ${EXECUTABLE}-*
|
||||||
rm -f output.log
|
rm -f output.log
|
||||||
rm -f cpu.prof
|
rm -f cpu.prof
|
||||||
|
|
||||||
cross_windows:
|
cross_windows:
|
||||||
CGO_ENABLED=1 \
|
CC=${MINGW64} \
|
||||||
CC=x86_64-w64-mingw32-gcc \
|
NAME=${EXECUTABLE} \
|
||||||
GOOS=windows \
|
./scripts/build-windows-amd64.sh
|
||||||
GOARCH=amd64 \
|
|
||||||
${GO} ${GO_BUILD_RELEASE}
|
|
||||||
|
|
||||||
cross_windows_x86:
|
cross_windows_x86:
|
||||||
CGO_ENABLED=1 \
|
CC=${MINGW32} \
|
||||||
CC=i686-w64-mingw32-gcc \
|
NAME=${EXECUTABLE} \
|
||||||
GOOS=windows \
|
./scripts/build-windows-386.sh
|
||||||
GOARCH=386 \
|
|
||||||
${GO} ${GO_BUILD_RELEASE}
|
|
||||||
|
|
||||||
goimports_everything:
|
goimports_everything:
|
||||||
find . -name "*.go" -exec goimports -w {} \;
|
find . -name "*.go" -exec goimports -w {} \;
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,5 @@
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
. common-build-windows.sh
|
||||||
|
|
||||||
|
build windows 386
|
|
@ -0,0 +1,5 @@
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
. common-release-build.sh
|
||||||
|
|
||||||
|
build windows amd64
|
|
@ -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
|
|
|
@ -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}"
|
||||||
|
}
|
Loading…
Reference in New Issue