@echo off rem =========================================================================== rem SG_Algorithm 编译脚本 rem rem 功能: rem 1) 交互选择要编译的库, 使用 MSBuild Rebuild (先清理再编译), rem 按库显示完成百分比进度, Debug 和 Release 都编译 (默认 x64) rem 2) 使用 WSL + CMake 编译 arm(aarch64) 库, 构建目录 armbuild, rem 每次都先 make clean 再编译 rem rem 用法: rem build.bat 交互选择库, Rebuild Debug + Release, 并编译 ARM rem build.bat /all 编译全部库 rem build.bat /config:debug 只编译 Debug (debug / release / both) rem build.bat /no-arm 跳过 ARM 编译 rem build.bat /arm-config:Debug ARM 配置 (默认 Release) rem build.bat /opencv:480 ARM 使用 OpenCV 4.8.0 (默认 320) rem build.bat /platform:x86 Windows 平台 (默认 x64) rem build.bat /j:8 ARM make 并行任务数 (默认 CPU 核心数) rem build.bat /dry-run 只打印命令, 不实际编译 rem build.bat /no-pause 结束后不暂停 rem rem 输出: rem Windows : build\{platform}\{config}\ (e.g. build\x64\Debug) rem ARM : build\aarch64\ rem =========================================================================== rem 注意: 本文件保存为 ANSI(GBK/cp936) 编码, 与中文 Windows 控制台代码页一致, rem 请勿另存为 UTF-8, 否则 cmd 解析中文时会乱码。 setlocal EnableExtensions EnableDelayedExpansion set "ROOT=%~dp0" if "%ROOT:~-1%"=="\" set "ROOT=%ROOT:~0,-1%" set "SLN=%ROOT%\SG_Algorithm.sln" set "ARMBUILD=%ROOT%\armbuild" set "LOGDIR=%ROOT%\build\logs" rem ---------------------------- 默认参数 ----------------------------------- set "PLATFORM=x64" set "CONFIGS=Debug Release" set "DO_ARM=1" set "ARM_CONFIG=Release" set "OPENCV_VERSION=320" set "JOBS=" set "NOPAUSE=0" set "DRYRUN=0" set "BUILD_ALL=0" set "FAILED=" set "FAIL_COUNT=0" set "OK_COUNT=0" set "STEP=0" rem ---------------------------- 参数解析 ----------------------------------- :parse_args if "%~1"=="" goto args_done set "ARG=%~1" if /i "%ARG%"=="/all" ( set "BUILD_ALL=1" & shift & goto parse_args ) if /i "%ARG%"=="/no-arm" ( set "DO_ARM=0" & shift & goto parse_args ) if /i "%ARG%"=="/no-pause" ( set "NOPAUSE=1" & shift & goto parse_args ) if /i "%ARG%"=="/dry-run" ( set "DRYRUN=1" & shift & goto parse_args ) if /i "%ARG%"=="/help" goto help if /i "%ARG%"=="/?" goto help if /i "%ARG%"=="-h" goto help if /i "!ARG:~0,10!"=="/platform:" ( set "PLATFORM=!ARG:~10!" & shift & goto parse_args ) if /i "!ARG:~0,12!"=="/arm-config:" ( set "ARM_CONFIG=!ARG:~12!" & shift & goto parse_args ) if /i "!ARG:~0,8!"=="/opencv:" ( set "OPENCV_VERSION=!ARG:~8!" & shift & goto parse_args ) if /i "!ARG:~0,8!"=="/config:" ( call :set_configs "!ARG:~8!" & shift & goto parse_args ) if /i "!ARG:~0,3!"=="/j:" ( set "JOBS=!ARG:~3!" & shift & goto parse_args ) echo [错误] 未知参数: %ARG% echo 使用 build.bat /help 查看帮助。 set "EXIT_CODE=1" goto end :args_done if /i not "%PLATFORM%"=="x64" if /i not "%PLATFORM%"=="x86" ( echo [错误] 不支持的平台: %PLATFORM% ^(仅支持 x64 / x86^) set "EXIT_CODE=1" goto end ) if /i "%ARM_CONFIG%"=="debug" set "ARM_CONFIG=Debug" if /i "%ARM_CONFIG%"=="release" set "ARM_CONFIG=Release" if /i not "%ARM_CONFIG%"=="Debug" if /i not "%ARM_CONFIG%"=="Release" ( echo [错误] 不支持的 ARM 配置: %ARM_CONFIG% ^(仅支持 Debug / Release^) set "EXIT_CODE=1" goto end ) if not exist "%SLN%" ( echo [错误] 找不到解决方案: %SLN% set "EXIT_CODE=1" goto end ) rem ---------------------------- 查找 MSBuild -------------------------------- rem 优先使用装有 v142 工具集的 VS 安装 (本解决方案中部分工程仍使用 v142) set "MSBUILD=" set "MSBUILD_V142=" set "VSWHERE=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" if exist "%VSWHERE%" ( for /f "delims=" %%i in ('call "%VSWHERE%" -products * -property installationPath') do ( if exist "%%i\MSBuild\Current\Bin\MSBuild.exe" ( if not defined MSBUILD set "MSBUILD=%%i\MSBuild\Current\Bin\MSBuild.exe" for /d %%d in ("%%i\VC\Tools\MSVC\14.29*") do ( set "MSBUILD_V142=%%i\MSBuild\Current\Bin\MSBuild.exe" ) ) ) ) if defined MSBUILD_V142 set "MSBUILD=%MSBUILD_V142%" if not defined MSBUILD ( for %%p in (MSBuild.exe) do if not "%%~$PATH:p"=="" set "MSBUILD=%%~$PATH:p" ) if not defined MSBUILD ( echo [错误] 未找到 MSBuild.exe, 请安装 Visual Studio 2019/2022 生成工具。 set "EXIT_CODE=1" goto end ) rem ---------------------------- 枚举库工程 ---------------------------------- rem 只列出非 *_test 的库工程, 且工程文件必须存在 set "LIB_COUNT=0" for /f "usebackq tokens=2,3 delims==, " %%A in (`findstr /b /c:"Project(" "%SLN%"`) do ( set "PNAME=%%~A" set "PPATH=%%~B" if not "!PPATH:_test\=!"=="!PPATH!" set "PNAME=" if /i "!PNAME:~-5!"=="_test" set "PNAME=" if "!PPATH:~-8!"==".vcxproj" if defined PNAME if exist "%ROOT%\!PPATH!" ( set /a LIB_COUNT+=1 set "LIB[!LIB_COUNT!]=!PNAME!" set "LIBPATH[!LIB_COUNT!]=!PPATH!" ) ) if %LIB_COUNT%==0 ( echo [错误] 在解决方案中未找到可编译的库工程。 set "EXIT_CODE=1" goto end ) if "%BUILD_ALL%"=="1" goto pick_all rem ---------------------------- 交互选择 ----------------------------------- :menu echo. echo ============================================================ echo SG_Algorithm 编译 (Rebuild) echo 解决方案 : SG_Algorithm.sln echo 平台 : %PLATFORM% echo 配置 : %CONFIGS% echo ARM 编译 : %DO_ARM% ^(%ARM_CONFIG%^) echo ============================================================ for /l %%i in (1,1,%LIB_COUNT%) do ( set "IDX= %%i" if %%i GEQ 10 set "IDX= %%i" echo !IDX!. !LIB[%%i]! ) echo. echo A. 全部 echo Q. 退出 echo. set "SEL=" set /p "SEL=请输入编号 (多选: 1 3 5 / 1-4 / all): " if not defined SEL ( set /a EMPTY_COUNT+=1 if !EMPTY_COUNT! GEQ 3 ( echo 未输入选择, 退出。 set "EXIT_CODE=1" goto end ) goto menu ) set "SEL=%SEL:,= %" set "SEL=%SEL:;= %" if /i "%SEL: =%"=="q" goto cancel if /i "%SEL: =%"=="quit" goto cancel if /i "%SEL: =%"=="all" goto pick_all if /i "%SEL: =%"=="a" goto pick_all if "%SEL: =%"=="*" goto pick_all rem 只允许 数字 / 空格 / 减号, 避免特殊字符进入命令行 for /f "delims=0123456789- " %%x in ("%SEL%") do ( echo [警告] 输入包含无效内容: %%x goto menu ) if "%SEL: =%"=="" goto menu for %%t in (!SEL!) do call :select_token "%%t" if not defined PICKED ( echo [警告] 没有选中任何有效的库, 请重新输入。 goto menu ) goto selection_done :pick_all set "PICKED=1" for /l %%i in (1,1,%LIB_COUNT%) do set "PICK[%%i]=1" :selection_done rem 自动附加 baseAlgorithm (工程之间没有 ProjectReference, 靠链接 .lib 依赖) set "HAS_BASE=0" set "NEED_BASE=0" for /l %%i in (1,1,%LIB_COUNT%) do ( if defined PICK[%%i] ( if /i "!LIB[%%i]!"=="baseAlgorithm" ( set "HAS_BASE=1" ) else ( findstr /i /c:"baseAlgorithm.lib" "%ROOT%\!LIBPATH[%%i]!" >nul && set "NEED_BASE=1" ) ) ) if "%NEED_BASE%"=="1" if "%HAS_BASE%"=="0" ( for /l %%i in (1,1,%LIB_COUNT%) do ( if /i "!LIB[%%i]!"=="baseAlgorithm" ( set "PICK[%%i]=1" echo [提示] 自动附加依赖库 baseAlgorithm ) ) ) rem ---------------------------- Windows 编译 (Rebuild) ---------------------- if not exist "%LOGDIR%" mkdir "%LOGDIR%" set "SEL_COUNT=0" for /l %%i in (1,1,%LIB_COUNT%) do if defined PICK[%%i] set /a SEL_COUNT+=1 set "CFG_COUNT=0" for %%c in (%CONFIGS%) do set /a CFG_COUNT+=1 set /a JOB_TOTAL=SEL_COUNT*CFG_COUNT echo. echo ============================================================ echo MSBuild Rebuild ^(%PLATFORM%^) 共 !JOB_TOTAL! 个任务 echo ============================================================ rem 先重建 baseAlgorithm, 其它库都链接它 for %%c in (%CONFIGS%) do ( for /l %%i in (1,1,%LIB_COUNT%) do ( if /i "!LIB[%%i]!"=="baseAlgorithm" if defined PICK[%%i] call :rebuild_one "!LIB[%%i]!" "%ROOT%\!LIBPATH[%%i]!" "%%c" ) for /l %%i in (1,1,%LIB_COUNT%) do ( if /i not "!LIB[%%i]!"=="baseAlgorithm" if defined PICK[%%i] call :rebuild_one "!LIB[%%i]!" "%ROOT%\!LIBPATH[%%i]!" "%%c" ) ) echo [100%%] 全部任务完成 rem ---------------------------- ARM 编译 ------------------------------------ if "%DO_ARM%"=="1" ( call :build_arm ) else ( echo. echo [跳过] ARM 编译 ^(/no-arm^) ) rem ---------------------------- 汇总 ---------------------------------------- echo. echo ============================================================ echo 编译结果 echo ============================================================ echo Windows 输出 : %ROOT%\build\%PLATFORM%\ (%CONFIGS%) if "%DO_ARM%"=="1" echo ARM 输出 : %ROOT%\build\aarch64 echo 成功任务 : %OK_COUNT% if %FAIL_COUNT% GTR 0 ( echo 失败任务 : %FAIL_COUNT% echo -^> %FAILED% echo 详细日志 : %LOGDIR% set "EXIT_CODE=1" ) else ( echo 失败任务 : 0 set "EXIT_CODE=0" ) goto end :cancel echo. echo 已取消。 set "EXIT_CODE=0" goto end :help echo. echo SG_Algorithm 编译脚本 (全部为 Rebuild: 先清理再编译) echo. echo build.bat 交互选择库, Rebuild Debug + Release, 并编译 ARM echo build.bat /all 编译全部库 echo build.bat /config:debug 只编译 Debug ^(debug / release / both^) echo build.bat /no-arm 跳过 ARM 编译 echo build.bat /arm-config:Debug ARM 配置 ^(默认 Release^) echo build.bat /opencv:480 ARM 使用 OpenCV 4.8.0 ^(默认 320^) echo build.bat /platform:x86 Windows 平台 ^(默认 x64^) echo build.bat /j:8 ARM make 并行任务数 ^(默认 CPU 核心数^) echo build.bat /dry-run 只打印命令, 不实际编译 echo build.bat /no-pause 结束后不暂停 echo. echo 输出: echo Windows : build\^<平台^>\^<配置^>\ echo ARM : build\aarch64 ^(CMake 构建目录 armbuild, 需要 WSL^) echo. set "EXIT_CODE=0" goto end rem =========================================================================== rem 子过程 rem =========================================================================== rem ---- 解析 /config: 参数 ---- :set_configs set "CFG=%~1" if /i "%CFG%"=="both" ( set "CONFIGS=Debug Release" & goto :eof ) if /i "%CFG%"=="all" ( set "CONFIGS=Debug Release" & goto :eof ) if /i "%CFG%"=="debug" ( set "CONFIGS=Debug" & goto :eof ) if /i "%CFG%"=="release" ( set "CONFIGS=Release" & goto :eof ) set "CONFIGS=%CFG:,= %" goto :eof rem ---- 解析交互输入中的单个记号 ---- :select_token set "TOK=%~1" if not defined TOK goto :eof if /i "%TOK%"=="all" ( set "PICKED=1" & for /l %%i in (1,1,%LIB_COUNT%) do set "PICK[%%i]=1" & goto :eof ) if /i "%TOK%"=="a" ( set "PICKED=1" & for /l %%i in (1,1,%LIB_COUNT%) do set "PICK[%%i]=1" & goto :eof ) set "SINGLE=%TOK:-=%" if "%SINGLE%"=="%TOK%" ( call :select_range %TOK% %TOK% ) else ( for /f "tokens=1,2 delims=-" %%a in ("%TOK%") do call :select_range %%a %%b ) goto :eof rem ---- 选中一个编号区间 ---- :select_range set "FROM=%~1" set "TO=%~2" if not defined FROM goto :eof if not defined TO goto :eof if %FROM% LSS 1 goto :bad_range if %TO% GTR %LIB_COUNT% goto :bad_range if %FROM% GTR %TO% goto :bad_range for /l %%i in (%FROM%,1,%TO%) do ( set "PICK[%%i]=1" set "PICKED=1" ) goto :eof :bad_range echo [警告] 编号超出范围 (1-%LIB_COUNT%): %FROM%-%TO% goto :eof rem ---- Rebuild 单个库, 显示完成百分比进度 ---- :rebuild_one set "LIB=%~1" set "PROJ=%~2" set "CFG=%~3" set "LOG=%LOGDIR%\%~1_%~3.log" set /a STEP+=1 set /a DONE=STEP-1 set /a PCT=DONE*100/JOB_TOTAL set "PCTXT= !PCT!" if !PCT! GEQ 10 set "PCTXT= !PCT!" if !PCT! GEQ 100 set "PCTXT=!PCT!" echo [!PCTXT!%%] (!STEP!/!JOB_TOTAL!) Rebuild !LIB! [%CFG% ^| %PLATFORM%] if "%DRYRUN%"=="1" ( echo [dry-run] "%MSBUILD%" "%PROJ%" /t:Rebuild /p:Configuration=%CFG% /p:Platform=%PLATFORM% set /a OK_COUNT+=1 goto :eof ) "%MSBUILD%" "%PROJ%" /t:Rebuild /p:Configuration=%CFG% /p:Platform=%PLATFORM% "/p:SolutionDir=%ROOT%\\" /m /nologo /v:m > "!LOG!" 2>&1 if errorlevel 1 ( echo [失败] -^> !LOG! findstr /i /c:" error " /c:"error C" /c:"error LNK" /c:"error MSB" "!LOG!" set "FAILED=!FAILED! !LIB![%CFG%]" set /a FAIL_COUNT+=1 ) else ( echo [成功] set /a OK_COUNT+=1 ) goto :eof rem ---- 编译 ARM 库 (WSL + CMake, 目录 armbuild, 先 make clean) ---- :build_arm echo. echo ============================================================ echo ARM (aarch64) Rebuild ^| 构建目录: armbuild echo ============================================================ where wsl.exe >nul 2>nul if errorlevel 1 ( echo [错误] 未找到 wsl.exe, 无法编译 ARM 库。可加 /no-arm 跳过。 set "FAILED=!FAILED! ARM[wsl]" set /a FAIL_COUNT+=1 goto :eof ) if not exist "%ARMBUILD%" mkdir "%ARMBUILD%" set "WSL_ARM=" for /f "usebackq delims=" %%i in (`wsl wslpath -a -u "%ARMBUILD%"`) do set "WSL_ARM=%%i" if not defined WSL_ARM ( echo [错误] 无法转换为 WSL 路径: %ARMBUILD% set "FAILED=!FAILED! ARM[path]" set /a FAIL_COUNT+=1 goto :eof ) set "NPROC=%NUMBER_OF_PROCESSORS%" if not defined NPROC set "NPROC=4" set "MAKE_OPTS=-j%NPROC%" if defined JOBS set "MAKE_OPTS=-j%JOBS%" if "%DRYRUN%"=="1" ( echo [dry-run] cd '%WSL_ARM%' ^&^& cmake -DCMAKE_BUILD_TYPE=%ARM_CONFIG% -DOPENCV_VERSION=%OPENCV_VERSION% .. ^&^& make clean ^&^& make %MAKE_OPTS% set /a OK_COUNT+=1 goto :eof ) wsl -e bash -lc "command -v cmake >/dev/null 2>&1 || { echo '[错误] WSL 中未找到 cmake'; exit 2; }" if errorlevel 1 ( echo [错误] WSL 中未找到 cmake。 set "FAILED=!FAILED! ARM[cmake]" set /a FAIL_COUNT+=1 goto :eof ) wsl -e bash -lc "command -v aarch64-linux-gnu-g++ >/dev/null 2>&1 || { echo '[错误] WSL 中未找到 aarch64-linux-gnu-g++'; exit 3; }" if errorlevel 1 ( echo [错误] WSL 中未找到 aarch64-linux-gnu-g++ 交叉编译器。 set "FAILED=!FAILED! ARM[gcc]" set /a FAIL_COUNT+=1 goto :eof ) wsl -e bash -lc "cd '%WSL_ARM%' && cmake -DCMAKE_BUILD_TYPE=%ARM_CONFIG% -DOPENCV_VERSION=%OPENCV_VERSION% .. && make clean && make %MAKE_OPTS%" if errorlevel 1 ( echo [失败] ARM Rebuild ^(%ARM_CONFIG%^) set "FAILED=!FAILED! ARM[%ARM_CONFIG%]" set /a FAIL_COUNT+=1 ) else ( echo [成功] ARM Rebuild ^(%ARM_CONFIG%^) -^> %ROOT%\build\aarch64 set /a OK_COUNT+=1 ) goto :eof rem =========================================================================== :end if %NOPAUSE%==0 ( echo. pause ) endlocal & exit /b %EXIT_CODE%