<# .SYNOPSIS Windows equivalent of build_core.sh - builds the Go core binaries. .DESCRIPTION Builds the Android client for every shipped ABI and the Linux client/servers. arm64-v8a builds with CGO disabled and needs no NDK. The other Android ABIs do: `GOOS=android` requires external linking for arm, amd64 and 386, so an NDK toolchain is located automatically. If none is found those ABIs are skipped with a warning rather than failing the build - the APK is still installable on 64-bit ARM, which is the overwhelming majority of devices. .EXAMPLE .\build_core.ps1 .\build_core.ps1 -ClientOnly .\build_core.ps1 -Abis arm64-v8a,armeabi-v7a #> [CmdletBinding()] param( # Only build the Android client (skip the Linux client and servers). [switch]$ClientOnly, # Root of the APK's lib directory; per-ABI subdirectories are created here. [string]$AndroidLibRoot, # Which Android ABIs to build. [string[]]$Abis = @('arm64-v8a', 'armeabi-v7a', 'x86_64'), # NDK root; auto-detected from the SDK when omitted. [string]$NdkRoot, # Minimum Android API the native cores are built for. [int]$MinApi = 24, [string]$GoBin = $(if ($env:GO_BIN) { $env:GO_BIN } else { 'go' }) ) $ErrorActionPreference = 'Stop' $Root = $PSScriptRoot if (-not $AndroidLibRoot) { $AndroidLibRoot = Join-Path $Root 'android\lib' } function Invoke-Go { param([hashtable]$Env, [string[]]$GoArgs) $saved = @{} foreach ($k in $Env.Keys) { $saved[$k] = [Environment]::GetEnvironmentVariable($k) [Environment]::SetEnvironmentVariable($k, $Env[$k]) } try { & $GoBin @GoArgs if ($LASTEXITCODE -ne 0) { throw "go build failed (exit $LASTEXITCODE)" } } finally { foreach ($k in $saved.Keys) { [Environment]::SetEnvironmentVariable($k, $saved[$k]) } } } # Locate an NDK llvm toolchain bin directory, newest first. function Find-NdkBin { param([string]$Explicit) $roots = @() if ($Explicit) { $roots += $Explicit } if ($env:ANDROID_NDK_ROOT) { $roots += $env:ANDROID_NDK_ROOT } if ($env:ANDROID_NDK_HOME) { $roots += $env:ANDROID_NDK_HOME } foreach ($sdk in $env:ANDROID_SDK_ROOT, $env:ANDROID_HOME, "$env:LOCALAPPDATA\Android\Sdk") { if ($sdk -and (Test-Path (Join-Path $sdk 'ndk'))) { $roots += (Get-ChildItem (Join-Path $sdk 'ndk') -Directory | Sort-Object { try { [version]$_.Name } catch { [version]'0.0.0' } } -Descending | ForEach-Object { $_.FullName }) } } foreach ($r in $roots) { if (-not $r) { continue } $bin = Join-Path $r 'toolchains\llvm\prebuilt\windows-x86_64\bin' if (Test-Path $bin) { return $bin } } return $null } # ABI -> (GOARCH, GOARM, clang triple prefix) $abiSpec = @{ 'arm64-v8a' = @{ arch = 'arm64'; arm = ''; cc = 'aarch64-linux-android' } 'armeabi-v7a' = @{ arch = 'arm'; arm = '7'; cc = 'armv7a-linux-androideabi' } 'x86_64' = @{ arch = 'amd64'; arm = ''; cc = 'x86_64-linux-android' } 'x86' = @{ arch = '386'; arm = ''; cc = 'i686-linux-android' } } $go = Get-Command $GoBin -ErrorAction SilentlyContinue if (-not $go) { throw "Go compiler not found. Install from https://go.dev/dl/ or set -GoBin." } $ndkBin = Find-NdkBin $NdkRoot New-Item -ItemType Directory -Force -Path "$Root\bin" | Out-Null Push-Location "$Root\core" try { $ldflags = '-ldflags=-s -w' $built = @() foreach ($abi in $Abis) { if (-not $abiSpec.ContainsKey($abi)) { Write-Warning "unknown ABI $abi, skipping"; continue } $spec = $abiSpec[$abi] $outDir = Join-Path $AndroidLibRoot $abi $out = Join-Path $outDir 'libdragontcp_client.so' # arm64 links internally; everything else needs the NDK's clang. $env = @{ GOOS = 'android'; GOARCH = $spec.arch } if ($spec.arm) { $env['GOARM'] = $spec.arm } if ($abi -eq 'arm64-v8a') { $env['CGO_ENABLED'] = '0' } else { if (-not $ndkBin) { Write-Warning "[core] $abi skipped: no NDK found (set -NdkRoot or ANDROID_NDK_ROOT)" continue } $cc = Join-Path $ndkBin ("{0}{1}-clang.cmd" -f $spec.cc, $MinApi) if (-not (Test-Path $cc)) { Write-Warning "[core] $abi skipped: $cc not found" continue } $env['CGO_ENABLED'] = '1' $env['CC'] = $cc } Write-Host "[core] Android $abi client..." -ForegroundColor Cyan New-Item -ItemType Directory -Force -Path $outDir | Out-Null Invoke-Go $env @('build', '-trimpath', $ldflags, '-o', $out, './cmd/dragontcp-client') $built += $abi } if (-not $built) { throw 'No Android ABI was built.' } Write-Host "[core] Android ABIs: $($built -join ', ')" -ForegroundColor Green # Remove stale ABI directories so the APK never ships an out-of-date core. if (Test-Path $AndroidLibRoot) { foreach ($dir in Get-ChildItem $AndroidLibRoot -Directory) { if ($built -notcontains $dir.Name) { Write-Warning "[core] removing stale $($dir.Name) native library" Remove-Item $dir.FullName -Recurse -Force } } } if (-not $ClientOnly) { Write-Host '[core] Linux AMD64 client...' -ForegroundColor Cyan Invoke-Go @{ CGO_ENABLED = '0'; GOOS = 'linux'; GOARCH = 'amd64' } ` @('build', '-trimpath', $ldflags, '-o', "$Root\bin\dragontcp-hybrid-client-linux-amd64", './cmd/dragontcp-client') Write-Host '[core] Linux AMD64 server...' -ForegroundColor Cyan Invoke-Go @{ CGO_ENABLED = '0'; GOOS = 'linux'; GOARCH = 'amd64' } ` @('build', '-trimpath', $ldflags, '-o', "$Root\bin\dragontcp-hybrid-server-linux-amd64", './cmd/dragontcp-server') Write-Host '[core] Linux ARM64 server...' -ForegroundColor Cyan Invoke-Go @{ CGO_ENABLED = '0'; GOOS = 'linux'; GOARCH = 'arm64' } ` @('build', '-trimpath', $ldflags, '-o', "$Root\bin\dragontcp-hybrid-server-linux-arm64", './cmd/dragontcp-server') } } finally { Pop-Location } Write-Host 'Core build complete.' -ForegroundColor Green