From 61d068ada1b5c321da219de07dbfbac97a48ba21 Mon Sep 17 00:00:00 2001 From: Justin Schuh Date: Fri, 9 Jul 2021 06:23:09 -0700 Subject: [PATCH] Update build_win.bat (#6688) * Support relative as well as absolute paths in -d/-destdir * Improved debuggability (control variables and echo suppression) * Improved error handling and messages --- build_win.bat | 137 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 96 insertions(+), 41 deletions(-) diff --git a/build_win.bat b/build_win.bat index b2bdf9aec..dac590811 100644 --- a/build_win.bat +++ b/build_win.bat @@ -1,6 +1,6 @@ @setlocal disableDelayedExpansion enableExtensions -@echo off -GOTO :MAIN +@IF "%PS_ECHO_ON%" NEQ "" (echo on) ELSE (echo off) +@GOTO :MAIN :HELP @ECHO Performs initial build or rebuild of the app (build) and deps (build/deps). @ECHO Default options are determined from build directories and system state. @@ -20,30 +20,33 @@ GOTO :MAIN @ECHO deps - clean and build deps @ECHO deps-dirty - build deps without cleaning @ECHO Default: %PS_STEPS_DEFAULT% -@ECHO -d -DESTDIR Deps destination directory +@ECHO -d -DESTDIR Deps destination directory (ignored on dirty builds) @ECHO %PS_DESTDIR_DEFAULT_MSG% @ECHO. @ECHO Example usage: @ECHO First build: build_win -d "c:\src\PrusaSlicer-deps" @ECHO Deps change: build_win -s all @ECHO App rebuild: build_win +@ECHO. GOTO :END :MAIN SET START_TIME=%TIME% +SET PS_START_DIR=%CD% pushd %~dp0 REM Probe build directories and sytem state for reasonable default arguments SET PS_CONFIG=RelWithDebInfo SET PS_ARCH=%PROCESSOR_ARCHITECTURE% CALL :TOLOWER PS_ARCH -SET DEPS_PATH_FILE=%~dp0deps\build\.DEPS_PATH.txt +SET PS_DEPS_PATH_FILE=%~dp0deps\build\.DEPS_PATH.txt SET PS_DESTDIR= -IF EXIST %DEPS_PATH_FILE% ( - FOR /F "tokens=* USEBACKQ" %%I IN ("%DEPS_PATH_FILE%") DO SET PS_DESTDIR=%%I +IF EXIST %PS_DEPS_PATH_FILE% ( + FOR /F "tokens=* USEBACKQ" %%I IN ("%PS_DEPS_PATH_FILE%") DO SET PS_DESTDIR=%%I IF EXIST build/ALL_BUILD.vcxproj ( SET PS_STEPS=app-dirty ) ELSE SET PS_STEPS=app ) ELSE SET PS_STEPS=all +SET PS_DESTDIR_CACHED=%PS_DESTDIR% REM Set up parameters used by help menu SET PS_CONFIG_DEFAULT=%PS_CONFIG% @@ -60,16 +63,40 @@ SET EXIT_STATUS=1 SET PARSER_STATE= SET PARSER_FAIL= FOR %%I in (%*) DO CALL :PARSE_OPTION "ARCH CONFIG DESTDIR STEPS" PARSER_STATE "%%~I" -IF "%PARSER_FAIL%%PARSER_STATE%" NEQ "" GOTO :HELP +IF "%PARSER_FAIL%" NEQ "" ( + @ECHO ERROR: Invalid switch: %PARSER_FAIL% 1>&2 + GOTO :HELP +)ELSE IF "%PARSER_STATE%" NEQ "" ( + @ECHO ERROR: Missing parameter for: %PARSER_STATE% 1>&2 + GOTO :HELP +) REM Validate arguments +SET PS_STEPS_SAVED=%PS_STEPS% CALL :PARSE_OPTION_NAME "all all-dirty deps-dirty deps app-dirty app" PS_STEPS -%PS_STEPS% -IF "%PS_STEPS%" EQU "" GOTO :HELP +IF "%PS_STEPS%" EQU "" ( + @ECHO ERROR: Invalid parameter: steps=%PS_STEPS_SAVED% 1>&2 + GOTO :HELP +) ELSE SET PS_STEPS_SAVED= (echo %PS_STEPS%)| findstr /I /C:"dirty">nul && SET PS_STEPS_DIRTY=1 CALL :TOLOWER PS_STEPS CALL :TOLOWER PS_ARCH -IF "%OPTION_NAME%" NEQ "" GOTO :HELP -IF "%PS_STEPS_DIRTY%%PS_DESTDIR%" EQU "" GOTO :HELP +CALL :CANONICALIZE_PATH PS_DESTDIR "%PS_START_DIR%" +IF "%PS_DESTDIR%" EQU "" ( + IF "%PS_STEPS_DIRTY%" EQU "" ( + @ECHO ERROR: Parameter required: destdir 1>&2 + GOTO :HELP + ) +) ELSE IF "%PS_DESTDIR%" NEQ "%PS_DESTDIR_CACHED%" ( + IF "%PS_STEPS_DIRTY%" NEQ "" ( + @ECHO WARNING: Parameter ignored: destdir + ) ELSE (echo "all deps")| findstr /I /C:"%PS_STEPS%">nul || ( + @ECHO WARNING: Conflict with cached parameter: 1>&2 + @ECHO WARNING: -destdir=%PS_DESTDIR% 1>&2 + @ECHO WARNING: cached=%PS_DESTDIR_CACHED% 1>&2 + ) +) +SET PS_DESTDIR_DEFAULT_MSG= REM Set up MSVC environment SET EXIT_STATUS=2 @@ -77,12 +104,18 @@ SET EXIT_STATUS=2 @ECHO ** Build Config: %PS_CONFIG% @ECHO ** Target Arch: %PS_ARCH% @ECHO ** Build Steps: %PS_STEPS% +@ECHO ** Deps path: %PS_DESTDIR% @ECHO ** Using Microsoft Visual Studio installation found at: SET VSWHERE="%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" IF NOT EXIST %VSWHERE% SET VSWHERE="%ProgramFiles%\Microsoft Visual Studio\Installer\vswhere.exe" FOR /F "tokens=* USEBACKQ" %%I IN (`%VSWHERE% -nologo -property installationPath`) DO SET MSVC_DIR=%%I @ECHO ** %MSVC_DIR% -CALL "%MSVC_DIR%\Common7\Tools\vsdevcmd.bat" -arch=%PS_ARCH% -host_arch=%PS_ARCH_HOST% -app_platform=Desktop || GOTO :END +CALL "%MSVC_DIR%\Common7\Tools\vsdevcmd.bat" -arch=%PS_ARCH% -host_arch=%PS_ARCH_HOST% -app_platform=Desktop +IF "%ERRORLEVEL%" NEQ "0" GOTO :END +IF "%PS_DRY_RUN_ONLY%" NEQ "" ( + @ECHO Script terminated early because PS_DRY_RUN_ONLY is set. 1>&2 + GOTO :END +) IF /I "%PS_STEPS:~0,3%" EQU "app" GOTO :BUILD_APP REM Build deps @@ -91,7 +124,7 @@ SET EXIT_STATUS=3 IF "%PS_STEPS_DIRTY%" EQU "" CALL :MAKE_OR_CLEAN_DIRECTORY deps\build cd deps\build || GOTO :END IF "%PS_STEPS_DIRTY%" EQU "" cmake.exe .. -DDESTDIR="%PS_DESTDIR%" || GOTO :END -(echo %PS_DESTDIR%)> "%DEPS_PATH_FILE%" +(echo %PS_DESTDIR%)> "%PS_DEPS_PATH_FILE%" msbuild /m ALL_BUILD.vcxproj /p:Configuration=%PS_CONFIG% || GOTO :END cd ..\.. IF /I "%PS_STEPS:~0,4%" EQU "deps" GOTO :PROLOGUE @@ -107,58 +140,67 @@ msbuild /m ALL_BUILD.vcxproj /p:Configuration=%PS_CONFIG% || GOTO :END :PROLOGUE SET EXIT_STATUS=%ERRORLEVEL% :END +@IF "%PS_ECHO_ON%%PS_DRY_RUN_ONLY%" NEQ "" ( + @ECHO Script Parameters: + @SET PS_ +) @ECHO Script started at %START_TIME% and completed at %TIME%. popd -endlocal exit /B %EXIT_STATUS% GOTO :EOF REM Functions and stubs start here. :PARSE_OPTION -REM Argument parser called for each argument -REM %1 - Valid option list -REM %2 - Variable name for parser state; must be unset when parsing finished -REM %3 - Current argument value -REM PARSER_FAIL will be set on an error -REM Note: Must avoid delayed expansion since filenames may contain ! character +@REM Argument parser called for each argument +@REM %1 - Valid option list +@REM %2 - Variable name for parser state; must be unset when parsing finished +@REM %3 - Current argument value +@REM PARSER_FAIL will be set on an error +@REM Note: Must avoid delayed expansion since filenames may contain ! character setlocal disableDelayedExpansion +IF "%PARSER_FAIL%" NEQ "" GOTO :EOF CALL SET LAST_ARG=%%%2%% IF "%LAST_ARG%" EQU "" ( CALL :PARSE_OPTION_NAME %1 %~2 %~3 1 SET ARG_TYPE=NAME ) ELSE ( - SET PS_SET_COMMAND=^&SET PS_%LAST_ARG%=%~3 + SET PS_SET_COMMAND=SET PS_%LAST_ARG%=%~3 SET ARG_TYPE=LAST_ARG SET %~2= ) CALL SET LAST_ARG=%%%2%% -IF "%LAST_ARG%" EQU "" IF "%ARG_TYPE%" EQU "NAME" SET PARSER_FAIL=1 -endlocal & (SET PARSER_FAIL=%PARSER_FAIL%) & (SET %~2=%LAST_ARG%) %PS_SET_COMMAND% +IF "%LAST_ARG%%ARG_TYPE%" EQU "NAME" SET PARSER_FAIL=%~3 +( + endlocal + SET PARSER_FAIL=%PARSER_FAIL% + SET %~2=%LAST_ARG% + %PS_SET_COMMAND% +) GOTO :EOF :PARSE_OPTION_NAME -REM Parses an option name -REM %1 - Valid option list -REM %2 - Out variable name; unset on error -REM %3 - Current argument value -REM $4 - Boolean indicating single character switches are valid -REM Note: Delayed expansion safe because ! character is invalid in option name +@REM Parses an option name +@REM %1 - Valid option list +@REM %2 - Out variable name; unset on error +@REM %3 - Current argument value +@REM $4 - Boolean indicating single character switches are valid +@REM Note: Delayed expansion safe because ! character is invalid in option name setlocal enableDelayedExpansion -IF "%4" NEQ "" FOR %%I IN (%~1) DO ( +IF "%4" NEQ "" FOR %%I IN (%~1) DO @( SET SHORT_NAME=%%~I SET SHORT_ARG_!SHORT_NAME:~0,1!=%%~I ) -SET OPTION_NAME=%~3 -(echo %OPTION_NAME%)| findstr /R /C:"[-/]..*">nul || GOTO :PARSE_OPTION_NAME_FAIL -SET OPTION_NAME=%OPTION_NAME:~1% +@SET OPTION_NAME=%~3 +@(echo %OPTION_NAME%)| findstr /R /C:"[-/]..*">nul || GOTO :PARSE_OPTION_NAME_FAIL +@SET OPTION_NAME=%OPTION_NAME:~1% IF "%4" NEQ "" ( IF "%OPTION_NAME%" EQU "%OPTION_NAME:~0,1%" ( IF "!SHORT_ARG_%OPTION_NAME:~0,1%!" NEQ "" SET OPTION_NAME=!SHORT_ARG_%OPTION_NAME:~0,1%! ) ) -(echo %OPTION_NAME%)| findstr /R /C:".[ ][ ]*.">nul && GOTO :PARSE_OPTION_NAME_FAIL -(echo %~1 )| findstr /I /C:" %OPTION_NAME% ">nul || GOTO :PARSE_OPTION_NAME_FAIL +@(echo %OPTION_NAME%)| findstr /R /C:".[ ][ ]*.">nul && GOTO :PARSE_OPTION_NAME_FAIL +@(echo %~1 )| findstr /I /C:" %OPTION_NAME% ">nul || GOTO :PARSE_OPTION_NAME_FAIL endlocal & SET %~2=%OPTION_NAME% GOTO :EOF :PARSE_OPTION_NAME_FAIL @@ -166,8 +208,8 @@ endlocal & SET %~2= GOTO :EOF :MAKE_OR_CLEAN_DIRECTORY -REM Create directory if it doesn't exist or clean it if it does -REM %1 - Directory path to clean or create +@REM Create directory if it doesn't exist or clean it if it does +@REM %1 - Directory path to clean or create setlocal disableDelayedExpansion IF NOT EXIST "%~1" ( ECHO Creating %~1 @@ -179,12 +221,25 @@ for /F "usebackq delims=" %%I in (`dir /a /b "%~1"`) do ( GOTO :EOF :TOLOWER -REM Converts supplied environment variable to lowercase -REM %1 - Input/output variable name -REM Note: This is slow on very long strings, but is used only on very short ones +@REM Converts supplied environment variable to lowercase +@REM %1 - Input/output variable name +@REM Note: This is slow on very long strings, but is used only on very short ones setlocal disableDelayedExpansion -FOR %%b IN (a b c d e f g h i j k l m n o p q r s t u v w x y z) DO CALL set %~1=%%%1:%%b=%%b%% -CALL SET OUTPUT=%%%~1%% +@FOR %%b IN (a b c d e f g h i j k l m n o p q r s t u v w x y z) DO @CALL set %~1=%%%1:%%b=%%b%% +@CALL SET OUTPUT=%%%~1%% endlocal & SET %~1=%OUTPUT% GOTO :EOF +:CANONICALIZE_PATH +@REM Canonicalizes the path in the supplied variable +@REM %1 - Input/output variable containing path to canonicalize +@REM %2 - Optional base directory +setlocal +CALL :CANONICALIZE_PATH_INNER %1 %%%~1%% %2 +endlocal & SET %~1=%OUTPUT% +GOTO :EOF +:CANONICALIZE_PATH_INNER +if "%~3" NEQ "" (pushd %~3 || GOTO :EOF) +SET OUTPUT=%~f2 +if "%~3" NEQ "" popd %~3 +GOTO :EOF