From 20d3cb46d46258294e658fea2e291e46ea7ff79f Mon Sep 17 00:00:00 2001 From: CN-JS-HuiBai Date: Wed, 15 Apr 2026 20:09:12 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=BC=96=E8=AF=91=E8=84=9A?= =?UTF-8?q?=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- install.sh => building-install.sh | 0 building-linux.sh | 183 ++++++++++++++++++++ building-windows.ps1 | 276 ++++++++++++++++++++++++++++++ 3 files changed, 459 insertions(+) rename install.sh => building-install.sh (100%) create mode 100644 building-linux.sh create mode 100644 building-windows.ps1 diff --git a/install.sh b/building-install.sh similarity index 100% rename from install.sh rename to building-install.sh diff --git a/building-linux.sh b/building-linux.sh new file mode 100644 index 00000000..cf8fc5a9 --- /dev/null +++ b/building-linux.sh @@ -0,0 +1,183 @@ +#!/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}" + +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 + 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" +} + +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" + ( + 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 1 -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)" + +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" diff --git a/building-windows.ps1 b/building-windows.ps1 new file mode 100644 index 00000000..91cdc630 --- /dev/null +++ b/building-windows.ps1 @@ -0,0 +1,276 @@ +[CmdletBinding()] +param( + [Parameter(Position = 0, ValueFromRemainingArguments = $true)] + [string[]]$Targets = @("all"), + + [string]$GoBin = "", + [string]$DistDir = "", + [string]$CgoEnabledValue = "0", + [string]$Version = "", + [string]$BuildTagsOthers = "", + [string]$BuildTagsWindows = "", + [switch]$Help +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = "Stop" + +$RootDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$MainPkg = "./cmd/sing-box" +$DefaultTargets = @( + "linux-amd64", + "linux-arm64", + "linux-armv7", + "windows-amd64", + "windows-arm64", + "darwin-amd64", + "darwin-arm64" +) + +function Show-Usage { + @' +Usage: + .\building-windows.ps1 + .\building-windows.ps1 all + .\building-windows.ps1 linux-amd64 + .\building-windows.ps1 linux-amd64 windows-amd64 + .\building-windows.ps1 current + +Optional parameters: + -GoBin Go binary path + -DistDir Output directory, default: .\dist + -CgoEnabledValue <0|1> CGO_ENABLED value, default: 0 + -Version Embedded version, default: git describe --tags --always + -BuildTagsOthers Override non-Windows build tags + -BuildTagsWindows Override Windows build tags +'@ | Write-Host +} + +function Require-File { + param([string]$Path) + + if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) { + throw "Missing required file: $Path" + } +} + +function Read-TrimmedFile { + param([string]$Path) + + return ((Get-Content -LiteralPath $Path -Raw) -replace "`r", "").Trim() +} + +function Resolve-GoBinary { + param([string]$RequestedGoBin) + + if ($RequestedGoBin) { + if (-not (Test-Path -LiteralPath $RequestedGoBin -PathType Leaf)) { + throw "Go binary not found: $RequestedGoBin" + } + return (Resolve-Path -LiteralPath $RequestedGoBin).Path + } + + $command = Get-Command go -ErrorAction SilentlyContinue + if ($command) { + return $command.Source + } + + $defaultPath = "C:\Program Files\Go\bin\go.exe" + if (Test-Path -LiteralPath $defaultPath -PathType Leaf) { + return $defaultPath + } + + throw "Go binary not found. Please install Go or pass -GoBin." +} + +function Resolve-Version { + param( + [string]$RequestedVersion, + [string]$RepoRoot + ) + + if ($RequestedVersion) { + return $RequestedVersion + } + + $gitCommand = Get-Command git -ErrorAction SilentlyContinue + if ($gitCommand) { + Push-Location $RepoRoot + try { + $described = git describe --tags --always 2>$null + if ($LASTEXITCODE -eq 0 -and $described) { + return $described.Trim() + } + $commit = git rev-parse --short HEAD 2>$null + if ($LASTEXITCODE -eq 0 -and $commit) { + return $commit.Trim() + } + } + finally { + Pop-Location + } + } + + return "custom" +} + +function Get-TargetConfig { + param([string]$Target) + + switch ($Target) { + "linux-amd64" { + return @{ + GOOS = "linux" + GOARCH = "amd64" + Output = "sing-box-linux-amd64" + Tags = $script:ResolvedBuildTagsOthers + } + } + "linux-arm64" { + return @{ + GOOS = "linux" + GOARCH = "arm64" + Output = "sing-box-linux-arm64" + Tags = $script:ResolvedBuildTagsOthers + } + } + "linux-armv7" { + return @{ + GOOS = "linux" + GOARCH = "arm" + GOARM = "7" + Output = "sing-box-linux-armv7" + Tags = $script:ResolvedBuildTagsOthers + } + } + "windows-amd64" { + return @{ + GOOS = "windows" + GOARCH = "amd64" + Output = "sing-box-windows-amd64.exe" + Tags = $script:ResolvedBuildTagsWindows + } + } + "windows-arm64" { + return @{ + GOOS = "windows" + GOARCH = "arm64" + Output = "sing-box-windows-arm64.exe" + Tags = $script:ResolvedBuildTagsWindows + } + } + "darwin-amd64" { + return @{ + GOOS = "darwin" + GOARCH = "amd64" + Output = "sing-box-darwin-amd64" + Tags = $script:ResolvedBuildTagsOthers + } + } + "darwin-arm64" { + return @{ + GOOS = "darwin" + GOARCH = "arm64" + Output = "sing-box-darwin-arm64" + Tags = $script:ResolvedBuildTagsOthers + } + } + "current" { + $goos = (& $script:ResolvedGoBin env GOOS).Trim() + $goarch = (& $script:ResolvedGoBin env GOARCH).Trim() + $output = "sing-box-$goos-$goarch" + $tags = $script:ResolvedBuildTagsOthers + if ($goos -eq "windows") { + $output += ".exe" + $tags = $script:ResolvedBuildTagsWindows + } + return @{ + GOOS = $goos + GOARCH = $goarch + Output = $output + Tags = $tags + } + } + default { + throw "Unsupported target: $Target" + } + } +} + +function Invoke-BuildTarget { + param([string]$Target) + + $config = Get-TargetConfig -Target $Target + $outputPath = Join-Path $script:ResolvedDistDir $config.Output + + Write-Host "==> Building $Target" -ForegroundColor Cyan + + Push-Location $RootDir + try { + $env:CGO_ENABLED = $CgoEnabledValue + $env:GOOS = $config.GOOS + $env:GOARCH = $config.GOARCH + + if ($config.ContainsKey("GOARM")) { + $env:GOARM = $config.GOARM + } else { + Remove-Item Env:GOARM -ErrorAction SilentlyContinue + } + + & $script:ResolvedGoBin build -v -p 1 -trimpath ` + -ldflags "-X 'github.com/sagernet/sing-box/constant.Version=$script:ResolvedVersion' $script:ResolvedLdflagsShared -s -w -buildid=" ` + -tags $config.Tags ` + -o $outputPath ` + $MainPkg + + if ($LASTEXITCODE -ne 0) { + throw "Build failed: $Target" + } + } + finally { + Pop-Location + } +} + +if ($Help) { + Show-Usage + exit 0 +} + +if ($Targets.Count -eq 1 -and ($Targets[0] -eq "-h" -or $Targets[0] -eq "--help")) { + Show-Usage + exit 0 +} + +$releaseTagsOthersPath = Join-Path $RootDir "release\DEFAULT_BUILD_TAGS_OTHERS" +$releaseTagsWindowsPath = Join-Path $RootDir "release\DEFAULT_BUILD_TAGS_WINDOWS" +$releaseLdflagsPath = Join-Path $RootDir "release\LDFLAGS" + +Require-File -Path $releaseTagsOthersPath +Require-File -Path $releaseTagsWindowsPath +Require-File -Path $releaseLdflagsPath + +$script:ResolvedGoBin = Resolve-GoBinary -RequestedGoBin $GoBin +$script:ResolvedDistDir = if ($DistDir) { $DistDir } else { Join-Path $RootDir "dist" } +$script:ResolvedDistDir = [System.IO.Path]::GetFullPath($script:ResolvedDistDir) +$script:ResolvedVersion = Resolve-Version -RequestedVersion $Version -RepoRoot $RootDir +$script:ResolvedBuildTagsOthers = if ($BuildTagsOthers) { $BuildTagsOthers } else { Read-TrimmedFile -Path $releaseTagsOthersPath } +$script:ResolvedBuildTagsWindows = if ($BuildTagsWindows) { $BuildTagsWindows } else { Read-TrimmedFile -Path $releaseTagsWindowsPath } +$script:ResolvedLdflagsShared = Read-TrimmedFile -Path $releaseLdflagsPath + +New-Item -ItemType Directory -Force -Path $script:ResolvedDistDir | Out-Null + +$resolvedTargets = @() +if ($Targets.Count -eq 0 -or ($Targets.Count -eq 1 -and $Targets[0] -eq "all")) { + $resolvedTargets = $DefaultTargets +} else { + $resolvedTargets = $Targets +} + +foreach ($target in $resolvedTargets) { + Invoke-BuildTarget -Target $target +} + +Write-Host "" +Write-Host "Build completed." -ForegroundColor Green +Write-Host "Output directory: $script:ResolvedDistDir"