Files
SingboxForPanel/building-linux.sh
2026-04-15 20:13:53 +08:00

203 lines
4.9 KiB
Bash

#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DIST_DIR="${DIST_DIR:-$ROOT_DIR/dist}"
MAIN_PKG="./cmd/sing-box"
GO_BIN="${GO_BIN:-go}"
CGO_ENABLED_VALUE="${CGO_ENABLED_VALUE:-0}"
BUILD_JOBS="${GO_BUILD_JOBS:-}"
DEFAULT_TARGETS=(
"linux-amd64"
"linux-arm64"
"linux-armv7"
"windows-amd64"
"windows-arm64"
"darwin-amd64"
"darwin-arm64"
)
usage() {
cat <<'EOF'
Usage:
./build.sh Build common targets
./build.sh all Build common targets
./build.sh linux-amd64 Build a single target
./build.sh linux-amd64 windows-amd64
./build.sh current Build current host platform
Environment variables:
GO_BIN Go binary path, default: go
DIST_DIR Output directory, default: ./dist
CGO_ENABLED_VALUE CGO_ENABLED value, default: 0
GO_BUILD_JOBS Go build parallel jobs, default: detected CPU core count
VERSION Embedded version string, default: git describe --tags --always
BUILD_TAGS_OTHERS Override tags for non-Windows builds
BUILD_TAGS_WINDOWS Override tags for Windows builds
EOF
}
require_file() {
local file="$1"
if [[ ! -f "$file" ]]; then
echo "Missing required file: $file" >&2
exit 1
fi
}
trim_file() {
local file="$1"
awk 'BEGIN{ORS=""} {gsub(/\r/, ""); print}' "$file"
}
resolve_version() {
if [[ -n "${VERSION:-}" ]]; then
printf '%s' "$VERSION"
return
fi
if git -C "$ROOT_DIR" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
git -C "$ROOT_DIR" describe --tags --always 2>/dev/null || git -C "$ROOT_DIR" rev-parse --short HEAD
return
fi
printf '%s' "custom"
}
resolve_build_jobs() {
if [[ -n "$BUILD_JOBS" ]]; then
printf '%s' "$BUILD_JOBS"
return
fi
if command -v nproc >/dev/null 2>&1; then
nproc
return
fi
if command -v getconf >/dev/null 2>&1; then
getconf _NPROCESSORS_ONLN
return
fi
printf '%s' "1"
}
build_target() {
local target="$1"
local goos goarch goarm="" output tags
case "$target" in
linux-amd64)
goos="linux"
goarch="amd64"
output="$DIST_DIR/sing-box-linux-amd64"
tags="$BUILD_TAGS_OTHERS"
;;
linux-arm64)
goos="linux"
goarch="arm64"
output="$DIST_DIR/sing-box-linux-arm64"
tags="$BUILD_TAGS_OTHERS"
;;
linux-armv7)
goos="linux"
goarch="arm"
goarm="7"
output="$DIST_DIR/sing-box-linux-armv7"
tags="$BUILD_TAGS_OTHERS"
;;
windows-amd64)
goos="windows"
goarch="amd64"
output="$DIST_DIR/sing-box-windows-amd64.exe"
tags="$BUILD_TAGS_WINDOWS"
;;
windows-arm64)
goos="windows"
goarch="arm64"
output="$DIST_DIR/sing-box-windows-arm64.exe"
tags="$BUILD_TAGS_WINDOWS"
;;
darwin-amd64)
goos="darwin"
goarch="amd64"
output="$DIST_DIR/sing-box-darwin-amd64"
tags="$BUILD_TAGS_OTHERS"
;;
darwin-arm64)
goos="darwin"
goarch="arm64"
output="$DIST_DIR/sing-box-darwin-arm64"
tags="$BUILD_TAGS_OTHERS"
;;
current)
goos="$("$GO_BIN" env GOOS)"
goarch="$("$GO_BIN" env GOARCH)"
output="$DIST_DIR/sing-box-${goos}-${goarch}"
if [[ "$goos" == "windows" ]]; then
output="${output}.exe"
tags="$BUILD_TAGS_WINDOWS"
else
tags="$BUILD_TAGS_OTHERS"
fi
;;
*)
echo "Unsupported target: $target" >&2
exit 1
;;
esac
echo "==> Building $target (jobs: $RESOLVED_BUILD_JOBS)"
(
cd "$ROOT_DIR"
export CGO_ENABLED="$CGO_ENABLED_VALUE"
export GOOS="$goos"
export GOARCH="$goarch"
if [[ -n "$goarm" ]]; then
export GOARM="$goarm"
else
unset GOARM 2>/dev/null || true
fi
"$GO_BIN" build -v -p "$RESOLVED_BUILD_JOBS" -trimpath \
-ldflags "-X 'github.com/sagernet/sing-box/constant.Version=$VERSION_VALUE' $LDFLAGS_SHARED -s -w -buildid=" \
-tags "$tags" \
-o "$output" \
"$MAIN_PKG"
)
}
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
usage
exit 0
fi
require_file "$ROOT_DIR/release/DEFAULT_BUILD_TAGS_OTHERS"
require_file "$ROOT_DIR/release/DEFAULT_BUILD_TAGS_WINDOWS"
require_file "$ROOT_DIR/release/LDFLAGS"
if ! command -v "$GO_BIN" >/dev/null 2>&1; then
echo "Go binary not found: $GO_BIN" >&2
exit 1
fi
BUILD_TAGS_OTHERS="${BUILD_TAGS_OTHERS:-$(trim_file "$ROOT_DIR/release/DEFAULT_BUILD_TAGS_OTHERS")}"
BUILD_TAGS_WINDOWS="${BUILD_TAGS_WINDOWS:-$(trim_file "$ROOT_DIR/release/DEFAULT_BUILD_TAGS_WINDOWS")}"
LDFLAGS_SHARED="$(trim_file "$ROOT_DIR/release/LDFLAGS")"
VERSION_VALUE="$(resolve_version)"
RESOLVED_BUILD_JOBS="$(resolve_build_jobs)"
mkdir -p "$DIST_DIR"
if [[ "$#" -eq 0 || "${1:-}" == "all" ]]; then
TARGETS=("${DEFAULT_TARGETS[@]}")
else
TARGETS=("$@")
fi
for target in "${TARGETS[@]}"; do
build_target "$target"
done
echo
echo "Build completed."
echo "Output directory: $DIST_DIR"