Skip to content

Instantly share code, notes, and snippets.

@eduncan911
Last active April 11, 2024 07:14
Show Gist options
  • Star 64 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save eduncan911/68775dba9d3c028181e4 to your computer and use it in GitHub Desktop.
Save eduncan911/68775dba9d3c028181e4 to your computer and use it in GitHub Desktop.
Go Cross-Compile Script
#!/bin/bash
#
# GoLang cross-compile snippet for Go 1.6+ based loosely on Dave Chaney's cross-compile script:
# http://dave.cheney.net/2012/09/08/an-introduction-to-cross-compilation-with-go
#
# To use:
#
# $ cd ~/path-to/my-awesome-project
# $ go-build-all
#
# Features:
#
# * Cross-compiles to multiple machine types and architectures.
# * Uses the current directory name as the output name...
# * ...unless you supply an source file: $ go-build-all main.go
# * Windows binaries are named .exe.
# * ARM v5, v6, v7 and v8 (arm64) support
#
# ARM Support:
#
# You must read https://github.com/golang/go/wiki/GoArm for the specifics of running
# Linux/BSD-style kernels and what kernel modules are needed for the target platform.
# While not needed for cross-compilation of this script, you're users will need to ensure
# the correct modules are included.
#
# Requirements:
#
# * GoLang 1.6+ (for mips and ppc), 1.5 for non-mips/ppc.
# * CD to directory of the binary you are compiling. $PWD is used here.
#
# For 1.4 and earlier, see http://dave.cheney.net/2012/09/08/an-introduction-to-cross-compilation-with-go
#
# This PLATFORMS list is refreshed after every major Go release.
# Though more platforms may be supported (freebsd/386), they have been removed
# from the standard ports/downloads and therefore removed from this list.
#
PLATFORMS="darwin/amd64" # amd64 only as of go1.5
PLATFORMS="$PLATFORMS windows/amd64 windows/386" # arm compilation not available for Windows
PLATFORMS="$PLATFORMS linux/amd64 linux/386"
PLATFORMS="$PLATFORMS linux/ppc64 linux/ppc64le"
PLATFORMS="$PLATFORMS linux/mips64 linux/mips64le" # experimental in go1.6
PLATFORMS="$PLATFORMS freebsd/amd64"
PLATFORMS="$PLATFORMS netbsd/amd64" # amd64 only as of go1.6
PLATFORMS="$PLATFORMS openbsd/amd64" # amd64 only as of go1.6
PLATFORMS="$PLATFORMS dragonfly/amd64" # amd64 only as of go1.5
PLATFORMS="$PLATFORMS plan9/amd64 plan9/386" # as of go1.4
PLATFORMS="$PLATFORMS solaris/amd64" # as of go1.3
# ARMBUILDS lists the platforms that are currently supported. From this list
# we generate the following architectures:
#
# ARM64 (aka ARMv8) <- only supported on linux and darwin builds (go1.6)
# ARMv7
# ARMv6
# ARMv5
#
# Some words of caution from the master:
#
# @dfc: you'll have to use gomobile to build for darwin/arm64 [and others]
# @dfc: that target expects that you're bulding for a mobile phone
# @dfc: iphone 5 and below, ARMv7, iphone 3 and below ARMv6, iphone 5s and above arm64
#
PLATFORMS_ARM="linux freebsd netbsd"
##############################################################
# Shouldn't really need to modify anything below this line. #
##############################################################
type setopt >/dev/null 2>&1
SCRIPT_NAME=`basename "$0"`
FAILURES=""
SOURCE_FILE=`echo $@ | sed 's/\.go//'`
CURRENT_DIRECTORY=${PWD##*/}
OUTPUT=${SOURCE_FILE:-$CURRENT_DIRECTORY} # if no src file given, use current dir name
for PLATFORM in $PLATFORMS; do
GOOS=${PLATFORM%/*}
GOARCH=${PLATFORM#*/}
BIN_FILENAME="${OUTPUT}-${GOOS}-${GOARCH}"
if [[ "${GOOS}" == "windows" ]]; then BIN_FILENAME="${BIN_FILENAME}.exe"; fi
CMD="GOOS=${GOOS} GOARCH=${GOARCH} go build -o ${BIN_FILENAME} $@"
echo "${CMD}"
eval $CMD || FAILURES="${FAILURES} ${PLATFORM}"
done
# ARM builds
if [[ $PLATFORMS_ARM == *"linux"* ]]; then
CMD="GOOS=linux GOARCH=arm64 go build -o ${OUTPUT}-linux-arm64 $@"
echo "${CMD}"
eval $CMD || FAILURES="${FAILURES} ${PLATFORM}"
fi
for GOOS in $PLATFORMS_ARM; do
GOARCH="arm"
# build for each ARM version
for GOARM in 7 6 5; do
BIN_FILENAME="${OUTPUT}-${GOOS}-${GOARCH}${GOARM}"
CMD="GOARM=${GOARM} GOOS=${GOOS} GOARCH=${GOARCH} go build -o ${BIN_FILENAME} $@"
echo "${CMD}"
eval "${CMD}" || FAILURES="${FAILURES} ${GOOS}/${GOARCH}${GOARM}"
done
done
# eval errors
if [[ "${FAILURES}" != "" ]]; then
echo ""
echo "${SCRIPT_NAME} failed on: ${FAILURES}"
exit 1
fi
@eduncan911
Copy link
Author

Could you provide some examples as to what "structures" you are using?

@marky7
Copy link

marky7 commented Feb 3, 2020

Awesome code, thank you !

@makew0rld
Copy link

makew0rld commented May 20, 2020

There are now some new targets now, see this table. Specifically there's arm64. Does anyone know where an official updated list of all targets can be found?

@makew0rld
Copy link

I found it, just run: go tool dist list

@eduncan911
Copy link
Author

Nice @makeworld-the-better-one! I knew there were others at the time I wrote this many many years go. Just those edge cases were not needed.

Humm, you know, it's about time I distribute this via more public means.

Let me test out and update to a few more that makes sense, and then I make make a GoLang lib for it with CICD that keeps it updated (I love GitHub Actions these days).

@makew0rld
Copy link

@eduncan911 That'd be awesome, thanks! Just let me know via this thread if you could, once it's ready.

@makew0rld
Copy link

Alright well I just wrote a script that is very similar to yours, but it uses go tool dist list instead, so it never goes out of date. I tested it and it seemed to work fine. https://gist.github.com/makeworld-the-better-one/e1bb127979ae4195f43aaa3ad46b1097

@alessiosavi
Copy link

mkdir build
for f in $(find . -executable -type f | xargs file | grep ELF | awk '{print $1}' | sed 's/://g' | sed 's/\.\///g'); do zip "$f".zip "build/$f"; done

For zip every file in a different zip under the build folder

@phanirithvij
Copy link

phanirithvij commented Jun 11, 2021

@alessiosavi I think this is simpler and works on git bash on windows

IFS=$'\n'
for f in $(ls -1 -v build)
do
    zip "$f".zip "build/$f"
done

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment