394 lines
8.6 KiB
Bash
Executable file
394 lines
8.6 KiB
Bash
Executable file
#! /usr/bin/env bash
|
|
|
|
# Tool to build go programs in this repo
|
|
#
|
|
# - it tacks on a version number for use by the individual tools
|
|
# - it supports git and mercurial version#
|
|
#
|
|
# NB:
|
|
# o the attempt at decoding dirty repo state for mercurial is
|
|
# borked. It doesn't know about untracked files
|
|
#
|
|
# (c) 2016 Sudhi Herle
|
|
#
|
|
# License: GPLv2
|
|
#
|
|
Progs=".:sigtool"
|
|
|
|
# Relative path to protobuf sources
|
|
# e.g. src/foo/a.proto
|
|
Protobufs="internal/pb/hdr.proto"
|
|
|
|
|
|
# -- DO NOT CHANGE ANYTHING AFTER THIS --
|
|
|
|
Z=`basename $0`
|
|
PWD=`pwd`
|
|
|
|
Static=0
|
|
Dryrun=0
|
|
Prodver=""
|
|
Verbose=0
|
|
|
|
hostos=$(go env GOHOSTOS) || exit 1
|
|
hostcpu=$(go env GOHOSTARCH) || exit 1
|
|
|
|
die() {
|
|
echo "$Z: $@" 1>&2
|
|
exit 0
|
|
}
|
|
|
|
warn() {
|
|
echo "$Z: $@" 1>&2
|
|
}
|
|
|
|
case $BASH_VERSION in
|
|
4.*|5.*) ;;
|
|
|
|
*) die "I need bash 4.x to run!"
|
|
;;
|
|
esac
|
|
|
|
|
|
# build a tool that runs on the host - if needed.
|
|
hosttool() {
|
|
local tool=$1
|
|
local bindir=$2
|
|
local src=$3
|
|
|
|
local p=$(type -P $tool)
|
|
if [ -n "$p" ]; then
|
|
echo $p
|
|
return 0
|
|
fi
|
|
|
|
# from here - we want this dir to find all build artifacts
|
|
PATH=$PATH:$bindir
|
|
export PATH
|
|
|
|
p=$bindir/$tool
|
|
if [ -x $p ]; then
|
|
echo $p
|
|
return 0
|
|
fi
|
|
|
|
# build it and stash it in the hostdir
|
|
echo "Building tool $tool from $src .."
|
|
$e go get -d $src || exit 1
|
|
$e go build -o $p $src || exit 1
|
|
echo $p
|
|
return 0
|
|
}
|
|
|
|
|
|
usage() {
|
|
|
|
cat <<EOF
|
|
$0 - A Go production build tool that adds git-repository information,
|
|
product version, build-timestamp etc. It supports cross-compilation,
|
|
static linking and generating protobuf output.
|
|
|
|
If needed, it uses the gogo-slick protobuf compiler [github.com/gogo/protobuf].
|
|
|
|
Build output is in bin/\$OS-\$CPU for a given OS, CPU combination.
|
|
|
|
Usage: $0
|
|
$0 [options] [PROGS]
|
|
|
|
Where OS-ARCH denotes one of the valid OS, ARCH combinations supported by 'go'.
|
|
And, PROGS is one or more go programs.
|
|
|
|
With no arguments, $0 builds: $Progs (source in ./src/)
|
|
|
|
The repository's latest tag is used as the default version of the software being
|
|
built.
|
|
|
|
Options:
|
|
-h, --help Show this help message and quit
|
|
-s, --static Build a statically linked binary [False]
|
|
-V N, --version=N Use 'N' as the product version string [$Prodver]
|
|
-a X, --arch=X Cross compile for OS-CPU 'X' [$hostos-$hostcpu]
|
|
-n, --dry-run Dry-run, don't actually build anything [False]
|
|
-t, --test Run "go test" on modules named on the command line [False]
|
|
-v, --verbose Build verbosely (adds "-v" to go tooling) [False]
|
|
--vet Run "go vet" on modules named on the command line [False]
|
|
-x Run in debug/trace mode [False]
|
|
--print-arch Print the target architecture and exit
|
|
EOF
|
|
|
|
exit 0
|
|
}
|
|
|
|
host=`uname|tr '[A-Z]' '[a-z]'`
|
|
export GO15VENDOREXPERIMENT=1
|
|
|
|
declare -A oses
|
|
declare -A cpus
|
|
declare -A cgo
|
|
|
|
# Supported & Verified OS/CPU combos for this script
|
|
oslist="linux android openbsd freebsd darwin dragonfly netbsd windows"
|
|
needcgo="android"
|
|
cpulist="i386 amd64 arm arm64"
|
|
cpualias_i386="i486 i586 i686"
|
|
cpualias_amd64="x86_64"
|
|
cpualias_arm64="aarch64"
|
|
|
|
# CGO Cross-Compilers for various CPU+OS combinations of Android
|
|
android_i386=i686-linux-android-gcc
|
|
android_arm64=aarch64-linux-android-gcc
|
|
android_arm=arm-linux-androideabi-gcc
|
|
|
|
# initialize the various hash tables
|
|
for o in $oslist; do oses[$o]=$o; done
|
|
for o in $needcgo; do cgo[$o]=$o; done
|
|
for c in $cpulist; do
|
|
cpus[$c]=$c
|
|
a="cpualias_$c"
|
|
a=${!a}
|
|
for x in $a; do cpus[$x]=$c; done
|
|
done
|
|
|
|
|
|
Tool=
|
|
doinit=0
|
|
args=
|
|
Printarch=0
|
|
|
|
#set -x
|
|
ac_prev=
|
|
for ac_option
|
|
do
|
|
shift
|
|
|
|
if [ -n "$ac_prev" ]; then
|
|
eval "$ac_prev=\$ac_option"
|
|
ac_prev=
|
|
continue
|
|
fi
|
|
|
|
case "$ac_option" in
|
|
-*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
|
|
*) ac_optarg= ;;
|
|
esac
|
|
|
|
|
|
case "$ac_option" in
|
|
--help|-h|--hel|--he|--h)
|
|
usage;
|
|
;;
|
|
|
|
--arch=*)
|
|
Arch=$ac_optarg
|
|
;;
|
|
-a|--arch)
|
|
ac_prev=Arch
|
|
;;
|
|
|
|
--version=*)
|
|
Prodver=$ac_optarg
|
|
;;
|
|
--test|-t)
|
|
Tool=test
|
|
;;
|
|
|
|
--vet)
|
|
Tool=vet
|
|
;;
|
|
|
|
-V|--version)
|
|
ac_prev=Prodver
|
|
;;
|
|
-v|--verbose)
|
|
Verbose=1
|
|
;;
|
|
|
|
-s|--static)
|
|
Static=1
|
|
;;
|
|
|
|
--dry-run|-n)
|
|
Dryrun=1
|
|
;;
|
|
|
|
--debug|-x)
|
|
set -x
|
|
;;
|
|
|
|
--print-arch)
|
|
Printarch=1
|
|
;;
|
|
|
|
*) # first non option terminates option processing.
|
|
# we gather all remaining args and bundle them up.
|
|
args="$args $ac_option"
|
|
for xx
|
|
do
|
|
args="$args $xx"
|
|
done
|
|
break
|
|
;;
|
|
esac
|
|
done
|
|
[ $Dryrun -gt 0 ] && e=echo
|
|
|
|
# let every error abort
|
|
set -e
|
|
|
|
# This fragment can't be in a function - since it exports several vars
|
|
if [ -n "$Arch" ]; then
|
|
ox=${Arch%%-*}
|
|
cx=${Arch##*-}
|
|
[ "$ox" = "$cx" ] && cx=$hostcpu
|
|
|
|
os=${oses[$ox]}
|
|
cpu=${cpus[$cx]}
|
|
[ -z "$os" ] && die "Don't know anything about OS $ox"
|
|
[ -z "$cpu" ] && die "Don't know anything about CPU $cx"
|
|
|
|
export GOOS=$os GOARCH=$cpu
|
|
cross=$os-$cpu
|
|
|
|
else
|
|
os=$hostos
|
|
cpu=$hostcpu
|
|
cross=$os-$cpu
|
|
fi
|
|
|
|
# If we don't need CGO, then we can attempt a static link
|
|
if [ -n "${cgo[$os]}" ]; then
|
|
export CGO_ENABLED=1
|
|
|
|
# See if we have a specific cross-compiler for this CPU+OS combo
|
|
xcc="${GOOS}_${GOARCH}"
|
|
xcc=${!xcc}
|
|
if [ -n "$xcc" ]; then
|
|
p=`type -p $xcc`
|
|
[ -n "$p" ] || die "Can't find $xcc! Do you have compilers for $GOARCH available in PATH?"
|
|
export CC=$xcc
|
|
else
|
|
echo "$Z: No Cross compiler defined for $GOOS-$GOARCH. Build may fail.." 1>&2
|
|
fi
|
|
else
|
|
if [ $Static -gt 0 ]; then
|
|
export CGO_ENABLED=0
|
|
|
|
isuffix="--installsuffix cgo"
|
|
ldflags="-s"
|
|
msg="statically linked"
|
|
fi
|
|
fi
|
|
|
|
if [ $Printarch -gt 0 ]; then
|
|
echo "$hostos-$hostcpu"
|
|
exit 0
|
|
fi
|
|
|
|
|
|
# This is where build outputs go
|
|
Bindir=$PWD/bin/$cross
|
|
Hostbindir=$PWD/bin/$hostos-$hostcpu
|
|
|
|
[ -d $Bindir ] || mkdir -p $Bindir
|
|
[ -d $Hostbindir ] || mkdir -p $Hostbindir
|
|
|
|
# Get git/hg version info for the build
|
|
if [ -d "./.hg" ]; then
|
|
xrev=$(hg id --id) || exit 1
|
|
brev=${xrev%+}
|
|
if [ "$brev" != "$xrev" ]; then
|
|
rev="hg:${brev}-dirty"
|
|
else
|
|
rev="hg:${brev}"
|
|
fi
|
|
if [ -z "$Prodver" ]; then
|
|
Prodver=$(hg log -r "branch(stable) and tag()" -T "{tags}\n" | tail -1)
|
|
fi
|
|
elif [ -d "./.git" ]; then
|
|
xrev=$(git describe --always --dirty --long --abbrev=12) || exit 1
|
|
rev="git:$xrev"
|
|
if [ -z "$Prodver" ]; then
|
|
Prodver=$(git tag --list | tail -1)
|
|
fi
|
|
else
|
|
rev="UNKNOWN-VER"
|
|
echo "$0: Can't find version info" 1>&2
|
|
fi
|
|
|
|
|
|
# Do Protobufs if needed
|
|
if [ -n "$Protobufs" ]; then
|
|
set +e
|
|
slick=$Hostbindir/protoc-gen-gogoslick
|
|
slicksrc=github.com/gogo/protobuf/protoc-gen-gogoslick
|
|
for pc in protoc protoc-c; do
|
|
pc=`which $pc`
|
|
[ -n "$pc" ] && break
|
|
done
|
|
|
|
[ -z "$pc" ] && die "Need 'protoc' for building .."
|
|
|
|
slick=$(hosttool protoc-gen-gogoslick $Hostbindir $slicksrc) || exit 1
|
|
#if [ ! -f $slick ]; then
|
|
# echo "Building $slick .."
|
|
# $e go build -o $slick github.com/gogo/protobuf/protoc-gen-gogoslick || exit 1
|
|
#i
|
|
|
|
export PATH=$PATH:$Hostbindir
|
|
|
|
for f in $Protobufs; do
|
|
dn=$(dirname $f)
|
|
bn=$(basename $f .proto)
|
|
of=$dn/${bn}.pb.go
|
|
if [ $f -nt $of ]; then
|
|
echo "Running $pc .."
|
|
$e $pc --gogoslick_out=. $f || exit 1
|
|
fi
|
|
done
|
|
set -e
|
|
fi
|
|
|
|
repover="main.RepoVersion=$rev"
|
|
prodver="main.ProductVersion=$Prodver"
|
|
date="main.Buildtime=`date -u '+%Y-%m-%dT%H:%M.%SZ'`"
|
|
ldflags="-ldflags \"-X $repover -X $prodver -X $date $ldflags\""
|
|
vflag=""
|
|
|
|
[ $Verbose -gt 0 ] && vflag="-v"
|
|
|
|
case $Tool in
|
|
test)
|
|
set -- $args
|
|
$e go test $vflag "$@"
|
|
;;
|
|
|
|
vet)
|
|
set -- $args
|
|
$e go vet $vflag "$@"
|
|
;;
|
|
|
|
*) # Default is to build programs
|
|
set -- $args
|
|
if [ -z "$1" ]; then
|
|
all=$Progs
|
|
else
|
|
all="$@"
|
|
fi
|
|
|
|
echo "Building $Prodver ($rev), $cross $msg .."
|
|
|
|
for p in $all; do
|
|
if echo $p | grep -q ':' ; then
|
|
out=${p##*:}
|
|
dir=${p%%:*}
|
|
else
|
|
out=$p
|
|
dir=$p
|
|
fi
|
|
echo " $dir: $out .. "
|
|
$e eval go build $vflag -o $Bindir/$out $isuffix "$ldflags" ./$dir || exit 1
|
|
done
|
|
;;
|
|
esac
|
|
|
|
# vim: ft=sh:expandtab:ts=4:sw=4:tw=84:
|