sigtool/build
Sudhi Herle eae20abd24 Updated to vtproto inlieu of gogo-slick; verified that protobuf enc/dec
are same across both.

* updated 'build' to use new vtproto toolchain;
* updated go.mod to use vtproto
2023-11-23 21:06:30 -08:00

425 lines
9.2 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
Go=`which go`
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
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]
--mod Run "go mod ..." [False]
--go=G Use Go in 'G' [$Go]
-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]'`
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
;;
--mod)
Tool=mod
;;
-V|--version)
ac_prev=Prodver
;;
-v|--verbose)
Verbose=1
;;
-s|--static)
Static=1
;;
--dry-run|-n)
Dryrun=1
;;
--debug|-x)
set -x
;;
--go-root=*)
GoRoot=$ac_optarg
;;
--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
# build a tool that runs on the host - if needed.
hosttool() {
local tool=$1
local bindir=$2
local src=$3
p=$bindir/$tool
if [ -x $p ]; then
return 0
fi
local tmpdir=/tmp/$tool.$$
mkdir $tmpdir || die "can't make $tmpdir"
# since go1.20 - install uses env vars to decide where to put
# build artifacts. Why are all the google tooling so bloody dev
# hostile! WTF is wrong with command line args?!
export GOBIN=$bindir
# build it and stash it in the hostdir
echo "Building tool $tool from $src .."
(
cd $tmpdir
$e $Go install $src@latest || die "can't install $tool"
)
$e rm -rf $tmpdir
return 0
}
# protobuf gen
buildproto() {
local pbgo=protoc-gen-go
local vtgo=protoc-gen-go-vtproto
local vtgo_src=github.com/planetscale/vtprotobuf/cmd/protoc-gen-go-vtproto
local pc
local args="$*"
local pgen=$(type -p protoc)
local gogen=$(type -p $pbgo)
local vt=$Hostbindir/$vtgo
[ -z $pgen ] && die "install protoc tools"
[ -z $gogen ] && die "install protoc-gen-go"
# now install the vtproto generator
hosttool $vtgo $Hostbindir $vtgo_src
for f in $args; do
local dn=$(dirname $f)
local bn=$(basename $f .proto)
$e $pgen \
--go_out=. --plugin protoc-gen-go=$gogen \
--go-vtproto_out=. --plugin protoc-gen-go-vtproto="$vt" \
--go-vtproto_opt=features=marshal+unmarshal+size \
$f || die "can't generate protobuf output for $f .."
done
return 0
}
# the rest has to execute in the context of main shell (not funcs)
hostos=$($Go env GOHOSTOS) || exit 1
hostcpu=$($Go env GOHOSTARCH) || exit 1
# 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
export PATH=$Hostbindir:$PATH
[ -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
buildproto $Protobufs
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 "$@"
;;
mod)
set -- $args
$e $Go mod $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: