-
Notifications
You must be signed in to change notification settings - Fork 42
/
build
executable file
·450 lines (354 loc) · 9.84 KB
/
build
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
#! /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="src:gotun"
# Relative path to protobuf sources
# e.g. src/foo/a.proto
Protobufs=""
# -- DO NOT CHANGE ANYTHING AFTER THIS --
Z=`basename $0`
PWD=`pwd`
Static=0
Dryrun=0
Prodver=""
Repover=""
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
getvcs_version() {
local rev=
local prodv=
if [ -d "./.hg" ]; then
local xrev=$(hg id --id) || exit 1
local brev=${xrev%+}
if [ "$brev" != "$xrev" ]; then
rev="hg:${brev}-dirty"
else
rev="hg:${brev}"
fi
prodv=$(hg log -r "branch(stable) and tag()" -T "{tags}\n" | sort -V | tail -1)
elif [ -d "./.git" ]; then
local xrev=$(git describe --always --dirty --long --abbrev=12) || exit 1
rev="git:$xrev"
prodv=$(git tag --list | sort -V | tail -1)
else
rev="UNKNOWN-VER"
warn "Can't find version info"
fi
[ -n "$Prodver" ] && prodv=$Prodver
echo "$rev $prodv"
return 0
}
read -r Repover Prodver <<< $(getvcs_version)
usage() {
declare -a progv=($Progs)
declare n=${#progv[@]}
declare pstr=
for ((i=0; i < n; i++)); do
local ent=${progv[$i]}
local dir=${ent%%:*}
local tool=${ent##*:}
pstr=$(printf "$pstr\n\t%s $Prodver $Repover (from ./%s)" $tool $dir)
done
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: $pstr
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
# Do Protobufs if needed
if [ -n "$Protobufs" ]; then
set +e
buildproto $Protobufs
set -e
fi
# Get git/hg version info for the build
repover="main.RepoVersion=$Repover"
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 ($Repover), $cross $msg .."
for p in $all; do
if echo $p | grep -q ':' ; then
out=${p##*:}
dir=${p%%:*}
else
out=$p
dir=$p
fi
# Add .exe suffix to out if needed
if [ "$GOOS" = "windows" ]; then
base=${out%%.exe}
out="${base}.exe"
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: