build_win.bat 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. @setlocal disableDelayedExpansion enableExtensions
  2. @IF "%PS_ECHO_ON%" NEQ "" (echo on) ELSE (echo off)
  3. @GOTO :MAIN
  4. :HELP
  5. @ECHO.
  6. @ECHO Performs initial build or rebuild of the app (build) and deps (build/deps).
  7. @ECHO Default options are determined from build directories and system state.
  8. @ECHO.
  9. @ECHO Usage: build_win [-ARCH ^<arch^>] [-CONFIG ^<config^>] [-DESTDIR ^<directory^>]
  10. @ECHO [-STEPS ^<all^|all-dirty^|app^|app-dirty^|deps^|deps-dirty^>]
  11. @ECHO [-RUN ^<console^|custom^|none^|viewer^|window^>]
  12. @ECHO.
  13. @ECHO -a -ARCH Target processor architecture
  14. @ECHO Default: %PS_ARCH_HOST%
  15. @ECHO -c -CONFIG MSVC project config
  16. @ECHO Default: %PS_CONFIG_DEFAULT%
  17. @ECHO -s -STEPS Performs only the specified build steps:
  18. @ECHO all - clean and build deps and app
  19. @ECHO all-dirty - build deps and app without cleaning
  20. @ECHO app - clean and build main applications
  21. @ECHO app-dirty - build main applications without cleaning
  22. @ECHO deps - clean and build deps
  23. @ECHO deps-dirty - build deps without cleaning
  24. @ECHO Default: %PS_STEPS_DEFAULT%
  25. @ECHO -r -RUN Specifies what to perform at the run step:
  26. @ECHO console - run and wait on prusa-slicer-console.exe
  27. @ECHO custom - run and wait on your custom build/%PS_CUSTOM_RUN_FILE%
  28. @ECHO ide - open project in Visual Studio if not open (no wait)
  29. @ECHO none - run step does nothing
  30. @ECHO viewer - run prusa-gcodeviewer.exe (no wait)
  31. @ECHO window - run prusa-slicer.exe (no wait)
  32. @ECHO Default: none
  33. @ECHO -d -DESTDIR Deps destination directory
  34. @ECHO Warning: Changing destdir path will not delete the old destdir.
  35. @ECHO Default: %PS_DESTDIR_DEFAULT_MSG%
  36. @ECHO.
  37. @ECHO Examples:
  38. @ECHO.
  39. @ECHO Initial build: build_win -d "c:\src\PrusaSlicer-deps"
  40. @ECHO Build post deps change: build_win -s all
  41. @ECHO App dirty build: build_win
  42. @ECHO App dirty build ^& run: build_win -r console
  43. @ECHO All clean build ^& run: build_win -s all -r console -d "deps\build\out_deps"
  44. @ECHO.
  45. GOTO :END
  46. :MAIN
  47. REM Script constants
  48. SET START_TIME=%TIME%
  49. SET PS_START_DIR=%CD%
  50. SET PS_SOLUTION_NAME=PrusaSlicer
  51. SET PS_CHOICE_TIMEOUT=30
  52. SET PS_CUSTOM_RUN_FILE=custom_run.bat
  53. SET PS_DEPS_PATH_FILE_NAME=.DEPS_PATH.txt
  54. SET PS_DEPS_PATH_FILE=%~dp0deps\build\%PS_DEPS_PATH_FILE_NAME%
  55. SET PS_CONFIG_LIST="Debug;MinSizeRel;Release;RelWithDebInfo"
  56. REM Probe build directories and system state for reasonable default arguments
  57. pushd %~dp0
  58. SET PS_CONFIG=RelWithDebInfo
  59. SET PS_ARCH=%PROCESSOR_ARCHITECTURE:amd64=x64%
  60. CALL :TOLOWER PS_ARCH
  61. SET PS_RUN=none
  62. SET PS_DESTDIR=
  63. CALL :RESOLVE_DESTDIR_CACHE
  64. REM Set up parameters used by help menu
  65. SET EXIT_STATUS=0
  66. SET PS_CONFIG_DEFAULT=%PS_CONFIG%
  67. SET PS_ARCH_HOST=%PS_ARCH%
  68. (echo " -help /help -h /h -? /? ")| findstr /I /C:" %~1 ">nul && GOTO :HELP
  69. REM Parse arguments
  70. SET EXIT_STATUS=1
  71. SET PS_CURRENT_STEP=arguments
  72. SET PARSER_STATE=
  73. SET PARSER_FAIL=
  74. FOR %%I in (%*) DO CALL :PARSE_OPTION "ARCH CONFIG DESTDIR STEPS RUN" PARSER_STATE "%%~I"
  75. IF "%PARSER_FAIL%" NEQ "" (
  76. @ECHO ERROR: Invalid switch: %PARSER_FAIL% 1>&2
  77. GOTO :HELP
  78. )ELSE IF "%PARSER_STATE%" NEQ "" (
  79. @ECHO ERROR: Missing parameter for: %PARSER_STATE% 1>&2
  80. GOTO :HELP
  81. )
  82. REM Validate arguments
  83. SET PS_ASK_TO_CONTINUE=
  84. CALL :TOLOWER PS_ARCH
  85. SET PS_ARCH=%PS_ARCH:amd64=x64%
  86. CALL :PARSE_OPTION_VALUE %PS_CONFIG_LIST:;= % PS_CONFIG
  87. IF "%PS_CONFIG%" EQU "" GOTO :HELP
  88. REM RESOLVE_DESTDIR_CACHE must go after PS_ARCH and PS_CONFIG, but before PS STEPS
  89. CALL :RESOLVE_DESTDIR_CACHE
  90. IF "%PS_STEPS%" EQU "" SET PS_STEPS=%PS_STEPS_DEFAULT%
  91. CALL :PARSE_OPTION_VALUE "all all-dirty deps-dirty deps app-dirty app app-cmake" PS_STEPS
  92. IF "%PS_STEPS%" EQU "" GOTO :HELP
  93. (echo %PS_STEPS%)| findstr /I /C:"dirty">nul && SET PS_STEPS_DIRTY=1 || SET PS_STEPS_DIRTY=
  94. IF "%PS_STEPS%" EQU "app-cmake" SET PS_STEPS_DIRTY=1
  95. IF "%PS_DESTDIR%" EQU "" SET PS_DESTDIR=%PS_DESTDIR_CACHED%
  96. IF "%PS_DESTDIR%" EQU "" (
  97. @ECHO ERROR: Parameter required: -DESTDIR 1>&2
  98. GOTO :HELP
  99. )
  100. CALL :CANONICALIZE_PATH PS_DESTDIR "%PS_START_DIR%"
  101. IF "%PS_DESTDIR%" NEQ "%PS_DESTDIR_CACHED%" (
  102. (echo "all deps all-dirty deps-dirty")| findstr /I /C:"%PS_STEPS%">nul || (
  103. IF EXIST "%PS_DESTDIR%" (
  104. @ECHO WARNING: DESTDIR does not match cache: 1>&2
  105. @ECHO WARNING: new: %PS_DESTDIR% 1>&2
  106. @ECHO WARNING: old: %PS_DESTDIR_CACHED% 1>&2
  107. SET PS_ASK_TO_CONTINUE=1
  108. ) ELSE (
  109. @ECHO ERROR: Invalid parameter: DESTDIR=%PS_DESTDIR% 1>&2
  110. GOTO :HELP
  111. )
  112. )
  113. )
  114. SET PS_DESTDIR_DEFAULT_MSG=
  115. CALL :PARSE_OPTION_VALUE "console custom ide none viewer window" PS_RUN
  116. IF "%PS_RUN%" EQU "" GOTO :HELP
  117. IF "%PS_RUN%" NEQ "none" IF "%PS_STEPS:~0,4%" EQU "deps" (
  118. @ECHO ERROR: RUN=%PS_RUN% specified with STEPS=%PS_STEPS%
  119. @ECHO ERROR: RUN=none is the only valid option for STEPS "deps" or "deps-dirty"
  120. GOTO :HELP
  121. )
  122. REM Give the user a chance to cancel if we found something odd.
  123. IF "%PS_ASK_TO_CONTINUE%" EQU "" GOTO :BUILD_ENV
  124. @ECHO.
  125. @ECHO Unexpected parameters detected. Build paused for %PS_CHOICE_TIMEOUT% seconds.
  126. choice /T %PS_CHOICE_TIMEOUT% /C YN /D N /M "Continue"
  127. IF %ERRORLEVEL% NEQ 1 GOTO :HELP
  128. REM Set up MSVC environment
  129. :BUILD_ENV
  130. SET EXIT_STATUS=2
  131. SET PS_CURRENT_STEP=environment
  132. @ECHO **********************************************************************
  133. @ECHO ** Build Config: %PS_CONFIG%
  134. @ECHO ** Target Arch: %PS_ARCH%
  135. @ECHO ** Build Steps: %PS_STEPS%
  136. @ECHO ** Run App: %PS_RUN%
  137. @ECHO ** Deps path: %PS_DESTDIR%
  138. @ECHO ** Using Microsoft Visual Studio installation found at:
  139. SET VSWHERE=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe
  140. IF NOT EXIST "%VSWHERE%" SET VSWHERE=%ProgramFiles%\Microsoft Visual Studio\Installer\vswhere.exe
  141. FOR /F "tokens=* USEBACKQ" %%I IN (`"%VSWHERE%" -nologo -property installationPath`) DO SET MSVC_DIR=%%I
  142. @ECHO ** %MSVC_DIR%
  143. CALL "%MSVC_DIR%\Common7\Tools\vsdevcmd.bat" -arch=%PS_ARCH% -host_arch=%PS_ARCH_HOST% -app_platform=Desktop
  144. IF %ERRORLEVEL% NEQ 0 GOTO :END
  145. REM Need to reset the echo state after vsdevcmd.bat clobbers it.
  146. @IF "%PS_ECHO_ON%" NEQ "" (echo on) ELSE (echo off)
  147. IF "%PS_DRY_RUN_ONLY%" NEQ "" (
  148. @ECHO Script terminated early because PS_DRY_RUN_ONLY is set. 1>&2
  149. GOTO :END
  150. )
  151. IF /I "%PS_STEPS:~0,3%" EQU "app" GOTO :BUILD_APP
  152. REM Build deps
  153. :BUILD_DEPS
  154. SET EXIT_STATUS=3
  155. SET PS_CURRENT_STEP=deps
  156. IF "%PS_STEPS_DIRTY%" EQU "" (
  157. CALL :MAKE_OR_CLEAN_DIRECTORY deps\build "%PS_DEPS_PATH_FILE_NAME%" .vs
  158. CALL :MAKE_OR_CLEAN_DIRECTORY "%PS_DESTDIR%"
  159. )
  160. cd deps\build || GOTO :END
  161. cmake.exe .. -DDESTDIR="%PS_DESTDIR%"
  162. IF %ERRORLEVEL% NEQ 0 IF "%PS_STEPS_DIRTY%" NEQ "" (
  163. (del CMakeCache.txt && cmake.exe .. -DDESTDIR="%PS_DESTDIR%") || GOTO :END
  164. ) ELSE GOTO :END
  165. (echo %PS_DESTDIR%)> "%PS_DEPS_PATH_FILE%"
  166. msbuild /m ALL_BUILD.vcxproj /p:Configuration=%PS_CONFIG% /v:quiet || GOTO :END
  167. cd ..\..
  168. IF /I "%PS_STEPS:~0,4%" EQU "deps" GOTO :RUN_APP
  169. REM Build app
  170. :BUILD_APP
  171. SET EXIT_STATUS=4
  172. SET PS_CURRENT_STEP=app
  173. IF "%PS_STEPS_DIRTY%" EQU "" CALL :MAKE_OR_CLEAN_DIRECTORY build "%PS_CUSTOM_RUN_FILE%" .vs
  174. cd build || GOTO :END
  175. REM Make sure we have a custom batch file skeleton for the run stage
  176. set PS_CUSTOM_BAT=%PS_CUSTOM_RUN_FILE%
  177. CALL :CANONICALIZE_PATH PS_CUSTOM_BAT
  178. IF NOT EXIST %PS_CUSTOM_BAT% CALL :WRITE_CUSTOM_SCRIPT_SKELETON %PS_CUSTOM_BAT%
  179. SET PS_PROJECT_IS_OPEN=
  180. FOR /F "tokens=2 delims=," %%I in (
  181. 'tasklist /V /FI "IMAGENAME eq devenv.exe " /NH /FO CSV ^| find "%PS_SOLUTION_NAME%"'
  182. ) do SET PS_PROJECT_IS_OPEN=%%~I
  183. cmake.exe .. -DCMAKE_PREFIX_PATH="%PS_DESTDIR%\usr\local" -DCMAKE_CONFIGURATION_TYPES=%PS_CONFIG_LIST%
  184. IF %ERRORLEVEL% NEQ 0 IF "%PS_STEPS_DIRTY%" NEQ "" (
  185. (del CMakeCache.txt && cmake.exe .. -DCMAKE_PREFIX_PATH="%PS_DESTDIR%\usr\local" -DCMAKE_CONFIGURATION_TYPES=%PS_CONFIG_LIST%) || GOTO :END
  186. ) ELSE GOTO :END
  187. REM Skip the build step if we're using the undocumented app-cmake to regenerate the full config from inside devenv
  188. IF "%PS_STEPS%" NEQ "app-cmake" msbuild /m ALL_BUILD.vcxproj /p:Configuration=%PS_CONFIG% /v:quiet || GOTO :END
  189. (echo %PS_DESTDIR%)> "%PS_DEPS_PATH_FILE_FOR_CONFIG%"
  190. REM Run app
  191. :RUN_APP
  192. REM All build steps complete.
  193. CALL :DIFF_TIME ELAPSED_TIME %START_TIME% %TIME%
  194. IF "%PS_CURRENT_STEP%" NEQ "arguments" (
  195. @ECHO.
  196. @ECHO Total Build Time Elapsed %ELAPSED_TIME%
  197. )
  198. SET EXIT_STATUS=5
  199. SET PS_CURRENT_STEP=run
  200. IF "%PS_RUN%" EQU "none" GOTO :PROLOGUE
  201. cd src\%PS_CONFIG% || GOTO :END
  202. SET PS_PROJECT_IS_OPEN=
  203. FOR /F "tokens=2 delims=," %%I in (
  204. 'tasklist /V /FI "IMAGENAME eq devenv.exe " /NH /FO CSV ^| find "%PS_SOLUTION_NAME%"'
  205. ) do SET PS_PROJECT_IS_OPEN=%%~I
  206. @ECHO.
  207. @ECHO Running %PS_RUN% application...
  208. @REM icacls below is just a hack for file-not-found error handling
  209. IF "%PS_RUN%" EQU "console" (
  210. icacls prusa-slicer-console.exe >nul || GOTO :END
  211. start /wait /b prusa-slicer-console.exe
  212. ) ELSE IF "%PS_RUN%" EQU "window" (
  213. icacls prusa-slicer.exe >nul || GOTO :END
  214. start prusa-slicer.exe
  215. ) ELSE IF "%PS_RUN%" EQU "viewer" (
  216. icacls prusa-gcodeviewer.exe >nul || GOTO :END
  217. start prusa-gcodeviewer.exe
  218. ) ELSE IF "%PS_RUN%" EQU "custom" (
  219. icacls %PS_CUSTOM_BAT% >nul || GOTO :END
  220. CALL %PS_CUSTOM_BAT%
  221. ) ELSE IF "%PS_RUN%" EQU "ide" (
  222. IF "%PS_PROJECT_IS_OPEN%" NEQ "" (
  223. @ECHO WARNING: Solution is already open in Visual Studio. Skipping ide run step. 1>&2
  224. ) ELSE (
  225. @ECHO Preparing to run Visual Studio...
  226. cd ..\.. || GOTO :END
  227. REM This hack generates a single config for MSVS, guaranteeing it gets set as the active config.
  228. cmake.exe .. -DCMAKE_PREFIX_PATH="%PS_DESTDIR%\usr\local" -DCMAKE_CONFIGURATION_TYPES=%PS_CONFIG% > nul 2> nul || GOTO :END
  229. REM Now launch devenv with the single config (setting it active) and a /command switch to re-run cmake and generate the full config list
  230. start devenv.exe %PS_SOLUTION_NAME%.sln /command ^"shell /o ^^^"%~f0^^^" -d ^^^"%PS_DESTDIR%^^^" -c %PS_CONFIG% -a %PS_ARCH% -r none -s app-cmake^"
  231. REM If devenv fails to launch just directly regenerate the full config list.
  232. IF %ERRORLEVEL% NEQ 0 (
  233. cmake.exe .. -DCMAKE_PREFIX_PATH="%PS_DESTDIR%\usr\local" -DCMAKE_CONFIGURATION_TYPES=%PS_CONFIG_LIST% 2> nul 1> nul || GOTO :END
  234. )
  235. )
  236. )
  237. @REM ********** DON'T ADD ANY CODE BETWEEN THESE TWO SECTIONS **********
  238. @REM RUN_APP may hand off control, so let exit codes fall through to PROLOGUE.
  239. :PROLOGUE
  240. SET EXIT_STATUS=%ERRORLEVEL%
  241. :END
  242. @IF "%PS_ECHO_ON%%PS_DRY_RUN_ONLY%" NEQ "" (
  243. @ECHO **********************************************************************
  244. @ECHO ** Script Parameters:
  245. @ECHO **********************************************************************
  246. @SET PS_
  247. )
  248. IF "%EXIT_STATUS%" NEQ "0" (
  249. IF "%PS_CURRENT_STEP%" NEQ "arguments" (
  250. @ECHO.
  251. @ECHO ERROR: *** Build process failed at %PS_CURRENT_STEP% step. *** 1>&2
  252. )
  253. ) ELSE (
  254. @ECHO All steps completed successfully.
  255. )
  256. popd
  257. exit /B %EXIT_STATUS%
  258. GOTO :EOF
  259. REM Functions and stubs start here.
  260. :RESOLVE_DESTDIR_CACHE
  261. @REM Resolves all DESTDIR cache values and sets PS_STEPS_DEFAULT
  262. @REM Note: This just sets global variables, so it doesn't use setlocal.
  263. SET PS_DEPS_PATH_FILE_FOR_CONFIG=%~dp0build\.vs\%PS_ARCH%\%PS_CONFIG%\%PS_DEPS_PATH_FILE_NAME%
  264. mkdir "%~dp0build\.vs\%PS_ARCH%\%PS_CONFIG%" > nul 2> nul
  265. REM Copy a legacy file if we don't have one in the proper location.
  266. echo f|xcopy /D "%~dp0build\%PS_ARCH%\%PS_CONFIG%\%PS_DEPS_PATH_FILE_NAME%" "%PS_DEPS_PATH_FILE_FOR_CONFIG%"
  267. CALL :CANONICALIZE_PATH PS_DEPS_PATH_FILE_FOR_CONFIG
  268. IF EXIST "%PS_DEPS_PATH_FILE_FOR_CONFIG%" (
  269. FOR /F "tokens=* USEBACKQ" %%I IN ("%PS_DEPS_PATH_FILE_FOR_CONFIG%") DO (
  270. SET PS_DESTDIR_CACHED=%%I
  271. SET PS_DESTDIR_DEFAULT_MSG=%%I
  272. )
  273. SET PS_STEPS_DEFAULT=app-dirty
  274. ) ELSE IF EXIST "%PS_DEPS_PATH_FILE%" (
  275. FOR /F "tokens=* USEBACKQ" %%I IN ("%PS_DEPS_PATH_FILE%") DO (
  276. SET PS_DESTDIR_CACHED=%%I
  277. SET PS_DESTDIR_DEFAULT_MSG=%%I
  278. )
  279. SET PS_STEPS_DEFAULT=app
  280. ) ELSE (
  281. SET PS_DESTDIR_CACHED=
  282. SET PS_DESTDIR_DEFAULT_MSG=Cache missing. Argument required.
  283. SET PS_STEPS_DEFAULT=all
  284. )
  285. GOTO :EOF
  286. :PARSE_OPTION
  287. @REM Argument parser called for each argument
  288. @REM %1 - Valid option list
  289. @REM %2 - Variable name for parser state; must be unset when parsing finished
  290. @REM %3 - Current argument value
  291. @REM PARSER_FAIL will be set on an error
  292. @REM Note: Must avoid delayed expansion since filenames may contain ! character
  293. setlocal disableDelayedExpansion
  294. IF "%PARSER_FAIL%" NEQ "" GOTO :EOF
  295. CALL SET LAST_ARG=%%%2%%
  296. IF "%LAST_ARG%" EQU "" (
  297. CALL :PARSE_OPTION_NAME %1 %~2 %~3 1
  298. SET ARG_TYPE=NAME
  299. ) ELSE (
  300. SET PS_SET_COMMAND=SET PS_%LAST_ARG%=%~3
  301. SET ARG_TYPE=LAST_ARG
  302. SET %~2=
  303. )
  304. CALL SET LAST_ARG=%%%2%%
  305. IF "%LAST_ARG%%ARG_TYPE%" EQU "NAME" SET PARSER_FAIL=%~3
  306. (
  307. endlocal
  308. SET PARSER_FAIL=%PARSER_FAIL%
  309. SET %~2=%LAST_ARG%
  310. %PS_SET_COMMAND%
  311. )
  312. GOTO :EOF
  313. :PARSE_OPTION_VALUE
  314. setlocal disableDelayedExpansion
  315. @REM Parses value and verifies it is within the supplied list
  316. @REM %1 - Valid option list
  317. @REM %2 - In/out variable name; unset on error
  318. CALL SET NAME=%~2
  319. CALL SET SAVED_VALUE=%%%NAME%%%
  320. CALL :PARSE_OPTION_NAME %1 %NAME% -%SAVED_VALUE%
  321. CALL SET NEW_VALUE=%%%NAME%%%
  322. IF "%NEW_VALUE%" EQU "" (
  323. @ECHO ERROR: Invalid parameter: %NAME:~3%=%SAVED_VALUE% 1>&2
  324. )
  325. endlocal & SET %NAME%=%NEW_VALUE%
  326. GOTO :EOF
  327. :PARSE_OPTION_NAME
  328. @REM Parses an option name
  329. @REM %1 - Valid option list
  330. @REM %2 - Out variable name; unset on error
  331. @REM %3 - Current argument value
  332. @REM %4 - Boolean indicating single character switches are valid
  333. @REM Note: Delayed expansion safe because ! character is invalid in option name
  334. setlocal enableDelayedExpansion
  335. IF "%4" NEQ "" FOR %%I IN (%~1) DO @(
  336. SET SHORT_NAME=%%~I
  337. SET SHORT_ARG_!SHORT_NAME:~0,1!=%%~I
  338. )
  339. @SET OPTION_NAME=%~3
  340. @(echo %OPTION_NAME%)| findstr /R /C:"[-/]..*">nul || GOTO :PARSE_OPTION_NAME_FAIL
  341. @SET OPTION_NAME=%OPTION_NAME:~1%
  342. IF "%4" NEQ "" (
  343. IF "%OPTION_NAME%" EQU "%OPTION_NAME:~0,1%" (
  344. IF "!SHORT_ARG_%OPTION_NAME:~0,1%!" NEQ "" SET OPTION_NAME=!SHORT_ARG_%OPTION_NAME:~0,1%!
  345. )
  346. )
  347. @(echo %OPTION_NAME%)| findstr /R /C:".[ ][ ]*.">nul && GOTO :PARSE_OPTION_NAME_FAIL
  348. @(echo %~1 )| findstr /I /C:" %OPTION_NAME% ">nul || GOTO :PARSE_OPTION_NAME_FAIL
  349. FOR %%I IN (%~1) DO SET OPTION_NAME=!OPTION_NAME:%%~I=%%~I!
  350. endlocal & SET %~2=%OPTION_NAME%
  351. GOTO :EOF
  352. :PARSE_OPTION_NAME_FAIL
  353. endlocal & SET %~2=
  354. GOTO :EOF
  355. :MAKE_OR_CLEAN_DIRECTORY
  356. @REM Create directory if it doesn't exist or clean it if it does
  357. @REM %1 - Directory path to clean or create
  358. @REM %* - Optional list of files/dirs to keep (in the base directory only)
  359. setlocal disableDelayedExpansion
  360. IF NOT EXIST "%~1" (
  361. @ECHO Creating %~1
  362. mkdir "%~1" && (
  363. endlocal
  364. GOTO :EOF
  365. )
  366. )
  367. @ECHO Cleaning %~1 ...
  368. SET KEEP_LIST=
  369. :MAKE_OR_CLEAN_DIRECTORY_ARG_LOOP
  370. IF "%~2" NEQ "" (
  371. SET KEEP_LIST=%KEEP_LIST% "%~2"
  372. SHIFT /2
  373. GOTO :MAKE_OR_CLEAN_DIRECTORY_ARG_LOOP
  374. )
  375. for /F "usebackq delims=" %%I in (`dir /a /b "%~1"`) do (
  376. (echo %KEEP_LIST%)| findstr /I /L /C:"\"%%I\"">nul || (
  377. rmdir /s /q "%~1\%%I" 2>nul ) || del /q /f "%~1\%%I"
  378. )
  379. endlocal
  380. GOTO :EOF
  381. :TOLOWER
  382. @REM Converts supplied environment variable to lowercase
  383. @REM %1 - Input/output variable name
  384. @REM Note: This is slow on very long strings, but is used only on very short ones
  385. setlocal disableDelayedExpansion
  386. @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%%
  387. @CALL SET OUTPUT=%%%~1%%
  388. endlocal & SET %~1=%OUTPUT%
  389. GOTO :EOF
  390. :CANONICALIZE_PATH
  391. @REM Canonicalizes the path in the supplied variable
  392. @REM %1 - Input/output variable containing path to canonicalize
  393. @REM %2 - Optional base directory
  394. setlocal
  395. CALL :CANONICALIZE_PATH_INNER %1 %%%~1%% %2
  396. endlocal & SET %~1=%OUTPUT%
  397. GOTO :EOF
  398. :CANONICALIZE_PATH_INNER
  399. if "%~3" NEQ "" (pushd %3 || GOTO :EOF)
  400. SET OUTPUT=%~f2
  401. if "%~3" NEQ "" popd
  402. GOTO :EOF
  403. :DIFF_TIME
  404. @REM Calculates elapsed time between two timestamps (TIME environment variable format)
  405. @REM %1 - Output variable
  406. @REM %2 - Start time
  407. @REM %3 - End time
  408. setlocal EnableDelayedExpansion
  409. set START_ARG=%2
  410. set END_ARG=%3
  411. set END=!END_ARG:%TIME:~8,1%=%%100)*100+1!
  412. set START=!START_ARG:%TIME:~8,1%=%%100)*100+1!
  413. set /A DIFF=((((10!END:%TIME:~2,1%=%%100)*60+1!%%100)-((((10!START:%TIME:~2,1%=%%100)*60+1!%%100), DIFF-=(DIFF^>^>31)*24*60*60*100
  414. set /A CC=DIFF%%100+100,DIFF/=100,SS=DIFF%%60+100,DIFF/=60,MM=DIFF%%60+100,HH=DIFF/60+100
  415. @endlocal & set %1=%HH:~1%%TIME:~2,1%%MM:~1%%TIME:~2,1%%SS:~1%%TIME:~8,1%%CC:~1%
  416. @GOTO :EOF
  417. :WRITE_CUSTOM_SCRIPT_SKELETON
  418. @REM Writes the following text to the supplied file
  419. @REM %1 - Output filename
  420. setlocal
  421. @(
  422. ECHO @ECHO.
  423. ECHO @ECHO ********************************************************************************
  424. ECHO @ECHO ** This is a custom run script skeleton.
  425. ECHO @ECHO ********************************************************************************
  426. ECHO @ECHO.
  427. ECHO @ECHO ********************************************************************************
  428. ECHO @ECHO ** The working directory is:
  429. ECHO @ECHO ********************************************************************************
  430. ECHO dir
  431. ECHO @ECHO.
  432. ECHO @ECHO ********************************************************************************
  433. ECHO @ECHO ** The environment is:
  434. ECHO @ECHO ********************************************************************************
  435. ECHO set
  436. ECHO @ECHO.
  437. ECHO @ECHO ********************************************************************************
  438. ECHO @ECHO ** Edit or replace this script to run custom steps after a successful build:
  439. ECHO @ECHO ** %~1
  440. ECHO @ECHO ********************************************************************************
  441. ECHO @ECHO.
  442. ) > "%~1"
  443. endlocal
  444. GOTO :EOF