build.cmd 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866
  1. :: Make sure the extensions are enabled
  2. @verify other 2>nul
  3. @setlocal EnableDelayedExpansion
  4. @if errorlevel 1 (
  5. call :print_usage "Failed to enable extensions"
  6. exit /b 1
  7. )
  8. ::Change the code page to unicode
  9. @chcp 65001 1>nul 2>nul
  10. @if errorlevel 1 (
  11. call :print_usage "Failed to change the code page to unicode"
  12. exit /b 1
  13. )
  14. :: Set up some global variables
  15. @set project=civetweb
  16. @set "script_name=%~nx0"
  17. @set "script_folder=%~dp0"
  18. @set "script_folder=%script_folder:~0,-1%"
  19. @set "output_path=%script_folder%\output"
  20. @set "build_path=%output_path%\build"
  21. @set "install_path=%output_path%\install"
  22. @set build_shared=OFF
  23. @set build_type=Release
  24. @set dependency_path=%TEMP%\%project%-build-dependencies
  25. :: Check the command line parameters
  26. @set logging_level=1
  27. @set "options=%* "
  28. @if not "!options!"=="!options:/? =!" set usage="Convenience script to build %project% with CMake"
  29. @for %%a in (%options%) do @(
  30. @set arg=%%~a
  31. @set arg=!arg: =!
  32. @set one=!arg:~0,1!
  33. @set two=!arg:~0,2!
  34. @if /i [!arg!] == [/q] set quiet=true
  35. @if /i [!two!] == [/v] call :verbosity "!arg!"
  36. @if /i [!arg!] == [/s] set build_shared=ON
  37. @if /i [!arg!] == [/d] set build_type=Debug
  38. @if /i not [!one!] == [/] (
  39. if not defined generator (
  40. set generator=!arg!
  41. ) else (
  42. set usage="Too many generators: !method! !arg!" ^
  43. "There should only be one generator parameter"
  44. )
  45. )
  46. )
  47. @if defined quiet (
  48. set logging_level=0
  49. )
  50. @if not defined generator (
  51. set generator=MSVC
  52. )
  53. @if /i not [%generator%] == [MinGW] (
  54. if /i not [%generator%] == [MSVC] (
  55. call :print_usage "Invalid argument: %generator%"
  56. exit /b 1
  57. )
  58. )
  59. :: Set up the logging
  60. @set log_folder=%output_path%\logs
  61. @call :iso8601 timestamp
  62. @set log_path=%log_folder%\%timestamp%.log
  63. @set log_keep=10
  64. :: Only keep a certain amount of logs
  65. @set /a "log_keep=log_keep-1"
  66. @if not exist %log_folder% @mkdir %log_folder%
  67. @for /f "skip=%log_keep%" %%f in ('dir /b /o-D /tc %log_folder%') do @(
  68. call :log 4 "Removing old log file %log_folder%\%%f"
  69. del %log_folder%\%%f
  70. )
  71. :: Set up some more global variables
  72. @call :architecture arch
  73. @call :windows_version win_ver win_ver_major win_ver_minor win_ver_rev
  74. @call :script_source script_source
  75. @if [%script_source%] == [explorer] (
  76. set /a "logging_level=logging_level+1"
  77. )
  78. :: Print the usage or start the script
  79. @set exit_code=0
  80. @if defined usage (
  81. call :print_usage %usage%
  82. ) else (
  83. call :main
  84. @if errorlevel 1 (
  85. @call :log 0 "Failed to build the %project% project"
  86. @set exit_code=1
  87. )
  88. )
  89. :: Tell the user where the built files are
  90. @call :log 5
  91. @call :log 0 "The built files are available in %install_path%"
  92. :: Stop the script if the user double clicked
  93. @if [%script_source%] == [explorer] (
  94. pause
  95. )
  96. @exit /b %exit_code%
  97. @endlocal
  98. @goto :eof
  99. :: -------------------------- Functions start here ----------------------------
  100. :main - Main function that performs the build
  101. @setlocal
  102. @call :log 6
  103. @call :log 2 "Welcome to the %project% build script"
  104. @call :log 6 "------------------------------------"
  105. @call :log 6
  106. @call :log 2 "This script builds the project using CMake"
  107. @call :log 6
  108. @call :log 2 "Generating %generator%..."
  109. @call :log 6
  110. @set methods=dependencies ^
  111. generate ^
  112. build ^
  113. install
  114. @for %%m in (%methods%) do @(
  115. call :log 3 "Executing the '%%m' method"
  116. call :log 8
  117. call :%%~m
  118. if errorlevel 1 (
  119. call :log 0 "Failed to complete the '%%~m' dependency routine"
  120. call :log 0 "View the log at %log_path%"
  121. exit /b 1
  122. )
  123. )
  124. @call :log 6 "------------------------------------"
  125. @call :log 2 "Build complete"
  126. @call :log 6
  127. @endlocal
  128. @goto :eof
  129. :print_usage - Prints the usage of the script
  130. :: %* - message to print, each argument on it's own line
  131. @setlocal
  132. @for %%a in (%*) do @echo.%%~a
  133. @echo.
  134. @echo.build [/?][/v[v...]^|/q][MinGW^|MSVC]
  135. @echo.
  136. @echo. [MinGW^|(MSVC)]
  137. @echo. Builds the library with one of the compilers
  138. @echo. /s Builds shared libraries
  139. @echo. /d Builds a debug variant of the project
  140. @echo. /v Sets the output to be more verbose
  141. @echo. /v[v...] Extra verbosity, /vv, /vvv, etc
  142. @echo. /q Quiets the output
  143. @echo. /? Shows this usage message
  144. @echo.
  145. @endlocal
  146. @goto :eof
  147. :dependencies - Installs any prerequisites for the build
  148. @setlocal EnableDelayedExpansion
  149. @if errorlevel 1 (
  150. call :log 0 "Failed to enable extensions"
  151. exit /b 1
  152. )
  153. @call :log 5
  154. @call :log 0 "Installing dependencies for %generator%"
  155. @if /i [%generator%] == [MinGW] (
  156. call :mingw compiler_path
  157. @if errorlevel 1 (
  158. @call :log 5
  159. @call :log 0 "Failed to find MinGW"
  160. @exit /b 1
  161. )
  162. set "PATH=!compiler_path!;%PATH%"
  163. @call :find_in_path gcc_executable gcc.exe
  164. @if errorlevel 1 (
  165. @call :log 5
  166. @call :log 0 "Failed to find gcc.exe"
  167. @exit /b 1
  168. )
  169. )
  170. @if [%reboot_required%] equ [1] call :reboot
  171. @endlocal & set "PATH=%PATH%"
  172. @goto :eof
  173. :generate - Uses CMake to generate the build files
  174. @setlocal EnableDelayedExpansion
  175. @if errorlevel 1 (
  176. call :log 0 "Failed to enable extensions"
  177. exit /b 1
  178. )
  179. @call :log 5
  180. @call :log 0 "Generating CMake files for %generator%"
  181. @call :cmake cmake_executable
  182. @if errorlevel 1 (
  183. @call :log 5
  184. @call :log 0 "Need CMake to create the build files"
  185. @exit /b 1
  186. )
  187. @if /i [%generator%] == [MinGW] @(
  188. @set "generator_var=-G "MinGW Makefiles^""
  189. )
  190. @if /i [%generator%] == [MSVC] @(
  191. rem We could figure out the correct MSVS generator here
  192. )
  193. @call :iso8601 iso8601
  194. @set output=%temp%\cmake-%iso8601%.log
  195. @if not exist %build_path% mkdir %build_path%
  196. @cd %build_path%
  197. @"%cmake_executable%" ^
  198. !generator_var! ^
  199. -DCMAKE_BUILD_TYPE=!build_type! ^
  200. -DBUILD_SHARED_LIBS=!build_shared! ^
  201. "%script_folder%" > "%output%"
  202. @if errorlevel 1 (
  203. @call :log 5
  204. @call :log 0 "Failed to generate build files with CMake"
  205. @call :log_append "%output%"
  206. @cd %script_folder%
  207. @exit /b 1
  208. )
  209. @cd %script_folder%
  210. @endlocal
  211. @goto :eof
  212. :build - Builds the library
  213. @setlocal EnableDelayedExpansion
  214. @if errorlevel 1 (
  215. call :log 0 "Failed to enable extensions"
  216. exit /b 1
  217. )
  218. @call :log 5
  219. @call :log 0 "Building %project% with %generator%"
  220. @if /i [%generator%] == [MinGW] @(
  221. @call :find_in_path mingw32_make_executable mingw32-make.exe
  222. @if errorlevel 1 (
  223. @call :log 5
  224. @call :log 0 "Failed to find mingw32-make"
  225. @exit /b 1
  226. )
  227. @set "build_command=^"!mingw32_make_executable!^" all test"
  228. )
  229. @if /i [%generator%] == [MSVC] @(
  230. @call :msbuild msbuild_executable
  231. @if errorlevel 1 (
  232. @call :log 5
  233. @call :log 0 "Failed to find MSBuild"
  234. @exit /b 1
  235. )
  236. @set "build_command=^"!msbuild_executable!^" /m:4 /p:Configuration=%build_type% %project%.sln"
  237. )
  238. @if not defined build_command (
  239. @call :log 5
  240. @call :log 0 "No build command for %generator%"
  241. @exit /b 1
  242. )
  243. @cd %build_path%
  244. @call :iso8601 iso8601
  245. @set output=%temp%\build-%iso8601%.log
  246. @call :log 7
  247. @call :log 2 "Build command: %build_command:"=%"
  248. @%build_command% > "%output%"
  249. @if errorlevel 1 (
  250. @call :log_append "%output%"
  251. @call :log 5
  252. @call :log 0 "Failed to complete the build"
  253. @exit /b 1
  254. )
  255. @call :log_append "%output%"
  256. @cd %script_folder%
  257. @endlocal
  258. @goto :eof
  259. :install - Installs the built files
  260. @setlocal
  261. @call :log 5
  262. @call :log 0 "Installing built files"
  263. @call :cmake cmake_executable
  264. @if errorlevel 1 (
  265. @call :log 5
  266. @call :log 0 "Need CMake to install the built files"
  267. @exit /b 1
  268. )
  269. @call :iso8601 iso8601
  270. @set output=%temp%\install-%iso8601%.log
  271. @"%cmake_executable%" ^
  272. "-DCMAKE_INSTALL_PREFIX=%install_path%" ^
  273. -P "%build_path%/cmake_install.cmake" ^
  274. > "%output%"
  275. @if errorlevel 1 (
  276. @call :log_append "%output%"
  277. @call :log 5
  278. @call :log 0 "Failed to install the files"
  279. @exit /b 1
  280. )
  281. @call :log_append "%output%"
  282. @endlocal
  283. @goto :eof
  284. :script_source - Determines if the script was ran from the cli or explorer
  285. :: %1 - The return variable [cli|explorer]
  286. @verify other 2>nul
  287. @setlocal EnableDelayedExpansion
  288. @if errorlevel 1 (
  289. call :log 0 "Failed to enable extensions"
  290. exit /b 1
  291. )
  292. @call :log 3 "Attempting to detect the script source"
  293. @echo "The invocation command was: '%cmdcmdline%'" >> %log_path%
  294. @for /f "tokens=1-3,*" %%a in ("%cmdcmdline%") do @(
  295. set cmd=%%~a
  296. set arg1=%%~b
  297. set arg2=%%~c
  298. set rest=%%~d
  299. )
  300. @set quote="
  301. @if "!arg2:~0,1!" equ "!quote!" (
  302. if "!arg2:~-1!" neq "!quote!" (
  303. set "arg2=!arg2:~1!"
  304. )
  305. )
  306. @call :log 4 "cmd = %cmd%"
  307. @call :log 4 "arg1 = %arg1%"
  308. @call :log 4 "arg2 = %arg2%"
  309. @call :log 4 "rest = %rest%"
  310. @call :log 4 "src = %~f0"
  311. @if /i "%arg2%" == "call" (
  312. set script_source=cli
  313. ) else (
  314. @if /i "%arg1%" == "/c" (
  315. set script_source=explorer
  316. ) else (
  317. set script_source=cli
  318. )
  319. )
  320. @call :log 3 "The script was invoked from %script_source%"
  321. @endlocal & set "%~1=%script_source%"
  322. @goto :eof
  323. :architecture - Finds the system architecture
  324. :: %1 - The return variable [x86|x86_64]
  325. @setlocal
  326. @call :log 3 "Determining the processor architecture"
  327. @set "key=HKLM\System\CurrentControlSet\Control\Session Manager\Environment"
  328. @set "var=PROCESSOR_ARCHITECTURE"
  329. @for /f "skip=2 tokens=2,*" %%a in ('reg query "%key%" /v "%var%"') do @set "arch=%%b"
  330. @if "%arch%" == "AMD64" set arch=x86_64
  331. @call :log 4 "arch = %arch%"
  332. @endlocal & set "%~1=%arch%"
  333. @goto :eof
  334. :md5 - Gets the MD5 checksum for a file
  335. :: %1 - The hash
  336. :: %2 - The file path
  337. @setlocal
  338. @set var=%~1
  339. @set file_path=%~2
  340. @if [%var%] == [] exit /b 1
  341. @if "%file_path%" == "" exit /b 1
  342. @if not exist "%file_path%" exit /b 1
  343. @for /f "skip=3 tokens=1,*" %%a in ('powershell Get-FileHash -Algorithm MD5 "'%file_path%'"') do @set hash=%%b
  344. @if not defined hash (
  345. call :log 6
  346. call :log 0 "Failed to get MD5 hash for %file_path%"
  347. exit /b 1
  348. )
  349. @endlocal & set "%var%=%hash: =%"
  350. @goto :eof
  351. :windows_version - Checks the windows version
  352. :: %1 - The windows version
  353. :: %2 - The major version number return variable
  354. :: %3 - The minor version number return variable
  355. :: %4 - The revision version number return variable
  356. @setlocal
  357. @call :log 3 "Retrieving the Windows version"
  358. @for /f "tokens=2 delims=[]" %%x in ('ver') do @set win_ver=%%x
  359. @set win_ver=%win_ver:Version =%
  360. @set win_ver_major=%win_ver:~0,1%
  361. @set win_ver_minor=%win_ver:~2,1%
  362. @set win_ver_rev=%win_ver:~4%
  363. @call :log 4 "win_ver = %win_ver%"
  364. @endlocal & set "%~1=%win_ver%" ^
  365. & set "%~2=%win_ver_major%" ^
  366. & set "%~3=%win_ver_minor%" ^
  367. & set "%~4=%win_ver_rev%"
  368. @goto :eof
  369. :find_in_path - Finds a program of file in the PATH
  370. @setlocal
  371. @set var=%~1
  372. @set file=%~2
  373. @if [%var%] == [] exit /b 1
  374. @if [%file%] == [] exit /b 1
  375. @call :log 3 "Searching PATH for %file%"
  376. @for %%x in ("%file%") do @set "file_path=%%~f$PATH:x"
  377. @if not defined file_path exit /b 1
  378. @endlocal & set "%var%=%file_path%"
  379. @goto :eof
  380. :administrator_check - Checks for administrator privileges
  381. @setlocal
  382. @call :log 2 "Checking for administrator privileges"
  383. @set "key=HKLM\Software\VCA\Tool Chain\Admin Check"
  384. @reg add "%key%" /v Elevated /t REG_DWORD /d 1 /f > nul 2>&1
  385. @if errorlevel 1 exit /b 1
  386. @reg delete "%key%" /va /f > nul 2>&1
  387. @endlocal
  388. @goto :eof
  389. :log_append - Appends another file into the current logging file
  390. :: %1 - the file_path to the file to concatenate
  391. @setlocal
  392. @set "file_path=%~1"
  393. @if [%file_path%] == [] exit /b 1
  394. @call :log 3 "Appending to log: %file_path%"
  395. @call :iso8601 iso8601
  396. @set "temp_log=%temp%\append-%iso8601%.log"
  397. @call :log 4 "Using temp file %temp_log%"
  398. @type "%log_path%" "%file_path%" > "%temp_log%" 2>nul
  399. @move /y "%temp_log%" "%log_path%" 1>nul
  400. @del "%file_path%" 2>nul
  401. @del "%temp_log%" 2>nul
  402. @endlocal
  403. @goto :eof
  404. :iso8601 - Returns the current time in ISO8601 format
  405. :: %1 - the return variable
  406. :: %2 - format [extended|basic*]
  407. :: iso8601 - contains the resulting timestamp
  408. @setlocal
  409. @wmic Alias /? >NUL 2>&1 || @exit /b 1
  410. @set "var=%~1"
  411. @if "%var%" == "" @exit /b 1
  412. @set "format=%~2"
  413. @if "%format%" == "" set format=basic
  414. @for /F "skip=1 tokens=1-6" %%g IN ('wmic Path Win32_UTCTime Get Day^,Hour^,Minute^,Month^,Second^,Year /Format:table') do @(
  415. @if "%%~l"=="" goto :iso8601_done
  416. @set "yyyy=%%l"
  417. @set "mm=00%%j"
  418. @set "dd=00%%g"
  419. @set "hour=00%%h"
  420. @set "minute=00%%i"
  421. @set "seconds=00%%k"
  422. )
  423. :iso8601_done
  424. @set mm=%mm:~-2%
  425. @set dd=%dd:~-2%
  426. @set hour=%hour:~-2%
  427. @set minute=%minute:~-2%
  428. @set seconds=%seconds:~-2%
  429. @if /i [%format%] == [extended] (
  430. set iso8601=%yyyy%-%mm%-%dd%T%hour%:%minute%:%seconds%Z
  431. ) else (
  432. if /i [%format%] == [basic] (
  433. set iso8601=%yyyy%%mm%%dd%T%hour%%minute%%seconds%Z
  434. ) else (
  435. @exit /b 1
  436. )
  437. )
  438. @set iso8601=%iso8601: =0%
  439. @endlocal & set %var%=%iso8601%
  440. @goto :eof
  441. :verbosity - Processes the verbosity parameter '/v[v...]
  442. :: %1 - verbosity given on the command line
  443. :: logging_level - set to the number of v's
  444. @setlocal
  445. @set logging_level=0
  446. @set verbosity=%~1
  447. :verbosity_loop
  448. @set verbosity=%verbosity:~1%
  449. @if not [%verbosity%] == [] @(
  450. set /a "logging_level=logging_level+1"
  451. goto verbosity_loop
  452. )
  453. @endlocal & set logging_level=%logging_level%
  454. @goto :eof
  455. :log - Logs a message, depending on verbosity
  456. :: %1 - level
  457. :: [0-4] for CLI logging
  458. :: [5-9] for GUI logging
  459. :: %2 - message to print
  460. @setlocal
  461. @set "level=%~1"
  462. @set "msg=%~2"
  463. @if "%log_folder%" == "" (
  464. echo Logging was used to early in the script, log_folder isn't set yet
  465. goto :eof
  466. )
  467. @if "%log_path%" == "" (
  468. echo Logging was used to early in the script, log_path isn't set yet
  469. goto :eof
  470. )
  471. @if not exist "%log_folder%" mkdir "%log_folder%"
  472. @if not exist "%log_path%" echo. 1>nul 2>"%log_path%"
  473. @echo.%msg% >> "%log_path%"
  474. @if %level% geq 5 (
  475. @if [%script_source%] == [explorer] (
  476. set /a "level=level-5"
  477. ) else (
  478. @goto :eof
  479. )
  480. )
  481. @if "%logging_level%" == "" (
  482. echo Logging was used to early in the script, logging_level isn't set yet
  483. goto :eof
  484. )
  485. @if %logging_level% geq %level% echo.%msg% 1>&2
  486. @endlocal
  487. @goto :eof
  488. :start_browser - Opens the default browser to a URL
  489. :: %1 - the url to open
  490. @setlocal
  491. @set url=%~1
  492. @call :log 4 "Opening default browser: %url%"
  493. @start %url%
  494. @endlocal
  495. @goto :eof
  496. :find_cmake - Finds cmake on the command line or in the registry
  497. :: %1 - the cmake file path
  498. @setlocal
  499. @set var=%~1
  500. @if [%var%] == [] exit /b 1
  501. @call :log 6
  502. @call :log 6 "Finding CMake"
  503. @call :log 6 "--------------"
  504. @call :find_in_path cmake_executable cmake.exe
  505. @if not errorlevel 1 goto found_cmake
  506. @for /l %%i in (5,-1,0) do @(
  507. @for /l %%j in (9,-1,0) do @(
  508. @for /l %%k in (9,-1,0) do @(
  509. @for %%l in (HKCU HKLM) do @(
  510. @for %%m in (SOFTWARE SOFTWARE\Wow6432Node) do @(
  511. @reg query "%%l\%%m\Kitware\CMake %%i.%%j.%%k" /ve > nul 2>nul
  512. @if not errorlevel 1 (
  513. @for /f "skip=2 tokens=2,*" %%a in ('reg query "%%l\%%m\Kitware\CMake %%i.%%j.%%k" /ve') do @(
  514. @if exist "%%b\bin\cmake.exe" (
  515. @set "cmake_executable=%%b\bin\cmake.exe"
  516. goto found_cmake
  517. )
  518. )
  519. )
  520. )))))
  521. @call :log 5
  522. @call :log 0 "Failed to find cmake"
  523. @exit /b 1
  524. :found_cmake
  525. @endlocal & set "%var%=%cmake_executable%"
  526. @goto :eof
  527. :cmake - Finds cmake and installs it if necessary
  528. :: %1 - the cmake file path
  529. @setlocal
  530. @set var=%~1
  531. @if [%var%] == [] exit /b 1
  532. @call :log 6
  533. @call :log 6 "Checking for CMake"
  534. @call :log 6 "------------------"
  535. @call :find_cmake cmake_executable cmake.exe
  536. @if not errorlevel 1 goto got_cmake
  537. @set checksum=C00267A3D3D9619A7A2E8FA4F46D7698
  538. @set version=3.2.2
  539. @call :install_nsis cmake http://www.cmake.org/files/v%version:~0,3%/cmake-%version%-win32-x86.exe %checksum%
  540. @if errorlevel 1 (
  541. call :log 5
  542. call :log 0 "Failed to install cmake"
  543. @exit /b 1
  544. )
  545. @call :find_cmake cmake_executable cmake.exe
  546. @if not errorlevel 1 goto got_cmake
  547. @call :log 5
  548. @call :log 0 "Failed to check for cmake"
  549. @exit /b 1
  550. :got_cmake
  551. @endlocal & set "%var%=%cmake_executable%"
  552. @goto :eof
  553. :mingw - Finds MinGW, installing it if needed
  554. :: %1 - the compiler path that should be added to PATH
  555. @setlocal EnableDelayedExpansion
  556. @if errorlevel 1 (
  557. @call :log 5
  558. @call :log 0 "Failed to enable extensions"
  559. @exit /b 1
  560. )
  561. @set var=%~1
  562. @if [%var%] == [] exit /b 1
  563. @call :log 6
  564. @call :log 6 "Checking for MinGW"
  565. @call :log 6 "------------------"
  566. @call :find_in_path gcc_executable gcc.exe
  567. @if not errorlevel 1 (
  568. @for %%a in ("%gcc_executable%") do @set "compiler_path=%%~dpa"
  569. goto got_mingw
  570. )
  571. @call :log 7
  572. @call :log 2 "Downloading MinGW"
  573. @if %logging_level% leq 1 set "logging=/q"
  574. @if %logging_level% gtr 1 set "logging=/v"
  575. @set output_path=
  576. @for /f %%a in ('call
  577. "%script_folder%\mingw.cmd"
  578. %logging%
  579. /arch "%arch%"
  580. "%dependency_path%"'
  581. ) do @set "compiler_path=%%a\"
  582. @if not defined compiler_path (
  583. @call :log_append "%output%"
  584. @call :log 5
  585. @call :log 0 "Failed to download MinGW"
  586. @exit /b 1
  587. )
  588. :got_mingw
  589. @call :log 5
  590. @call :log 0 "Found MinGW: %compiler_path%gcc.exe"
  591. @endlocal & set "%var%=%compiler_path%"
  592. @goto :eof
  593. :msbuild - Finds MSBuild
  594. :: %1 - the path to MSBuild executable
  595. @setlocal
  596. @set var=%~1
  597. @if [%var%] == [] exit /b 1
  598. @call :find_in_path msbuild_executable msbuild.exe
  599. @if not errorlevel 1 goto got_msbuild
  600. @for /l %%i in (20,-1,4) do @(
  601. @for /l %%j in (9,-1,0) do @(
  602. @for %%k in (HKCU HKLM) do @(
  603. @for %%l in (SOFTWARE SOFTWARE\Wow6432Node) do @(
  604. @reg query "%%k\%%l\Microsoft\MSBuild\%%i.%%j" /v MSBuildOverrideTasksPath > nul 2>nul
  605. @if not errorlevel 1 (
  606. @for /f "skip=2 tokens=2,*" %%a in ('reg query "%%k\%%l\Microsoft\MSBuild\%%i.%%j" /v MSBuildOverrideTasksPath') do @(
  607. @if exist "%%bmsbuild.exe" (
  608. @set "msbuild_executable=%%bmsbuild.exe"
  609. goto got_msbuild
  610. )
  611. )
  612. )
  613. ))))
  614. @call :log 5
  615. @call :log 0 "Failed to check for MSBuild"
  616. @exit /b 1
  617. :got_msbuild
  618. @endlocal & set "%var%=%msbuild_executable%"
  619. @goto :eof
  620. :download - Downloads a file from the internet
  621. :: %1 - the url of the file to download
  622. :: %2 - the file to download to
  623. :: %3 - the MD5 checksum of the file (optional)
  624. @setlocal EnableDelayedExpansion
  625. @if errorlevel 1 (
  626. call :print_usage "Failed to enable extensions"
  627. exit /b 1
  628. )
  629. @set url=%~1
  630. @set file_path=%~2
  631. @set checksum=%~3
  632. @for %%a in (%file_path%) do @set dir_path=%%~dpa
  633. @for %%a in (%file_path%) do @set file_name=%%~nxa
  634. @if [%url%] == [] exit /b 1
  635. @if [%file_path%] == [] exit /b 1
  636. @if [%dir_path%] == [] exit /b 1
  637. @if [%file_name%] == [] exit /b 1
  638. @if not exist "%dir_path%" mkdir "%dir_path%"
  639. @call :log 1 "Downloading %url%"
  640. @call :iso8601 iso8601
  641. @set temp_path=%temp%\download-%iso8601%-%file_name%
  642. @call :log 3 "Using temp file %temp_path%"
  643. @powershell Invoke-WebRequest "%url%" -OutFile %temp_path%
  644. @if errorlevel 1 (
  645. call :log 0 "Failed to download %url%"
  646. exit /b 1
  647. )
  648. @if [%checksum%] neq [] (
  649. @call :log 4 "Checking %checksum% against %temp_path%"
  650. @call :md5 hash "%temp_path%"
  651. if "!hash!" neq "%checksum%" (
  652. call :log 0 "Failed to match checksum: %temp_path%"
  653. call :log 0 "Hash : !hash!"
  654. call :log 0 "Checksum: %checksum%"
  655. exit /b 1
  656. ) else (
  657. call :log 3 "Checksum matched: %temp_path%"
  658. call :log 3 "Hash : !hash!"
  659. call :log 3 "Checksum: %checksum%"
  660. )
  661. )
  662. @call :log 4 "Renaming %temp_path% to %file_path%"
  663. @move /y "%temp_path%" "%file_path%" 1>nul
  664. @endlocal
  665. @goto :eof
  666. :install_msi - Installs a dependency from an Microsoft Installer package (.msi)
  667. :: %1 - [string] name of the project to install
  668. :: %2 - The location of the .msi, a url must start with 'http://' or file_path
  669. :: %3 - The checksum of the msi (optional)
  670. @setlocal
  671. @set name=%~1
  672. @set file_path=%~2
  673. @set checksum=%~3
  674. @set msi=%~nx2
  675. @set msi_path=%dependency_path%\%msi%
  676. @if [%name%] == [] exit /b 1
  677. @if [%file_path%] == [] exit /b 1
  678. @if [%msi%] == [] exit /b 1
  679. @if [%msi_path%] == [] exit /b 1
  680. @for %%x in (msiexec.exe) do @set "msiexec_path=%%~f$PATH:x"
  681. @if "msiexec_path" == "" (
  682. call :log 0 "Failed to find the Microsoft package installer (msiexec.exe)"
  683. call :log 6
  684. call :log 0 "Please install it from the Microsoft Download center"
  685. call :log 6
  686. choice /C YN /T 60 /D N /M "Would you like to go there now?"
  687. if !errorlevel! equ 1 call :start_browser ^
  688. "http://search.microsoft.com/DownloadResults.aspx?q=Windows+Installer"
  689. exit /b 1
  690. )
  691. @call :log 6
  692. @call :log 1 "Installing the '%name%' dependency"
  693. @call :log 6 "-------------------------------------"
  694. @call :administrator_check
  695. @if errorlevel 1 (
  696. call :log 0 "You must run %~nx0 in elevated mode to install '%name%'"
  697. call :log 5 "Right-Click and select 'Run as Administrator'
  698. call :log 0 "Install the dependency manually by running %file_path%"
  699. @exit /b 740
  700. )
  701. @if [%file_path:~0,4%] == [http] (
  702. if not exist "%msi_path%" (
  703. call :download "%file_path%" "%msi_path%" %checksum%
  704. if errorlevel 1 (
  705. call :log 0 "Failed to download the %name% dependency"
  706. exit /b 1
  707. )
  708. )
  709. ) else (
  710. call :log 2 "Copying MSI %file_path% to %msi_path%"
  711. call :log 7
  712. if not exist "%msi_path%" (
  713. xcopy /q /y /z "%file_path%" "%msi_path%" 1>nul
  714. if errorlevel 1 (
  715. call :log 0 "Failed to copy the Microsoft Installer"
  716. exit /b 1
  717. )
  718. )
  719. )
  720. @call :log 1 "Running the %msi%"
  721. @call :log 6
  722. @set msi_log=%temp%\msiexec-%timestamp%.log
  723. @call :log 3 "Logging to: %msi_log%"
  724. @msiexec /i "%msi_path%" /passive /log "%msi_log%" ALLUSERS=1
  725. @set msi_errorlevel=%errorlevel%
  726. @call :log_append "%msi_log%"
  727. @if %msi_errorlevel% equ 0 goto install_msi_success
  728. @if %msi_errorlevel% equ 3010 goto install_msi_success_reboot
  729. @if %msi_errorlevel% equ 1641 goto install_msi_success_reboot
  730. @if %msi_errorlevel% equ 3015 goto install_msi_in_progress_reboot
  731. @if %msi_errorlevel% equ 1615 goto install_msi_in_progress_reboot
  732. @call :log 0 "Microsoft Installer failed: %msi_errorlevel%"
  733. @call :log 0 "Install the dependency manually by running %msi_path%"
  734. @exit /b 1
  735. :install_msi_in_progress_reboot
  736. @call :log 0 "The installation requires a reboot to continue"
  737. @call :log 5
  738. @call :reboot
  739. @exit /b 1
  740. :install_msi_success_reboot
  741. @call :log 3 "The installation requires a reboot to be fully functional"
  742. @set reboot_required=1
  743. :install_msi_success
  744. @call :log 2 "Successfully installed %name%"
  745. @call :log 7
  746. @endlocal & set reboot_required=%reboot_required%
  747. @goto :eof
  748. :install_nsis - Installs a dependency from an Nullsoft Installer package (.exe)
  749. :: %1 - [string] name of the project to install
  750. :: %2 - The location of the .exe, a url must start with 'http://' or file_path
  751. :: %3 - The checksum of the exe (optional)
  752. @setlocal
  753. @set name=%~1
  754. @set file_path=%~2
  755. @set checksum=%~3
  756. @set exe=%~nx2
  757. @set exe_path=%dependency_path%\%exe%
  758. @if [%name%] == [] exit /b 1
  759. @if [%file_path%] == [] exit /b 1
  760. @if [%exe%] == [] exit /b 1
  761. @if [%exe_path%] == [] exit /b 1
  762. @call :log 6
  763. @call :log 1 "Installing the '%name%' dependency"
  764. @call :log 6 "-------------------------------------"
  765. @call :administrator_check
  766. @if errorlevel 1 (
  767. call :log 0 "You must run %~nx0 in elevated mode to install '%name%'"
  768. call :log 5 "Right-Click and select 'Run as Administrator'
  769. call :log 0 "Install the dependency manually by running %file_path%"
  770. @exit /b 740
  771. )
  772. @if [%file_path:~0,4%] == [http] (
  773. if not exist "%exe_path%" (
  774. call :download "%file_path%" "%exe_path%" %checksum%
  775. if errorlevel 1 (
  776. call :log 0 "Failed to download the %name% dependency"
  777. exit /b 1
  778. )
  779. )
  780. ) else (
  781. call :log 2 "Copying installer %file_path% to %exe_path%"
  782. call :log 7
  783. if not exist "%exe_path%" (
  784. xcopy /q /y /z "%file_path%" "%exe_path%" 1>nul
  785. if errorlevel 1 (
  786. call :log 0 "Failed to copy the Nullsoft Installer"
  787. exit /b 1
  788. )
  789. )
  790. )
  791. @call :log 1 "Running the %exe%"
  792. @call :log 6
  793. @"%exe_path%" /S
  794. @set nsis_errorlevel=%errorlevel%
  795. @if %nsis_errorlevel% equ 0 goto install_nsis_success
  796. @if %nsis_errorlevel% equ 3010 goto install_nsis_success_reboot
  797. @if %nsis_errorlevel% equ 1641 goto install_nsis_success_reboot
  798. @if %nsis_errorlevel% equ 3015 goto install_nsis_in_progress_reboot
  799. @if %nsis_errorlevel% equ 1615 goto install_nsis_in_progress_reboot
  800. @call :log 0 "Nullsoft Installer failed: %nsis_errorlevel%"
  801. @call :log 0 "Install the dependency manually by running %exe_path%"
  802. @exit /b 1
  803. :install_nsis_in_progress_reboot
  804. @call :log 0 "The installation requires a reboot to continue"
  805. @call :log 5
  806. @call :reboot
  807. @exit /b 1
  808. :install_nsis_success_reboot
  809. @call :log 3 "The installation requires a reboot to be fully functional"
  810. @set reboot_required=1
  811. :install_nsis_success
  812. @call :log 2 "Successfully installed %name%"
  813. @call :log 7
  814. @endlocal & set reboot_required=%reboot_required%
  815. @goto :eof
  816. :reboot - Asks the user if they would like to reboot then stops the script
  817. @setlocal
  818. @call :log 6 "-------------------------------------------"
  819. @choice /C YN /T 60 /D N /M "The %method% requires a reboot, reboot now?"
  820. @set ret=%errorlevel%
  821. @call :log 6
  822. @if %ret% equ 1 (
  823. @shutdown /r
  824. ) else (
  825. @call :log 0 "You will need to reboot to complete the %method%"
  826. @call :log 5
  827. )
  828. @endlocal
  829. @goto :eof