Make update-go-path.sh able to skip the Go bootstrap chain
Setting CONFIG_GOLANG_EXTERNAL_BOOTSTRAP_ROOT on its own only skips the initial bootstrap step; OpenWrt still builds the rest of the chain from source because CONFIG_GOLANG_BUILD_BOOTSTRAP defaults to y. Add --external, which clears that symbol so the installed toolchain builds host Go directly. Fix the "no Go installed" detection, which never fired. An unmatched glob is left as a literal, so the array held the pattern itself and the script wrote CONFIG_GOLANG_EXTERNAL_BOOTSTRAP_ROOT="/usr/lib/go-go-*/" and reported success. nullglob alone is not enough either, since it only drops words that contain a wildcard and the literal candidate paths survive regardless, so each candidate is now checked for existence. Also pick the Go version by asking bin/go rather than parsing the directory name, warn when the installed Go is older than the bootstrap version the tree expects, replace every existing form of a symbol instead of appending a duplicate, and run make defconfig afterwards. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,74 +1,172 @@
|
||||
#!/bin/bash
|
||||
# Automatically detect Go installation and update .config for OpenWRT
|
||||
# Point the OpenWrt build at an installed Go toolchain.
|
||||
#
|
||||
# Go based packages (tailscale, adguardhome, easytier, cloudflared, ...) need a
|
||||
# host Go. By default OpenWrt builds the whole bootstrap chain from source; an
|
||||
# already installed Go can replace part or all of that:
|
||||
#
|
||||
# --external GOLANG_BUILD_BOOTSTRAP=n, host Go is built with the
|
||||
# installed toolchain directly (skips the entire chain,
|
||||
# requires a Go new enough for the target version)
|
||||
# default keep GOLANG_BUILD_BOOTSTRAP=y and only set the root, which
|
||||
# skips the initial bootstrap step
|
||||
#
|
||||
# Usage: ./update-go-path.sh [options]
|
||||
#
|
||||
# --external skip the bootstrap chain entirely (recommended)
|
||||
# --go-root <dir> use this Go instead of auto-detecting
|
||||
# --skip-defconfig do not run make defconfig afterwards
|
||||
# -n, --dry-run show what would change, write nothing
|
||||
# -h, --help show this help
|
||||
#
|
||||
# Run it from the OpenWrt root: ./helper/update-go-path.sh
|
||||
#
|
||||
# Author: Zhe Yuan
|
||||
|
||||
set -e
|
||||
set -euo pipefail
|
||||
umask 022
|
||||
|
||||
CONFIG_FILE=".config"
|
||||
EXTERNAL=false
|
||||
GO_ROOT=""
|
||||
RUN_DEFCONFIG=true
|
||||
DRY_RUN=false
|
||||
|
||||
echo "========================================"
|
||||
echo " Go Path Auto Updater for OpenWRT"
|
||||
echo "========================================"
|
||||
info() { echo "[INFO] $*"; }
|
||||
warn() { echo "[WARN] $*"; }
|
||||
err() { echo "[ERROR] $*" >&2; }
|
||||
|
||||
# --- Check for .config file ---
|
||||
if [ ! -f "$CONFIG_FILE" ]; then
|
||||
echo "[ERROR] No .config file found in current directory!"
|
||||
echo "Please run this script inside your OpenWRT build root."
|
||||
exit 1
|
||||
fi
|
||||
usage() { sed -n '2,25p' "$0" | sed 's/^# \{0,1\}//;s/^#$//'; }
|
||||
|
||||
# --- Detect available Go installations ---
|
||||
GO_DIRS=(/usr/lib/go-*/)
|
||||
if [ ${#GO_DIRS[@]} -eq 0 ]; then
|
||||
echo "[ERROR] No Go installation found under /usr/lib/go-*"
|
||||
echo "Please install Go using: sudo apt install golang -y"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Extract version numbers ---
|
||||
GO_VERSIONS=()
|
||||
for dir in "${GO_DIRS[@]}"; do
|
||||
ver=$(basename "$dir" | sed -E 's/^go-([0-9]+\.[0-9]+).*$/\1/')
|
||||
GO_VERSIONS+=("$ver")
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--external) EXTERNAL=true ;;
|
||||
--go-root)
|
||||
if [ $# -lt 2 ] || [ -z "${2:-}" ]; then err "--go-root requires a directory."; exit 1; fi
|
||||
GO_ROOT="$2"; shift ;;
|
||||
--skip-defconfig) RUN_DEFCONFIG=false ;;
|
||||
-n|--dry-run) DRY_RUN=true ;;
|
||||
-h|--help) usage; exit 0 ;;
|
||||
*) err "Unknown option: $1"; echo "Run '$0 --help' for usage." >&2; exit 1 ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# --- Sort versions and pick the latest ---
|
||||
IFS=$'\n' sorted=($(sort -V <<<"${GO_VERSIONS[*]}"))
|
||||
LATEST_VER="${sorted[-1]}"
|
||||
LATEST_PATH="/usr/lib/go-${LATEST_VER}/"
|
||||
echo "========================================"
|
||||
echo " Go Toolchain Setup for OpenWrt"
|
||||
echo "========================================"
|
||||
|
||||
echo "[INFO] Found Go versions: ${GO_VERSIONS[*]}"
|
||||
echo "[INFO] Using latest Go version: $LATEST_VER"
|
||||
echo "[INFO] Path: $LATEST_PATH"
|
||||
|
||||
# --- Check if multiple versions exist ---
|
||||
if [ ${#GO_VERSIONS[@]} -gt 1 ]; then
|
||||
echo "[WARN] Multiple Go versions detected!"
|
||||
echo "If you prefer to use an older version, modify manually:"
|
||||
echo " CONFIG_GOLANG_EXTERNAL_BOOTSTRAP_ROOT=\"/usr/lib/go-X.XX/\""
|
||||
echo
|
||||
if [ ! -f "$CONFIG_FILE" ]; then
|
||||
err "No .config in the current directory."
|
||||
err "From the OpenWrt root, run it as: ./helper/$(basename "$0")"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Update .config ---
|
||||
if grep -q '^CONFIG_GOLANG_EXTERNAL_BOOTSTRAP_ROOT=' "$CONFIG_FILE"; then
|
||||
echo "[INFO] Updating existing CONFIG_GOLANG_EXTERNAL_BOOTSTRAP_ROOT..."
|
||||
sed -i "s|^CONFIG_GOLANG_EXTERNAL_BOOTSTRAP_ROOT=.*|CONFIG_GOLANG_EXTERNAL_BOOTSTRAP_ROOT=\"${LATEST_PATH}\"|" "$CONFIG_FILE"
|
||||
# --- Locate a Go installation --------------------------------------------
|
||||
if [ -z "$GO_ROOT" ]; then
|
||||
# nullglob only drops words that actually contain a wildcard; a literal path
|
||||
# such as /usr/local/go/ survives even when it does not exist. So collect
|
||||
# candidates and keep only the directories that are really there.
|
||||
shopt -s nullglob
|
||||
CANDIDATES=(/usr/lib/go-*/ /usr/local/go/ /usr/lib/golang/)
|
||||
shopt -u nullglob
|
||||
|
||||
GO_DIRS=()
|
||||
for dir in "${CANDIDATES[@]}"; do
|
||||
[ -d "$dir" ] && GO_DIRS+=("$dir")
|
||||
done
|
||||
|
||||
if [ ${#GO_DIRS[@]} -eq 0 ]; then
|
||||
err "No Go installation found under /usr/lib/go-*, /usr/local/go or /usr/lib/golang."
|
||||
err "Install one with: sudo apt install golang-1.24-go"
|
||||
err "or keep the default, where OpenWrt builds its own bootstrap chain."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BEST_VER=""
|
||||
for dir in "${GO_DIRS[@]}"; do
|
||||
[ -x "${dir}bin/go" ] || continue
|
||||
ver="$("${dir}bin/go" version 2>/dev/null | awk '{print $3}' | sed 's/^go//')"
|
||||
[ -n "$ver" ] || continue
|
||||
if [ -z "$BEST_VER" ] ||
|
||||
[ "$(printf '%s\n%s\n' "$BEST_VER" "$ver" | sort -V | tail -n 1)" = "$ver" ]; then
|
||||
BEST_VER="$ver"
|
||||
GO_ROOT="$dir"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -z "$GO_ROOT" ]; then
|
||||
err "Found Go directories but none contained a working bin/go."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ${#GO_DIRS[@]} -gt 1 ]; then
|
||||
info "Go installations found: ${GO_DIRS[*]}"
|
||||
info "Using the newest; override with --go-root <dir>."
|
||||
fi
|
||||
fi
|
||||
|
||||
GO_ROOT="${GO_ROOT%/}/"
|
||||
if [ ! -x "${GO_ROOT}bin/go" ]; then
|
||||
err "No usable Go compiler at ${GO_ROOT}bin/go"
|
||||
exit 1
|
||||
fi
|
||||
GO_VER="$("${GO_ROOT}bin/go" version | awk '{print $3}' | sed 's/^go//')"
|
||||
|
||||
info "Go toolchain: $GO_ROOT (version $GO_VER)"
|
||||
|
||||
# --- Warn if it is older than what the tree wants -------------------------
|
||||
BOOTSTRAP_MK="feeds/packages/lang/golang/golang-bootstrap/Makefile"
|
||||
if [ -f "$BOOTSTRAP_MK" ]; then
|
||||
NEED="$(awk -F':=' '/^GO_VERSION_MAJOR_MINOR/ {print $2; exit}' "$BOOTSTRAP_MK" | tr -d ' ')"
|
||||
if [ -n "$NEED" ] &&
|
||||
[ "$(printf '%s\n%s\n' "$NEED" "$GO_VER" | sort -V | head -n 1)" != "$NEED" ]; then
|
||||
warn "Installed Go $GO_VER is older than the bootstrap version $NEED this tree expects."
|
||||
warn "The build may fail; consider installing golang-$NEED-go."
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- Apply ----------------------------------------------------------------
|
||||
set_config() {
|
||||
local key="$1" val="$2"
|
||||
if [ "$DRY_RUN" = true ]; then
|
||||
echo "[DRY-RUN] $key=$val"
|
||||
return
|
||||
fi
|
||||
# Drop every existing form of the symbol, then append once.
|
||||
sed -i "/^${key}=/d;/^# ${key} is not set$/d" "$CONFIG_FILE"
|
||||
if [ "$val" = "n" ]; then
|
||||
echo "# $key is not set" >> "$CONFIG_FILE"
|
||||
else
|
||||
echo "$key=$val" >> "$CONFIG_FILE"
|
||||
fi
|
||||
}
|
||||
|
||||
set_config CONFIG_GOLANG_EXTERNAL_BOOTSTRAP_ROOT "\"$GO_ROOT\""
|
||||
|
||||
if [ "$EXTERNAL" = true ]; then
|
||||
set_config CONFIG_GOLANG_BUILD_BOOTSTRAP n
|
||||
info "Bootstrap chain disabled; host Go is built with the installed toolchain."
|
||||
else
|
||||
echo "[INFO] Adding CONFIG_GOLANG_EXTERNAL_BOOTSTRAP_ROOT..."
|
||||
echo "CONFIG_GOLANG_EXTERNAL_BOOTSTRAP_ROOT=\"${LATEST_PATH}\"" >> "$CONFIG_FILE"
|
||||
set_config CONFIG_GOLANG_BUILD_BOOTSTRAP y
|
||||
info "Bootstrap chain kept (only the initial step is skipped)."
|
||||
info "Pass --external to skip it entirely."
|
||||
fi
|
||||
|
||||
# --- Verify result ---
|
||||
echo
|
||||
echo "[SUCCESS] Go path updated in .config:"
|
||||
grep 'CONFIG_GOLANG_EXTERNAL_BOOTSTRAP_ROOT' "$CONFIG_FILE"
|
||||
if [ "$DRY_RUN" = true ]; then
|
||||
echo
|
||||
info "Dry run complete; .config was not modified."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$RUN_DEFCONFIG" = true ]; then
|
||||
info "Running make defconfig..."
|
||||
make defconfig >/dev/null
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "========================================"
|
||||
echo "✅ Go path update complete!"
|
||||
echo "OK Go configuration updated."
|
||||
echo "========================================"
|
||||
echo
|
||||
echo "👉 If you wish to override manually, edit .config and change:"
|
||||
echo " CONFIG_GOLANG_EXTERNAL_BOOTSTRAP_ROOT=\"/usr/lib/go-X.XX/\""
|
||||
grep -E '^(CONFIG_GOLANG_EXTERNAL_BOOTSTRAP_ROOT|CONFIG_GOLANG_BUILD_BOOTSTRAP)|^# CONFIG_GOLANG_BUILD_BOOTSTRAP' "$CONFIG_FILE" | sed 's/^/ /'
|
||||
echo
|
||||
|
||||
Reference in New Issue
Block a user