添加编译脚本

This commit is contained in:
CN-JS-HuiBai
2026-04-15 20:09:12 +08:00
parent 565a788f77
commit 20d3cb46d4
3 changed files with 459 additions and 0 deletions

183
building-linux.sh Normal file
View File

@@ -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"

276
building-windows.ps1 Normal file
View File

@@ -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 <path> Go binary path
-DistDir <path> Output directory, default: .\dist
-CgoEnabledValue <0|1> CGO_ENABLED value, default: 0
-Version <string> Embedded version, default: git describe --tags --always
-BuildTagsOthers <string> Override non-Windows build tags
-BuildTagsWindows <string> 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"