Files
fenrir/build-fenrir.sh

123 lines
4.7 KiB
Bash
Executable File

#!/usr/bin/env bash
# Build Fenrir with a suitable Go toolchain without changing the system Go.
set -euo pipefail
projectDir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
fail() {
echo "Error: $*" >&2
exit 1
}
usage() {
cat <<'EOF'
Usage: build-fenrir.sh [-o PATH | --output PATH] [-- GO_BUILD_FLAGS...]
Build Fenrir, downloading a suitable Go toolchain when needed.
-o, --output PATH Write the binary to PATH (default: checkout/fenrir).
Relative paths are resolved from the caller's directory.
Missing parent directories are created.
-h, --help Show this help without checking build dependencies.
-- Pass remaining flags to go build, e.g. -- -trimpath.
Go environment variables such as GOFLAGS, GOCACHE, GOMODCACHE, GOTMPDIR,
and CGO_CFLAGS/CGO_LDFLAGS are inherited. This script only builds the binary;
package installation and resource staging belong in the packaging recipe.
EOF
}
outputPath="$projectDir/fenrir"
buildFlags=()
while (( $# )); do
case $1 in
-o|--output)
(( $# >= 2 )) || fail "$1 requires a path."
[[ -n $2 && $2 != -* ]] || fail "$1 requires a path (use ./ for a path starting with '-')."
outputPath=$2
shift 2
;;
-h|--help)
usage
exit 0
;;
--)
shift
buildFlags=("$@")
break
;;
*) fail "Unknown argument: $1. See --help." ;;
esac
done
if [[ $outputPath != /* ]]; then
outputPath="$PWD/$outputPath"
fi
[[ ! -d $outputPath ]] || fail "Output path is a directory; specify the binary filename."
cd -- "$projectDir"
[[ $(uname -s) == Linux ]] || fail "Fenrir requires Linux."
command -v pkg-config >/dev/null || fail "Install pkg-config and the native development libraries listed in README.md."
missingLibraries=()
for library in libevdev x11 vterm alsa; do
if ! pkg-config --exists "$library"; then
missingLibraries+=("$library")
fi
done
if (( ${#missingLibraries[@]} )); then
fail "Missing development libraries (pkg-config names): ${missingLibraries[*]}. See README.md."
fi
requiredVersion=$(awk '$1 == "go" { print $2; exit }' go.mod)
[[ $requiredVersion =~ ^1\.[0-9]+\.[0-9]+$ ]] || fail "Cannot read the required Go version from go.mod."
# Go 1.21+ downloads and verifies the toolchain selected by go.mod itself.
# Probe the bundled version so a user's GOTOOLCHAIN setting cannot affect this check.
unset GOROOT
goCommand=""
if command -v go >/dev/null; then
installedVersion=$(GOTOOLCHAIN=local go version 2>/dev/null || true)
if [[ $installedVersion =~ go1\.([0-9]+) ]] && (( 10#${BASH_REMATCH[1]} >= 21 )); then
goCommand=$(command -v go)
fi
fi
if [[ -z $goCommand ]]; then
case $(uname -m) in
x86_64) archiveArch=amd64 ;;
aarch64|arm64) archiveArch=arm64 ;;
armv6l|armv7l) archiveArch=armv6l ;;
i386|i486|i586|i686) archiveArch=386 ;;
ppc64le|riscv64|s390x|loong64) archiveArch=$(uname -m) ;;
loongarch64) archiveArch=loong64 ;;
*) fail "No Go bootstrap archive configured for $(uname -m). Install Go 1.21 or newer and rerun this script." ;;
esac
toolchainDir="${XDG_CACHE_HOME:-$HOME/.cache}/fenrir/toolchains/go${requiredVersion}.linux-${archiveArch}"
goCommand="$toolchainDir/go/bin/go"
if [[ ! -x $goCommand ]]; then
command -v curl >/dev/null || fail "Install curl to download Go, or install Go 1.21 or newer."
command -v tar >/dev/null || fail "Install tar to unpack Go."
mkdir -p -- "$(dirname -- "$toolchainDir")"
downloadDir=$(mktemp -d "${toolchainDir}.download.XXXXXX")
trap 'rm -rf -- "$downloadDir"' EXIT
echo "Downloading Go $requiredVersion for Linux/$archiveArch from go.dev..."
curl --fail --location --show-error --proto '=https' --proto-redir '=https' \
--output "$downloadDir/go.tar.gz" \
"https://go.dev/dl/go${requiredVersion}.linux-${archiveArch}.tar.gz"
tar -xzf "$downloadDir/go.tar.gz" -C "$downloadDir"
[[ -x $downloadDir/go/bin/go ]] || fail "The downloaded archive does not contain Go."
# Another build may have finished the same download while ours ran.
if [[ ! -x $goCommand ]]; then
mkdir -p -- "$toolchainDir"
mv -T -- "$downloadDir/go" "$toolchainDir/go" || [[ -x $goCommand ]]
fi
fi
fi
# Apply automatic selection only to this build, including when the caller has
# disabled it globally.
export GOTOOLCHAIN=auto
echo "Using $("$goCommand" version)"
mkdir -p -- "$(dirname -- "$outputPath")"
"$goCommand" build "${buildFlags[@]}" -o "$outputPath" ./cmd/fenrir
echo "Fenrir has been built: $outputPath"