这段批处理脚本用于在 Windows 系统上构建 WireGuard 应用程序。脚本自动化了依赖项的下载、资源文件的生成、代码的编译以及可执行文件的签名等过程。以下是对脚本各个部分的详细分析:
1. 初始设置
关闭命令回显
@echo off
- 作用:关闭命令行回显,使脚本运行时不会显示每条执行的命令,仅显示输出信息。
版权信息
rem SPDX-License-Identifier: MIT
rem Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
- 作用:使用
rem
命令添加注释,声明脚本的许可证类型和版权信息。
启用延迟变量扩展
setlocal enabledelayedexpansion
- 作用:启用延迟变量扩展,允许在同一代码块内动态修改和访问变量值。这对于在循环或条件语句中处理变量非常有用。
设置环境变量
set BUILDDIR=%~dp0
set PATH=%BUILDDIR%.deps\llvm-mingw\bin;%BUILDDIR%.deps\go\bin;%BUILDDIR%.deps;%PATH%
set PATHEXT=.exe
cd /d %BUILDDIR% || exit /b 1
set BUILDDIR=%~dp0
:- 作用:将
BUILDDIR
设置为脚本所在目录的路径。
- 作用:将
set PATH=...
:- 作用:将
.deps\llvm-mingw\bin
、.deps\go\bin
和.deps
目录添加到系统的PATH
环境变量中,确保脚本能够找到所需的可执行文件和工具链。
- 作用:将
set PATHEXT=.exe
:- 作用:设置可执行文件的扩展名为
.exe
,确保命令行能够正确识别和执行这些文件。
- 作用:设置可执行文件的扩展名为
cd /d %BUILDDIR% || exit /b 1
:- 作用:切换到
BUILDDIR
目录。如果切换失败,则脚本退出并返回错误代码1
。
- 作用:切换到
2. 检查和安装依赖项
检查是否已准备好依赖项
if exist .deps\prepared goto :render
- 作用:检查
.deps\prepared
文件是否存在。如果存在,跳转到:render
标签,跳过依赖项的下载和准备过程。
安装依赖项 (:installdeps
)
:installdeps
rmdir /s /q .deps 2> NUL
mkdir .deps || goto :error
cd .deps || goto :error
...
copy /y NUL prepared > NUL || goto :error
cd .. || goto :error
- 作用:
rmdir /s /q .deps 2> NUL
:删除.deps
目录及其所有内容,如果删除失败(例如目录不存在),则忽略错误。mkdir .deps || goto :error
:创建.deps
目录。如果创建失败,跳转到:error
标签处理错误。cd .deps || goto :error
:进入.deps
目录。如果失败,跳转到:error
。- 下载并验证依赖项:通过调用
:download
子程序下载和验证所需的依赖文件(Go、LLVM MinGW、ImageMagick、GNU Make、WireGuard 工具和 WireGuard-nt)。 copy /y NUL prepared > NUL || goto :error
:创建一个空的prepared
文件,标志依赖项已准备好。如果失败,跳转到:error
。cd .. || goto :error
:返回上级目录,如果失败,跳转到:error
。
下载子程序 (:download
)
:download
echo [+] Downloading %1
curl -#fLo %1 %2 || exit /b 1
echo [+] Verifying %1
for /f %%a in ('CertUtil -hashfile %1 SHA256 ^| findstr /r "^[0-9a-f]*$"') do if not "%%a"=="%~3" exit /b 1
echo [+] Extracting %1
tar -xf %1 %~4 || exit /b 1
echo [+] Cleaning up %1
del %1 || exit /b 1
goto :eof
- 作用:
- 下载文件:使用
curl
从指定 URL 下载文件并保存为%1
(第一个参数)。 - 验证 SHA256 校验和:使用
CertUtil
计算下载文件的 SHA256 哈希值,并与预期值%~3
比较。如果不匹配,则退出并返回错误。 - 解压文件:使用
tar
解压缩下载的文件,根据%~4
指定的参数(例如解压特定目录或文件)。 - 清理下载的压缩包:删除下载的压缩文件。
- 跳转到文件末尾:结束子程序,返回调用点。
- 下载文件:使用
3. 渲染图标 (:render
)
:render
echo [+] Rendering icons
for %%a in ("ui\icon\*.svg") do convert -background none "%%~fa" -define icon:auto-resize="256,192,128,96,64,48,40,32,24,20,16" -compress zip "%%~dpna.ico" || goto :error
- 作用:
- 输出信息:显示正在渲染图标的消息。
- 循环处理 SVG 图标:遍历
ui\icon\
目录下的所有.svg
文件,使用convert
(ImageMagick 工具)将每个 SVG 文件转换为多分辨率的.ico
图标文件。 - 错误处理:如果转换失败,跳转到
:error
标签。
4. 构建 WireGuard (:build
)
:build
for /f "tokens=3" %%a in ('findstr /r "Number.*=.*[0-9.]*" .\version\version.go') do set WIREGUARD_VERSION=%%a
set WIREGUARD_VERSION=%WIREGUARD_VERSION:"=%
for /f "tokens=1-4" %%a in ("%WIREGUARD_VERSION:.= % 0 0 0") do set WIREGUARD_VERSION_ARRAY=%%a,%%b,%%c,%%d
set GOOS=windows
set GOARM=7
set GOPATH=%BUILDDIR%.deps\gopath
set GOROOT=%BUILDDIR%.deps\go
if "%GoGenerate%"=="yes" (
echo [+] Regenerating files
go generate ./... || exit /b 1
)
call :build_plat x86 i686 386 || goto :error
call :build_plat amd64 x86_64 amd64 || goto :error
call :build_plat arm64 aarch64 arm64 || goto :error
- 作用:
- 提取版本号:
- 使用
findstr
从version/version.go
文件中提取版本号,并存储在WIREGUARD_VERSION
变量中。 - 移除版本号中的引号。
- 将版本号拆分为数组格式,存储在
WIREGUARD_VERSION_ARRAY
变量中,用于资源文件的版本信息。
- 使用
- 设置 Go 环境变量:
set GOOS=windows
:设置目标操作系统为 Windows。set GOARM=7
:设置 ARM 架构的目标版本(ARMv7)。set GOPATH
和set GOROOT
:设置 Go 的工作区和根目录,指向.deps\gopath
和.deps\go
。
- 生成代码:
- 如果环境变量
GoGenerate
设置为yes
,则运行go generate
命令生成必要的代码。如果失败,退出脚本。
- 如果环境变量
- 构建不同架构的可执行文件:
- 调用
:build_plat
子程序三次,分别为x86
(386 架构)、amd64
(amd64 架构)和arm64
(arm64 架构)构建 WireGuard。
- 调用
- 提取版本号:
构建平台子程序 (:build_plat
)
:build_plat
set GOARCH=%~3
mkdir %1 >NUL 2>&1
echo [+] Assembling resources %1
%~2-w64-mingw32-windres -I ".deps\wireguard-nt\bin\%~1" -DWIREGUARD_VERSION_ARRAY=%WIREGUARD_VERSION_ARRAY% -DWIREGUARD_VERSION_STR=%WIREGUARD_VERSION% -i resources.rc -o "resources_%~3.syso" -O coff -c 65001 || exit /b %errorlevel%
echo [+] Building program %1
go build -tags load_wgnt_from_rsrc -ldflags="-H windowsgui -s -w" -trimpath -buildvcs=false -v -o "%~1\wireguard.exe" || exit /b 1
if not exist "%~1\wg.exe" (
echo [+] Building command line tools %1
del .deps\src\*.exe .deps\src\*.o .deps\src\wincompat\*.o .deps\src\wincompat\*.lib 2> NUL
set LDFLAGS=-s
make --no-print-directory -C .deps\src PLATFORM=windows CC=%~2-w64-mingw32-gcc WINDRES=%~2-w64-mingw32-windres V=1 RUNSTATEDIR= SYSTEMDUNITDIR= -j%NUMBER_OF_PROCESSORS% || exit /b 1
move /Y .deps\src\wg.exe "%~1\wg.exe" > NUL || exit /b 1
)
goto :eof
- 参数解释:
%1
:平台名称(如x86
、amd64
、arm64
)。%2
:对应的 MinGW 前缀(如i686
、x86_64
、aarch64
)。%3
:Go 架构标识(如386
、amd64
、arm64
)。
- 作用:
- 设置架构:
set GOARCH=%~3
:设置 Go 的目标架构。
- 创建平台目录:
mkdir %1 >NUL 2>&1
:创建对应平台的目录(如x86
、amd64
、arm64
),如果目录已存在,则忽略错误。
- 组装资源文件:
- 使用
windres
工具(MinGW 的资源编译器)将resources.rc
资源文件编译为.syso
文件,嵌入版本信息。 - 参数:
-I ".deps\wireguard-nt\bin\%~1"
:指定资源文件包含路径。-DWIREGUARD_VERSION_ARRAY=...
和-DWIREGUARD_VERSION_STR=...
:定义资源文件中的版本信息宏。-i resources.rc
:输入的资源文件。-o "resources_%~3.syso"
:输出的.syso
资源文件。-O coff -c 65001
:指定输出格式为 COFF,并设置编码为 UTF-8。
- 使用
- 构建 WireGuard 可执行文件:
- 使用
go build
命令编译 WireGuard 程序,设置相应的编译标志:-tags load_wgnt_from_rsrc
:启用特定的编译标签。-ldflags="-H windowsgui -s -w"
:链接器标志,生成 GUI 应用程序且删除调试信息以减小可执行文件大小。-trimpath
:去除编译时路径信息。-buildvcs=false
:不嵌入版本控制系统信息。-v
:显示详细的编译信息。-o "%~1\wireguard.exe"
:指定输出的可执行文件路径。
- 如果编译失败,退出脚本并返回错误代码。
- 使用
- 构建命令行工具
wg.exe
:- 检查
wg.exe
是否存在:if not exist "%~1\wg.exe" (
:如果在目标平台目录中不存在wg.exe
,则需要构建命令行工具。
- 删除旧的可执行文件和对象文件:
del .deps\src\*.exe .deps\src\*.o .deps\src\wincompat\*.o .deps\src\wincompat\*.lib 2> NUL
:删除旧的可执行文件和对象文件,忽略错误。
- 设置链接器标志:
set LDFLAGS=-s
:设置链接器标志,去除符号表以减小可执行文件大小。
- 运行
make
构建wg.exe
:make --no-print-directory -C .deps\src PLATFORM=windows CC=%~2-w64-mingw32-gcc WINDRES=%~2-w64-mingw32-windres V=1 RUNSTATEDIR= SYSTEMDUNITDIR= -j%NUMBER_OF_PROCESSORS% || exit /b 1
:--no-print-directory
:不打印目录信息。-C .deps\src
:切换到.deps\src
目录执行make
。PLATFORM=windows
:指定目标平台为 Windows。CC=...
和WINDRES=...
:指定使用的编译器和资源编译器。V=1
:启用详细输出。-j%NUMBER_OF_PROCESSORS%
:并行构建,使用与处理器数量相同的线程数。
- 如果
make
构建失败,退出脚本并返回错误代码。
- 移动生成的
wg.exe
到目标平台目录:move /Y .deps\src\wg.exe "%~1\wg.exe" > NUL || exit /b 1
:将生成的wg.exe
移动到目标平台目录,忽略输出。如果移动失败,退出脚本并返回错误代码。
- 检查
- 结束子程序:
goto :eof
:结束当前子程序,返回调用点。
- 设置架构:
5. 签名可执行文件 (:sign
)
:sign
if exist .\sign.bat call .\sign.bat
if "%SigningCertificate%"=="" goto :success
if "%TimestampServer%"=="" goto :success
echo [+] Signing
signtool sign /sha1 "%SigningCertificate%" /fd sha256 /tr "%TimestampServer%" /td sha256 /d WireGuard x86\wireguard.exe x86\wg.exe amd64\wireguard.exe amd64\wg.exe arm64\wireguard.exe arm64\wg.exe || goto :error
- 作用:
- 调用自定义签名脚本:
if exist .\sign.bat call .\sign.bat
:如果存在sign.bat
文件,则调用执行该脚本。这允许用户自定义签名过程。
- 检查签名证书和时间戳服务器:
if "%SigningCertificate%"=="" goto :success
:如果未设置SigningCertificate
环境变量,跳过签名步骤。if "%TimestampServer%"=="" goto :success
:如果未设置TimestampServer
环境变量,跳过签名步骤。
- 执行签名:
signtool sign ...
:使用signtool
工具对生成的可执行文件进行签名。/sha1 "%SigningCertificate%"
:指定签名证书的 SHA1 哈希值。/fd sha256
:使用 SHA256 哈希算法进行签名。/tr "%TimestampServer%"
和/td sha256
:指定时间戳服务器,并使用 SHA256 进行时间戳哈希。/d WireGuard
:为签名指定描述信息。x86\wireguard.exe x86\wg.exe amd64\wireguard.exe amd64\wg.exe arm64\wireguard.exe arm64\wg.exe
:要签名的目标可执行文件。
- 如果签名失败,跳转到
:error
标签。
- 调用自定义签名脚本:
6. 成功结束 (:success
)
:success
echo [+] Success. Launch wireguard.exe.
exit /b 0
- 作用:
- 输出成功信息:显示构建成功的消息。
- 退出脚本:以成功状态码
0
退出脚本。
7. 错误处理 (:error
)
:error
echo [-] Failed with error #%errorlevel%.
cmd /c exit %errorlevel%
- 作用:
- 输出错误信息:显示构建失败的消息及错误代码。
- 退出脚本:使用当前错误级别退出脚本,传递错误状态给调用环境。
8. 关键子程序总结
:download
子程序
- 功能:下载指定的文件、验证其 SHA256 校验和、解压缩并清理下载的压缩包。
- 参数:
%1
:目标文件名。%2
:下载 URL。%3
:预期的 SHA256 校验和。%4
:解压缩参数(如要解压的特定文件或目录)。
:build_plat
子程序
- 功能:为指定的平台架构编译 WireGuard 可执行文件。
- 参数:
%1
:平台名称(如x86
、amd64
、arm64
)。%2
:MinGW 前缀(如i686
、x86_64
、aarch64
)。%3
:Go 架构标识(如386
、amd64
、arm64
)。
9. 总结
这段批处理脚本通过以下步骤自动化了 WireGuard 在 Windows 上的构建过程:
- 初始化环境:设置必要的环境变量,确保脚本在正确的目录下运行,并能找到所需的工具链。
- 依赖项管理:检查是否已经准备好依赖项,如果没有,则下载、验证和解压所需的依赖包,包括 Go、LLVM MinGW、ImageMagick、GNU Make 等。
- 资源生成:将 SVG 图标转换为多分辨率的 ICO 图标文件,确保应用程序具有适当的图标资源。
- 代码编译:提取版本信息,设置 Go 环境变量,并为不同的架构(x86、amd64、arm64)编译 WireGuard 可执行文件及其命令行工具。
- 签名可执行文件:如果提供了签名证书和时间戳服务器,使用
signtool
对生成的可执行文件进行数字签名,确保其完整性和来源的可信度。 - 错误处理:在任何步骤失败时,脚本都会输出相应的错误信息并退出,确保构建过程的可靠性。
- 成功提示:构建完成后,输出成功消息,指示用户可以启动生成的
wireguard.exe
。
通过这种自动化的构建流程,开发者能够高效地在 Windows 平台上生成不同架构的 WireGuard 版本,确保构建过程的一致性和可重复性。