mingw.cmd 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879
  1. :: Make sure the extensions are enabled
  2. @verify other 2>nul
  3. @setlocal EnableExtensions 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 "script_name=%~nx0"
  16. @set "script_folder=%~dp0"
  17. @set "script_folder=%script_folder:~0,-1%"
  18. @set "dependency_path=%TEMP%\mingw-build-dependencies"
  19. :: Check the command line parameters
  20. @set logging_level=1
  21. :options_loop
  22. @if [%1] == [] goto :options_parsed
  23. @set "arg=%~1"
  24. @set one=%arg:~0,1%
  25. @set two=%arg:~0,2%
  26. @set three=%arg:~0,3%
  27. @if /i [%arg%] == [/?] (
  28. @call :print_usage "Downloads a specific version of MinGW"
  29. @exit /b 0
  30. )
  31. @if /i [%arg%] == [/q] set quiet=true
  32. @if /i [%two%] == [/v] @if /i not [%three%] == [/ve] @call :verbosity "!arg!"
  33. @if /i [%arg%] == [/version] set "version=%~2" & shift
  34. @if /i [%arg%] == [/arch] set "arch=%~2" & shift
  35. @if /i [%arg%] == [/exceptions] set "exceptions=%~2" & shift
  36. @if /i [%arg%] == [/threading] set "threading=%~2" & shift
  37. @if /i [%arg%] == [/revision] set "revision=%~2" & shift
  38. @if /i not [!one!] == [/] (
  39. if not defined output_path (
  40. set output_path=!arg!
  41. ) else (
  42. @call :print_usage "Too many output locations: !output_path! !arg!" ^
  43. "There should only be one output location"
  44. @exit /b 1
  45. )
  46. )
  47. @shift
  48. @goto :options_loop
  49. :options_parsed
  50. @if defined quiet set logging_level=0
  51. @if not defined output_path set "output_path=%script_folder%\mingw-builds"
  52. @set "output_path=%output_path:/=\%"
  53. :: Set up the logging
  54. @set "log_folder=%output_path%\logs"
  55. @call :iso8601 timestamp
  56. @set "log_path=%log_folder%\%timestamp%.log"
  57. @set log_keep=10
  58. :: Get default architecture
  59. @if not defined arch @call :architecture arch
  60. :: Only keep a certain amount of logs
  61. @set /a "log_keep=log_keep-1"
  62. @if not exist %log_folder% @mkdir %log_folder%
  63. @for /f "skip=%log_keep%" %%f in ('dir /b /o-D /tc %log_folder%') do @(
  64. @call :log 4 "Removing old log file %log_folder%\%%f"
  65. del %log_folder%\%%f
  66. )
  67. :: Set up some more global variables
  68. @call :windows_version win_ver win_ver_major win_ver_minor win_ver_rev
  69. @call :script_source script_source
  70. @if [%script_source%] == [explorer] (
  71. set /a "logging_level=logging_level+1"
  72. )
  73. :: Execute the main function
  74. @call :main "%arch%" "%version%" "%threading%" "%exceptions%" "%revision%"
  75. @if errorlevel 1 (
  76. @call :log 0 "Failed to download MinGW"
  77. @call :log 0 "View the log at %log_path%"
  78. @exit /b 1
  79. )
  80. :: Stop the script if the user double clicked
  81. @if [%script_source%] == [explorer] (
  82. pause
  83. )
  84. @endlocal
  85. @goto :eof
  86. :: -------------------------- Functions start here ----------------------------
  87. :main - Main function that performs the download
  88. :: %1 - Target architecture
  89. :: %2 - Version of MinGW to get [optional]
  90. :: %3 - Threading model [optional]
  91. :: %4 - Exception model [optional]
  92. :: %5 - Package revision [optional]
  93. @setlocal
  94. @call :log 6
  95. @call :log 2 "Welcome to the MinGW download script"
  96. @call :log 6 "------------------------------------"
  97. @call :log 6
  98. @call :log 2 "This script downloads a specific version of MinGW"
  99. @set "arch=%~1"
  100. @if "%arch%" == "" @exit /b 1
  101. @set "version=%~2"
  102. @set "threading=%~3"
  103. @set "exceptions=%~4"
  104. @set "revision=%~5"
  105. @call :log 3 "arch = %arch%"
  106. @call :log 3 "version = %version%"
  107. @call :log 3 "exceptions = %exceptions%"
  108. @call :log 3 "threading = %threading%"
  109. @call :log 3 "revision = %revision%"
  110. @call :repository repo
  111. @if errorlevel 1 (
  112. @call :log 0 "Failed to get the MinGW-builds repository information"
  113. @exit /b 1
  114. )
  115. @call :resolve slug url "%repo%" "%arch%" "%version%" "%threading%" "%exceptions%" "%revision%"
  116. @if errorlevel 1 (
  117. @call :log 0 "Failed to resolve the correct URL of MinGW"
  118. @exit /b 1
  119. )
  120. @call :unpack compiler_path "%url%" "%output_path%\mingw\%slug%"
  121. @if errorlevel 1 (
  122. @call :log 0 "Failed to unpack the MinGW archive"
  123. @exit /b 1
  124. )
  125. @rmdir /s /q "%dependency_path%"
  126. @echo.%compiler_path%
  127. @endlocal
  128. @goto :eof
  129. :repository - Gets the MinGW-builds repository
  130. :: %1 - The return variable for the repository file path
  131. @verify other 2>nul
  132. @setlocal EnableDelayedExpansion
  133. @if errorlevel 1 (
  134. @call :log 0 "Failed to enable extensions"
  135. @exit /b 1
  136. )
  137. @set "var=%~1"
  138. @if "%var%" == "" @exit /b 1
  139. @call :log 7
  140. @call :log 2 "Getting MinGW repository information"
  141. @set "url=http://downloads.sourceforge.net/project/mingw-w64/Toolchains targetting Win32/Personal Builds/mingw-builds/installer/repository.txt"
  142. @call :log 6
  143. @call :log 1 "Downloading MinGW repository"
  144. @set "file_path=%dependency_path%\mingw-repository.txt"
  145. @call :download "%url%" "%file_path%"
  146. @if errorlevel 1 (
  147. @call :log 0 "Failed to download the MinGW repository information"
  148. @exit /b 1
  149. )
  150. @set "repository_path=%dependency_path%\repository.txt"
  151. @del "%repository_path%" 2>nul
  152. @for /f "delims=| tokens=1-6,*" %%a in (%file_path%) do @(
  153. @set "version=%%~a"
  154. @set "version=!version: =!"
  155. @set "arch=%%~b"
  156. @set "arch=!arch: =!"
  157. @set "threading=%%~c"
  158. @set "threading=!threading: =!"
  159. @set "exceptions=%%~d"
  160. @set "exceptions=!exceptions: =!"
  161. @set "revision=%%~e"
  162. @set "revision=!revision: =!"
  163. @set "revision=!revision:rev=!"
  164. @set "url=%%~f"
  165. @set "url=!url:%%20= !"
  166. @for /l %%a in (1,1,32) do @if "!url:~-1!" == " " set url=!url:~0,-1!
  167. @echo !arch!^|!version!^|!threading!^|!exceptions!^|!revision!^|!url!>> "%repository_path%"
  168. )
  169. @del "%file_path%" 2>nul
  170. @endlocal & set "%var%=%repository_path%"
  171. @goto :eof
  172. :resolve - Gets the MinGW-builds repository
  173. :: %1 - The return variable for the MinGW slug
  174. :: %2 - The return variable for the MinGW URL
  175. :: %3 - The repository information to use
  176. :: %4 - Target architecture
  177. :: %5 - Version of MinGW to get [optional]
  178. :: %6 - Threading model [optional]
  179. :: %7 - Exception model [optional]
  180. :: %8 - Package revision [optional]
  181. @setlocal
  182. @set "slug_var=%~1"
  183. @if "%slug_var%" == "" @exit /b 1
  184. @set "url_var=%~2"
  185. @if "%url_var%" == "" @exit /b 1
  186. @set "repository=%~3"
  187. @if "%repository%" == "" @exit /b 1
  188. @set "arch=%~4"
  189. @if "%arch%" == "" @exit /b 1
  190. @call :resolve_version version "%repository%" "%arch%" "%~5"
  191. @if errorlevel 1 @exit /b 1
  192. @call :resolve_threading threading "%repository%" "%arch%" "%version%" "%~6"
  193. @if errorlevel 1 @exit /b 1
  194. @call :resolve_exceptions exceptions "%repository%" "%arch%" "%version%" "%threading%" "%~7"
  195. @if errorlevel 1 @exit /b 1
  196. @call :resolve_revision revision "%repository%" "%arch%" "%version%" "%threading%" "%exceptions%" "%~8"
  197. @if errorlevel 1 @exit /b 1
  198. @call :log 3 "Finding URL"
  199. @for /f "delims=| tokens=1-6" %%a in (%repository%) do @(
  200. @if "%arch%" == "%%a" (
  201. @if "%version%" == "%%b" (
  202. @if "%threading%" == "%%c" (
  203. @if "%exceptions%" == "%%d" (
  204. @if "%revision%" == "%%e" (
  205. @set "url=%%f"
  206. ) ) ) ) ) )
  207. @if "%url%" == "" (
  208. @call :log 0 "Failed to resolve URL"
  209. @exit /b 1
  210. )
  211. @set slug=gcc-%version%-%arch%-%threading%-%exceptions%-rev%revision%
  212. @call :log 2 "Resolved slug: %slug%"
  213. @call :log 2 "Resolved url: %url%"
  214. @endlocal & set "%slug_var%=%slug%" & set "%url_var%=%url%"
  215. @goto :eof
  216. :unpack - Unpacks the MinGW archive
  217. :: %1 - The return variable name for the compiler path
  218. :: %2 - The filepath or URL of the archive
  219. :: %3 - The folder to unpack to
  220. @verify other 2>nul
  221. @setlocal EnableDelayedExpansion
  222. @if errorlevel 1 (
  223. @call :log 0 "Failed to enable extensions"
  224. @exit /b 1
  225. )
  226. @set "var=%~1"
  227. @if "%var%" == "" @exit /b 1
  228. @set "archive_path=%~2"
  229. @if "%archive_path%" == "" @exit /b 1
  230. @set "folder_path=%~3"
  231. @if "%folder_path%" == "" @exit /b 1
  232. @set "compiler_path=%folder_path%\bin"
  233. @if exist "%compiler_path%" goto :unpack_done
  234. @call :log 7
  235. @call :log 2 "Unpacking MinGW archive"
  236. @set "http=%archive_path:~0,4%"
  237. @if "%http%" == "http" (
  238. @set "url=%archive_path%"
  239. @for /f %%a in ("!url: =-!") do @set "file_name=%%~na"
  240. @for /f %%a in ("!url: =-!") do @set "file_ext=%%~xa"
  241. @set "archive_path=%dependency_path%\!file_name!!file_ext!"
  242. @if not exist "!archive_path!" (
  243. @call :log 6
  244. @call :log 1 "Downloading MinGW archive"
  245. @call :download "!url!" "!archive_path!"
  246. @if errorlevel 1 (
  247. @del "!archive_path!" 2>nul
  248. @call :log 0 "Failed to download: !file_name!!file_ext!"
  249. @exit /b 1
  250. )
  251. )
  252. )
  253. @if not exist "%archive_path%" (
  254. @call :log 0 "The archive did not exist to unpack: %archive_path%"
  255. @exit /b 1
  256. )
  257. @for /f %%a in ("%archive_path: =-%") do @set "file_name=%%~na"
  258. @for /f %%a in ("%archive_path: =-%") do @set "file_ext=%%~xa"
  259. @call :log 6
  260. @call :log 1 "Unpacking MinGW %file_name%%file_ext%"
  261. @call :find_sevenzip sevenzip_executable
  262. @if errorlevel 1 (
  263. @call :log 0 "Need 7zip to unpack the MinGW archive"
  264. @exit /b 1
  265. )
  266. @call :iso8601 iso8601
  267. @for /f %%a in ("%folder_path%") do @set "tmp_path=%%~dpatmp-%iso8601%"
  268. @"%sevenzip_executable%" x -y "-o%tmp_path%" "%archive_path%" > nul
  269. @if errorlevel 1 (
  270. @rmdir /s /q "%folder_path%"
  271. @call :log 0 "Failed to unpack the MinGW archive"
  272. @exit /b 1
  273. )
  274. @set "expected_path=%tmp_path%\mingw64"
  275. @if not exist "%expected_path%" (
  276. @set "expected_path=%tmp_path%\mingw32"
  277. )
  278. @move /y "%expected_path%" "%folder_path%" > nul
  279. @if errorlevel 1 (
  280. @rmdir /s /q "%tmp_path%" 2>nul
  281. @call :log 0 "Failed to move MinGW folder"
  282. @call :log 0 "%expected_path%"
  283. @call :log 0 "%folder_path%"
  284. @exit /b 1
  285. )
  286. @rmdir /s /q %tmp_path%
  287. @set "compiler_path=%folder_path%\bin"
  288. :unpack_done
  289. @if not exist "%compiler_path%\gcc.exe" (
  290. @call :log 0 "Failed to find gcc: %compiler_path%"
  291. @exit /b 1
  292. )
  293. @endlocal & set "%var%=%compiler_path%"
  294. @goto :eof
  295. :find_sevenzip - Finds (or downloads) the 7zip executable
  296. :: %1 - The return variable for the 7zip executable path
  297. @setlocal
  298. @set "var=%~1"
  299. @if "%var%" == "" @exit /b 1
  300. @call :log 2 "Finding 7zip"
  301. @call :find_in_path sevenzip_executable 7z.exe
  302. @if not errorlevel 1 goto :find_sevenzip_done
  303. @call :find_in_path sevenzip_executable 7za.exe
  304. @if not errorlevel 1 goto :find_sevenzip_done
  305. @set checksum=2FAC454A90AE96021F4FFC607D4C00F8
  306. @set "url=http://7-zip.org/a/7za920.zip"
  307. @for /f %%a in ("%url: =-%") do @set "file_name=%%~na"
  308. @for /f %%a in ("%url: =-%") do @set "file_ext=%%~xa"
  309. @set "archive_path=%dependency_path%\%file_name%%file_ext%"
  310. @if not exist "%archive_path%" (
  311. @call :log 6
  312. @call :log 1 "Downloading 7zip archive"
  313. @call :download "%url%" "%archive_path%" %checksum%
  314. @if errorlevel 1 (
  315. @del "%archive_path%" 2>nul
  316. @call :log 0 "Failed to download: %file_name%%file_ext%"
  317. @exit /b 1
  318. )
  319. )
  320. @set "sevenzip_path=%dependency_path%\sevenzip"
  321. @if not exist "%sevenzip_path%" (
  322. @call :unzip "%archive_path%" "%sevenzip_path%"
  323. @if errorlevel 1 (
  324. @call :log 0 "Failed to unzip the7zip archive"
  325. @exit /b 1
  326. )
  327. )
  328. @set "sevenzip_executable=%sevenzip_path%\7za.exe"
  329. @if not exist "%sevenzip_executable%" (
  330. @call :log 0 "Failed to find unpacked 7zip: %sevenzip_executable%"
  331. @exit /b 1
  332. )
  333. :find_sevenzip_done
  334. @call :log 2 "Found 7zip: %sevenzip_executable%"
  335. @endlocal & set "%var%=%sevenzip_executable%"
  336. @goto :eof
  337. :unzip - Unzips a .zip archive
  338. :: %1 - The archive to unzip
  339. :: %2 - The location to unzip to
  340. @setlocal
  341. @set "archive_path=%~1"
  342. @if "%archive_path%" == "" @exit /b 1
  343. @set "folder_path=%~2"
  344. @if "%folder_path%" == "" @exit /b 1
  345. @for /f %%a in ("%archive_path: =-%") do @set "file_name=%%~na"
  346. @for /f %%a in ("%archive_path: =-%") do @set "file_ext=%%~xa"
  347. @call :log 2 "Unzipping: %file_name%%file_ext%"
  348. @powershell ^
  349. Add-Type -assembly "system.io.compression.filesystem"; ^
  350. [io.compression.zipfile]::ExtractToDirectory(^
  351. '%archive_path%', '%folder_path%') 2>nul
  352. @if errorlevel 1 (
  353. @call :log 0 "Failed to unzip: %file_name%%file_ext%"
  354. @exit /b 1
  355. )
  356. @endlocal
  357. @goto :eof
  358. :resolve_version - Gets the version of the MinGW compiler
  359. :: %1 - The return variable for the version
  360. :: %2 - The repository information to use
  361. :: %3 - The architecture of the compiler
  362. :: %4 - Version of MinGW to get [optional]
  363. @verify other 2>nul
  364. @setlocal EnableDelayedExpansion
  365. @if errorlevel 1 (
  366. @call :log 0 "Failed to enable extensions"
  367. @exit /b 1
  368. )
  369. @set "var=%~1"
  370. @if "%var%" == "" @exit /b 1
  371. @set "repository=%~2"
  372. @if "%repository%" == "" @exit /b 1
  373. @set "arch=%~3"
  374. @if "%arch%" == "" @exit /b 1
  375. @set "version=%~4"
  376. @if not "%version%" == "" goto :resolve_version_done
  377. :: Find the latest version
  378. @call :log 3 "Finding latest version"
  379. @set version=0.0.0
  380. @for /f "delims=| tokens=1-6" %%a in (%repository%) do @(
  381. @if "%arch%" == "%%a" (
  382. @call :version_compare result "%version%" "%%b"
  383. @if errorlevel 1 (
  384. @call :log 0 "Failed to compare versions: %version% %%a"
  385. @exit /b 1
  386. )
  387. @if !result! lss 0 set version=%%b
  388. )
  389. )
  390. :resolve_version_done
  391. @if "%version%" == "" (
  392. @call :log 0 "Failed to resolve latest version number"
  393. @exit /b 1
  394. )
  395. @call :log 2 "Resolved version: %version%"
  396. @endlocal & set "%var%=%version%"
  397. @goto :eof
  398. :resolve_threading - Gets the threading model of the MinGW compiler
  399. :: %1 - The return variable for the threading model
  400. :: %2 - The repository information to use
  401. :: %3 - The architecture of the compiler
  402. :: %4 - The version of the compiler
  403. :: %5 - threading model of MinGW to use [optional]
  404. @verify other 2>nul
  405. @setlocal EnableDelayedExpansion
  406. @if errorlevel 1 (
  407. @call :log 0 "Failed to enable extensions"
  408. @exit /b 1
  409. )
  410. @set "var=%~1"
  411. @if "%var%" == "" @exit /b 1
  412. @set "repository=%~2"
  413. @if "%repository%" == "" @exit /b 1
  414. @set "arch=%~3"
  415. @if "%arch%" == "" @exit /b 1
  416. @set "version=%~4"
  417. @if "%version%" == "" @exit /b 1
  418. @set "threading=%~5"
  419. @if not "%threading%" == "" goto :resolve_threading_done
  420. @call :log 3 "Finding best threading model"
  421. @for /f "delims=| tokens=1-6" %%a in (%repository%) do @(
  422. @if "%arch%" == "%%a" (
  423. @if "%version%" == "%%b" (
  424. @if not defined threading (
  425. @set "threading=%%c"
  426. )
  427. @if "%%c" == "posix" (
  428. @set "threading=%%c"
  429. ) ) ) )
  430. :resolve_threading_done
  431. @if "%threading%" == "" (
  432. @call :log 0 "Failed to resolve the best threading model"
  433. @exit /b 1
  434. )
  435. @call :log 2 "Resolved threading model: %threading%"
  436. @endlocal & set "%var%=%threading%"
  437. @goto :eof
  438. :resolve_exceptions - Gets the exception model of the MinGW compiler
  439. :: %1 - The return variable for the exception model
  440. :: %2 - The repository information to use
  441. :: %3 - The architecture of the compiler
  442. :: %4 - The version of the compiler
  443. :: %4 - The threading model of the compiler
  444. :: %5 - exception model of MinGW to use [optional]
  445. @verify other 2>nul
  446. @setlocal EnableDelayedExpansion
  447. @if errorlevel 1 (
  448. @call :log 0 "Failed to enable extensions"
  449. @exit /b 1
  450. )
  451. @set "var=%~1"
  452. @if "%var%" == "" @exit /b 1
  453. @set "repository=%~2"
  454. @if "%repository%" == "" @exit /b 1
  455. @set "arch=%~3"
  456. @if "%arch%" == "" @exit /b 1
  457. @set "version=%~4"
  458. @if "%version%" == "" @exit /b 1
  459. @set "threading=%~5"
  460. @if "%threading%" == "" @exit /b 1
  461. @set "exceptions=%~6"
  462. @if not "%exceptions%" == "" goto :resolve_exceptions_done
  463. @call :log 3 "Finding best exception model"
  464. @for /f "delims=| tokens=1-6" %%a in (%repository%) do @(
  465. @if "%arch%" == "%%a" (
  466. @if "%version%" == "%%b" (
  467. @if "%threading%" == "%%c" (
  468. @if not defined exceptions (
  469. @set "exceptions=%%d"
  470. )
  471. @if "%%d" == "dwarf" (
  472. @set "exceptions=%%d"
  473. )
  474. @if "%%d" == "seh" (
  475. @set "exceptions=%%d"
  476. ) ) ) ) )
  477. :resolve_exceptions_done
  478. @if "%exceptions%" == "" (
  479. @call :log 0 "Failed to resolve the best exception model"
  480. @exit /b 1
  481. )
  482. @call :log 2 "Resolved exception model: %exceptions%"
  483. @endlocal & set "%var%=%exceptions%"
  484. @goto :eof
  485. :resolve_revision - Gets the revision of the MinGW compiler
  486. :: %1 - The return variable for the revision
  487. :: %2 - The repository information to use
  488. :: %3 - The architecture of the compiler
  489. :: %4 - The version of the compiler
  490. :: %4 - The threading model of the compiler
  491. :: %4 - The exception model of the compiler
  492. :: %5 - revision of the MinGW package to use [optional]
  493. @verify other 2>nul
  494. @setlocal EnableDelayedExpansion
  495. @if errorlevel 1 (
  496. @call :log 0 "Failed to enable extensions"
  497. @exit /b 1
  498. )
  499. @set "var=%~1"
  500. @if "%var%" == "" @exit /b 1
  501. @set "repository=%~2"
  502. @if "%repository%" == "" @exit /b 1
  503. @set "arch=%~3"
  504. @if "%arch%" == "" @exit /b 1
  505. @set "version=%~4"
  506. @if "%version%" == "" @exit /b 1
  507. @set "threading=%~5"
  508. @if "%threading%" == "" @exit /b 1
  509. @set "exceptions=%~6"
  510. @if "%exceptions%" == "" @exit /b 1
  511. @set "revision=%~7"
  512. @if not "%revision%" == "" goto :resolve_revision_done
  513. @call :log 3 "Finding latest revision"
  514. @for /f "delims=| tokens=1-6" %%a in (%repository%) do @(
  515. @if "%arch%" == "%%a" (
  516. @if "%version%" == "%%b" (
  517. @if "%threading%" == "%%c" (
  518. @if "%exceptions%" == "%%d" (
  519. @if "%%e" gtr "%revision%" (
  520. @set "revision=%%e"
  521. ) ) ) ) ) )
  522. :resolve_revision_done
  523. @if "%revision%" == "" (
  524. @call :log 0 "Failed to resolve latest revision"
  525. @exit /b 1
  526. )
  527. @call :log 2 "Resolved revision: %revision%"
  528. @endlocal & set "%var%=%revision%"
  529. @goto :eof
  530. :version_compare - Compares two semantic version numbers
  531. :: %1 - The return variable:
  532. :: - < 0 : if %2 < %3
  533. :: - 0 : if %2 == %3
  534. :: - > 0 : if %2 > %3
  535. :: %2 - The first version to compare
  536. :: %3 - The second version to compare
  537. @setlocal
  538. @set "var=%~1"
  539. @if "%var%" == "" @exit /b 1
  540. @set "lhs=%~2"
  541. @if "%lhs%" == "" @exit /b 1
  542. @set "rhs=%~3"
  543. @if "%lhs%" == "" @exit /b 1
  544. @set result=0
  545. @for /f "delims=. tokens=1-6" %%a in ("%lhs%.%rhs%") do @(
  546. @if %%a lss %%d (
  547. set result=-1
  548. goto :version_compare_done
  549. ) else (
  550. @if %%a gtr %%d (
  551. set result=1
  552. goto :version_compare_done
  553. ) else (
  554. @if %%b lss %%e (
  555. set result=-1
  556. goto :version_compare_done
  557. ) else (
  558. @if %%b gtr %%e (
  559. set result=1
  560. goto :version_compare_done
  561. ) else (
  562. @if %%c lss %%f (
  563. set result=-1
  564. goto :version_compare_done
  565. ) else (
  566. @if %%c gtr %%f (
  567. set result=1
  568. goto :version_compare_done
  569. )
  570. )
  571. )
  572. )
  573. )
  574. )
  575. )
  576. :version_compare_done
  577. @endlocal & set "%var%=%result%"
  578. @goto :eof
  579. :print_usage - Prints the usage of the script
  580. :: %* - message to print, each argument on it's own line
  581. @setlocal
  582. @for %%a in (%*) do @echo.%%~a
  583. @echo.
  584. @echo.build [/?][/v[v...]^|/q][/version][/arch a][/threading t]
  585. @echo. [/exceptions e][/revision r] location
  586. @echo.
  587. @echo. /version v The version of MinGW to download
  588. @echo. /arch a The target architecture [i686^|x86_64]
  589. @echo. /threading t
  590. @echo. Threading model to use [posix^|win32]
  591. @echo. /exceptions e
  592. @echo. Exception model to use [sjlj^|seh^|dwarf]
  593. @echo. /revision e Revision of the release to use
  594. @echo. /v Sets the output to be more verbose
  595. @echo. /v[v...] Extra verbosity, /vv, /vvv, etc
  596. @echo. /q Quiets the output
  597. @echo. /? Shows this usage message
  598. @echo.
  599. @endlocal
  600. @goto :eof
  601. :script_source - Determines if the script was ran from the cli or explorer
  602. :: %1 - The return variable [cli|explorer]
  603. @verify other 2>nul
  604. @setlocal EnableDelayedExpansion
  605. @if errorlevel 1 (
  606. @call :log 0 "Failed to enable extensions"
  607. @exit /b 1
  608. )
  609. @call :log 3 "Attempting to detect the script source"
  610. @echo "The invocation command was: '%cmdcmdline%'" >> %log_path%
  611. @for /f "tokens=1-3,*" %%a in ("%cmdcmdline%") do @(
  612. set cmd=%%~a
  613. set arg1=%%~b
  614. set arg2=%%~c
  615. set rest=%%~d
  616. )
  617. @set quote="
  618. @if "!arg2:~0,1!" equ "!quote!" (
  619. if "!arg2:~-1!" neq "!quote!" (
  620. set "arg2=!arg2:~1!"
  621. )
  622. )
  623. @call :log 4 "cmd = %cmd%"
  624. @call :log 4 "arg1 = %arg1%"
  625. @call :log 4 "arg2 = %arg2%"
  626. @call :log 4 "rest = %rest%"
  627. @call :log 4 "src = %~f0"
  628. @if /i "%arg2%" == "call" (
  629. set script_source=cli
  630. ) else (
  631. @if /i "%arg1%" == "/c" (
  632. set script_source=explorer
  633. ) else (
  634. set script_source=cli
  635. )
  636. )
  637. @call :log 3 "The script was invoked from %script_source%"
  638. @endlocal & set "%~1=%script_source%"
  639. @goto :eof
  640. :architecture - Finds the system architecture
  641. :: %1 - The return variable [i686|x86_64]
  642. @setlocal
  643. @call :log 3 "Determining the processor architecture"
  644. @set "key=HKLM\System\CurrentControlSet\Control\Session Manager\Environment"
  645. @set "var=PROCESSOR_ARCHITECTURE"
  646. @for /f "skip=2 tokens=2,*" %%a in ('reg query "%key%" /v "%var%"') do @set "arch=%%b"
  647. @if "%arch%" == "AMD64" set arch=x86_64
  648. @if "%arch%" == "x64" set arch=i686
  649. @call :log 4 "arch = %arch%"
  650. @endlocal & set "%~1=%arch%"
  651. @goto :eof
  652. :md5 - Gets the MD5 checksum for a file
  653. :: %1 - The hash
  654. :: %2 - The file path
  655. @setlocal
  656. @set "var=%~1"
  657. @set "file_path=%~2"
  658. @if "%var%" == "" @exit /b 1
  659. @if "%file_path%" == "" @exit /b 1
  660. @if not exist "%file_path%" @exit /b 1
  661. @for /f "skip=3 tokens=1,*" %%a in ('powershell Get-FileHash -Algorithm MD5 "'%file_path%'"') do @set hash=%%b
  662. @if not defined hash (
  663. @call :log 6
  664. @call :log 0 "Failed to get MD5 hash for %file_path%"
  665. @exit /b 1
  666. )
  667. @endlocal & set "%var%=%hash: =%"
  668. @goto :eof
  669. :windows_version - Checks the windows version
  670. :: %1 - The windows version
  671. :: %2 - The major version number return variable
  672. :: %3 - The minor version number return variable
  673. :: %4 - The revision version number return variable
  674. @setlocal
  675. @call :log 3 "Retrieving the Windows version"
  676. @for /f "tokens=2 delims=[]" %%x in ('ver') do @set win_ver=%%x
  677. @set win_ver=%win_ver:Version =%
  678. @set win_ver_major=%win_ver:~0,1%
  679. @set win_ver_minor=%win_ver:~2,1%
  680. @set win_ver_rev=%win_ver:~4%
  681. @call :log 4 "win_ver = %win_ver%"
  682. @endlocal & set "%~1=%win_ver%" ^
  683. & set "%~2=%win_ver_major%" ^
  684. & set "%~3=%win_ver_minor%" ^
  685. & set "%~4=%win_ver_rev%"
  686. @goto :eof
  687. :find_in_path - Finds a program of file in the PATH
  688. :: %1 - return variable of the file path
  689. @setlocal
  690. @set "var=%~1"
  691. @if "%var%" == "" @exit /b 1
  692. @set "file=%~2"
  693. @if "%file%" == "" @exit /b 1
  694. @call :log 3 "Searching PATH for %file%"
  695. @for %%x in ("%file%") do @set "file_path=%%~f$PATH:x"
  696. @if not defined file_path @exit /b 1
  697. @endlocal & set "%var%=%file_path%"
  698. @goto :eof
  699. :log_append - Appends another file into the current logging file
  700. :: %1 - the file_path to the file to concatenate
  701. @setlocal
  702. @set "file_path=%~1"
  703. @if "%file_path%" == "" @exit /b 1
  704. @call :log 3 "Appending to log: %file_path%"
  705. @call :iso8601 iso8601
  706. @set temp_log=%temp%\append-%iso8601%.log
  707. @call :log 4 "Using temp file %temp_log%"
  708. @type "%log_path%" "%file_path%" > "%temp_log%" 2>nul
  709. @move /y "%temp_log%" "%log_path%" 1>nul
  710. @del "%file_path% 2>nul
  711. @del "%temp_log% 2>nul
  712. @endlocal
  713. @goto :eof
  714. :iso8601 - Returns the current time in ISO8601 format
  715. :: %1 - the return variable
  716. :: %2 - format [extended|basic*]
  717. :: iso8601 - contains the resulting timestamp
  718. @setlocal
  719. @wmic Alias /? >NUL 2>&1 || @exit /b 1
  720. @set "var=%~1"
  721. @if "%var%" == "" @exit /b 1
  722. @set "format=%~2"
  723. @if "%format%" == "" set format=basic
  724. @for /F "skip=1 tokens=1-6" %%g IN ('wmic Path Win32_UTCTime Get Day^,Hour^,Minute^,Month^,Second^,Year /Format:table') do @(
  725. @if "%%~l"=="" goto :iso8601_done
  726. @set "yyyy=%%l"
  727. @set "mm=00%%j"
  728. @set "dd=00%%g"
  729. @set "hour=00%%h"
  730. @set "minute=00%%i"
  731. @set "seconds=00%%k"
  732. )
  733. :iso8601_done
  734. @set mm=%mm:~-2%
  735. @set dd=%dd:~-2%
  736. @set hour=%hour:~-2%
  737. @set minute=%minute:~-2%
  738. @set seconds=%seconds:~-2%
  739. @if /i [%format%] == [extended] (
  740. set iso8601=%yyyy%-%mm%-%dd%T%hour%:%minute%:%seconds%Z
  741. ) else (
  742. if /i [%format%] == [basic] (
  743. set iso8601=%yyyy%%mm%%dd%T%hour%%minute%%seconds%Z
  744. ) else (
  745. @exit /b 1
  746. )
  747. )
  748. @set iso8601=%iso8601: =0%
  749. @endlocal & set %var%=%iso8601%
  750. @goto :eof
  751. :verbosity - Processes the verbosity parameter '/v[v...]
  752. :: %1 - verbosity given on the command line
  753. :: logging_level - set to the number of v's
  754. @setlocal
  755. @set logging_level=0
  756. @set verbosity=%~1
  757. :verbosity_loop
  758. @set verbosity=%verbosity:~1%
  759. @if not [%verbosity%] == [] @(
  760. set /a "logging_level=logging_level+1"
  761. goto verbosity_loop
  762. )
  763. @endlocal & set logging_level=%logging_level%
  764. @goto :eof
  765. :log - Logs a message, depending on verbosity
  766. :: %1 - level
  767. :: [0-4] for CLI logging
  768. :: [5-9] for GUI logging
  769. :: %2 - message to print
  770. @setlocal
  771. @set "level=%~1"
  772. @set "msg=%~2"
  773. @if "%log_folder%" == "" (
  774. echo Logging was used to early in the script, log_folder isn't set yet
  775. goto :eof
  776. )
  777. @if "%log_path%" == "" (
  778. echo Logging was used to early in the script, log_path isn't set yet
  779. goto :eof
  780. )
  781. @if not exist "%log_folder%" mkdir "%log_folder%"
  782. @if not exist "%log_path%" echo. 1>nul 2>"%log_path%"
  783. @echo.%msg% >> "%log_path%"
  784. @if %level% geq 5 (
  785. @if [%script_source%] == [explorer] (
  786. set /a "level=level-5"
  787. ) else (
  788. @goto :eof
  789. )
  790. )
  791. @if "%logging_level%" == "" (
  792. echo Logging was used to early in the script, logging_level isn't set yet
  793. goto :eof
  794. )
  795. @if %logging_level% geq %level% echo.%msg% 1>&2
  796. @endlocal
  797. @goto :eof
  798. :download - Downloads a file from the internet
  799. :: %1 - the url of the file to download
  800. :: %2 - the file to download to
  801. :: %3 - the MD5 checksum of the file (optional)
  802. @setlocal EnableDelayedExpansion
  803. @if errorlevel 1 (
  804. @call :print_usage "Failed to enable extensions"
  805. @exit /b 1
  806. )
  807. @set "url=%~1"
  808. @set "file_path=%~2"
  809. @set "checksum=%~3"
  810. @for %%a in (%file_path%) do @set dir_path=%%~dpa
  811. @for %%a in (%file_path%) do @set file_name=%%~nxa
  812. @if "%url%" == "" @exit /b 1
  813. @if "%file_path%" == "" @exit /b 1
  814. @if "%dir_path%" == "" @exit /b 1
  815. @if "%file_name%" == "" @exit /b 1
  816. @if not exist "%dir_path%" mkdir "%dir_path%"
  817. @call :log 2 "Downloading %url%"
  818. @call :iso8601 iso8601
  819. @set "temp_path=%temp%\download-%iso8601%-%file_name%"
  820. @call :log 4 "Using temp file %temp_path%"
  821. @powershell Invoke-WebRequest "'%url%'" ^
  822. -OutFile "'%temp_path%'" ^
  823. -UserAgent [Microsoft.PowerShell.Commands.PSUserAgent]::IE ^
  824. 1> nul 2> nul
  825. @if errorlevel 1 (
  826. @call :log 0 "Failed to download %url%"
  827. @exit /b 1
  828. )
  829. @if [%checksum%] neq [] (
  830. @call :log 4 "Checking %checksum% against %temp_path%"
  831. @call :md5 hash "%temp_path%"
  832. if "!hash!" neq "%checksum%" (
  833. @call :log 0 "Failed to match checksum: %temp_path%"
  834. @call :log 0 "Hash : !hash!"
  835. @call :log 0 "Checksum: %checksum%"
  836. @exit /b 1
  837. ) else (
  838. @call :log 3 "Checksum matched: %temp_path%"
  839. @call :log 3 "Hash : !hash!"
  840. @call :log 3 "Checksum: %checksum%"
  841. )
  842. )
  843. @call :log 4 "Renaming %temp_path% to %file_path%"
  844. @move /y "%temp_path%" "%file_path%" 1>nul
  845. @endlocal
  846. @goto :eof