mingw.cmd 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884
  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. @call :iso8601 iso8601
  349. @set "log_path=%temp%\unzip-%iso8601%-%file_name%.log"
  350. @powershell ^
  351. Add-Type -assembly "system.io.compression.filesystem"; ^
  352. [io.compression.zipfile]::ExtractToDirectory(^
  353. '%archive_path%', '%folder_path%') 2>"%log_path%"
  354. @if errorlevel 1 (
  355. @call :log 0 "Failed to unzip: %file_name%%file_ext%"
  356. @call :log_append "%log_path%"
  357. @exit /b 1
  358. )
  359. @endlocal
  360. @goto :eof
  361. :resolve_version - Gets the version of the MinGW compiler
  362. :: %1 - The return variable for the version
  363. :: %2 - The repository information to use
  364. :: %3 - The architecture of the compiler
  365. :: %4 - Version of MinGW to get [optional]
  366. @verify other 2>nul
  367. @setlocal EnableDelayedExpansion
  368. @if errorlevel 1 (
  369. @call :log 0 "Failed to enable extensions"
  370. @exit /b 1
  371. )
  372. @set "var=%~1"
  373. @if "%var%" == "" @exit /b 1
  374. @set "repository=%~2"
  375. @if "%repository%" == "" @exit /b 1
  376. @set "arch=%~3"
  377. @if "%arch%" == "" @exit /b 1
  378. @set "version=%~4"
  379. @if not "%version%" == "" goto :resolve_version_done
  380. :: Find the latest version
  381. @call :log 3 "Finding latest version"
  382. @set version=0.0.0
  383. @for /f "delims=| tokens=1-6" %%a in (%repository%) do @(
  384. @if "%arch%" == "%%a" (
  385. @call :version_compare result "%version%" "%%b"
  386. @if errorlevel 1 (
  387. @call :log 0 "Failed to compare versions: %version% %%a"
  388. @exit /b 1
  389. )
  390. @if !result! lss 0 set version=%%b
  391. )
  392. )
  393. :resolve_version_done
  394. @if "%version%" == "" (
  395. @call :log 0 "Failed to resolve latest version number"
  396. @exit /b 1
  397. )
  398. @call :log 2 "Resolved version: %version%"
  399. @endlocal & set "%var%=%version%"
  400. @goto :eof
  401. :resolve_threading - Gets the threading model of the MinGW compiler
  402. :: %1 - The return variable for the threading model
  403. :: %2 - The repository information to use
  404. :: %3 - The architecture of the compiler
  405. :: %4 - The version of the compiler
  406. :: %5 - threading model of MinGW to use [optional]
  407. @verify other 2>nul
  408. @setlocal EnableDelayedExpansion
  409. @if errorlevel 1 (
  410. @call :log 0 "Failed to enable extensions"
  411. @exit /b 1
  412. )
  413. @set "var=%~1"
  414. @if "%var%" == "" @exit /b 1
  415. @set "repository=%~2"
  416. @if "%repository%" == "" @exit /b 1
  417. @set "arch=%~3"
  418. @if "%arch%" == "" @exit /b 1
  419. @set "version=%~4"
  420. @if "%version%" == "" @exit /b 1
  421. @set "threading=%~5"
  422. @if not "%threading%" == "" goto :resolve_threading_done
  423. @call :log 3 "Finding best threading model"
  424. @for /f "delims=| tokens=1-6" %%a in (%repository%) do @(
  425. @if "%arch%" == "%%a" (
  426. @if "%version%" == "%%b" (
  427. @if not defined threading (
  428. @set "threading=%%c"
  429. )
  430. @if "%%c" == "posix" (
  431. @set "threading=%%c"
  432. ) ) ) )
  433. :resolve_threading_done
  434. @if "%threading%" == "" (
  435. @call :log 0 "Failed to resolve the best threading model"
  436. @exit /b 1
  437. )
  438. @call :log 2 "Resolved threading model: %threading%"
  439. @endlocal & set "%var%=%threading%"
  440. @goto :eof
  441. :resolve_exceptions - Gets the exception model of the MinGW compiler
  442. :: %1 - The return variable for the exception model
  443. :: %2 - The repository information to use
  444. :: %3 - The architecture of the compiler
  445. :: %4 - The version of the compiler
  446. :: %4 - The threading model of the compiler
  447. :: %5 - exception model of MinGW to use [optional]
  448. @verify other 2>nul
  449. @setlocal EnableDelayedExpansion
  450. @if errorlevel 1 (
  451. @call :log 0 "Failed to enable extensions"
  452. @exit /b 1
  453. )
  454. @set "var=%~1"
  455. @if "%var%" == "" @exit /b 1
  456. @set "repository=%~2"
  457. @if "%repository%" == "" @exit /b 1
  458. @set "arch=%~3"
  459. @if "%arch%" == "" @exit /b 1
  460. @set "version=%~4"
  461. @if "%version%" == "" @exit /b 1
  462. @set "threading=%~5"
  463. @if "%threading%" == "" @exit /b 1
  464. @set "exceptions=%~6"
  465. @if not "%exceptions%" == "" goto :resolve_exceptions_done
  466. @call :log 3 "Finding best exception model"
  467. @for /f "delims=| tokens=1-6" %%a in (%repository%) do @(
  468. @if "%arch%" == "%%a" (
  469. @if "%version%" == "%%b" (
  470. @if "%threading%" == "%%c" (
  471. @if not defined exceptions (
  472. @set "exceptions=%%d"
  473. )
  474. @if "%%d" == "dwarf" (
  475. @set "exceptions=%%d"
  476. )
  477. @if "%%d" == "seh" (
  478. @set "exceptions=%%d"
  479. ) ) ) ) )
  480. :resolve_exceptions_done
  481. @if "%exceptions%" == "" (
  482. @call :log 0 "Failed to resolve the best exception model"
  483. @exit /b 1
  484. )
  485. @call :log 2 "Resolved exception model: %exceptions%"
  486. @endlocal & set "%var%=%exceptions%"
  487. @goto :eof
  488. :resolve_revision - Gets the revision of the MinGW compiler
  489. :: %1 - The return variable for the revision
  490. :: %2 - The repository information to use
  491. :: %3 - The architecture of the compiler
  492. :: %4 - The version of the compiler
  493. :: %4 - The threading model of the compiler
  494. :: %4 - The exception model of the compiler
  495. :: %5 - revision of the MinGW package to use [optional]
  496. @verify other 2>nul
  497. @setlocal EnableDelayedExpansion
  498. @if errorlevel 1 (
  499. @call :log 0 "Failed to enable extensions"
  500. @exit /b 1
  501. )
  502. @set "var=%~1"
  503. @if "%var%" == "" @exit /b 1
  504. @set "repository=%~2"
  505. @if "%repository%" == "" @exit /b 1
  506. @set "arch=%~3"
  507. @if "%arch%" == "" @exit /b 1
  508. @set "version=%~4"
  509. @if "%version%" == "" @exit /b 1
  510. @set "threading=%~5"
  511. @if "%threading%" == "" @exit /b 1
  512. @set "exceptions=%~6"
  513. @if "%exceptions%" == "" @exit /b 1
  514. @set "revision=%~7"
  515. @if not "%revision%" == "" goto :resolve_revision_done
  516. @call :log 3 "Finding latest revision"
  517. @for /f "delims=| tokens=1-6" %%a in (%repository%) do @(
  518. @if "%arch%" == "%%a" (
  519. @if "%version%" == "%%b" (
  520. @if "%threading%" == "%%c" (
  521. @if "%exceptions%" == "%%d" (
  522. @if "%%e" gtr "%revision%" (
  523. @set "revision=%%e"
  524. ) ) ) ) ) )
  525. :resolve_revision_done
  526. @if "%revision%" == "" (
  527. @call :log 0 "Failed to resolve latest revision"
  528. @exit /b 1
  529. )
  530. @call :log 2 "Resolved revision: %revision%"
  531. @endlocal & set "%var%=%revision%"
  532. @goto :eof
  533. :version_compare - Compares two semantic version numbers
  534. :: %1 - The return variable:
  535. :: - < 0 : if %2 < %3
  536. :: - 0 : if %2 == %3
  537. :: - > 0 : if %2 > %3
  538. :: %2 - The first version to compare
  539. :: %3 - The second version to compare
  540. @setlocal
  541. @set "var=%~1"
  542. @if "%var%" == "" @exit /b 1
  543. @set "lhs=%~2"
  544. @if "%lhs%" == "" @exit /b 1
  545. @set "rhs=%~3"
  546. @if "%lhs%" == "" @exit /b 1
  547. @set result=0
  548. @for /f "delims=. tokens=1-6" %%a in ("%lhs%.%rhs%") do @(
  549. @if %%a lss %%d (
  550. set result=-1
  551. goto :version_compare_done
  552. ) else (
  553. @if %%a gtr %%d (
  554. set result=1
  555. goto :version_compare_done
  556. ) else (
  557. @if %%b lss %%e (
  558. set result=-1
  559. goto :version_compare_done
  560. ) else (
  561. @if %%b gtr %%e (
  562. set result=1
  563. goto :version_compare_done
  564. ) else (
  565. @if %%c lss %%f (
  566. set result=-1
  567. goto :version_compare_done
  568. ) else (
  569. @if %%c gtr %%f (
  570. set result=1
  571. goto :version_compare_done
  572. )
  573. )
  574. )
  575. )
  576. )
  577. )
  578. )
  579. :version_compare_done
  580. @endlocal & set "%var%=%result%"
  581. @goto :eof
  582. :print_usage - Prints the usage of the script
  583. :: %* - message to print, each argument on it's own line
  584. @setlocal
  585. @for %%a in (%*) do @echo.%%~a
  586. @echo.
  587. @echo.build [/?][/v[v...]^|/q][/version][/arch a][/threading t]
  588. @echo. [/exceptions e][/revision r] location
  589. @echo.
  590. @echo. /version v The version of MinGW to download
  591. @echo. /arch a The target architecture [i686^|x86_64]
  592. @echo. /threading t
  593. @echo. Threading model to use [posix^|win32]
  594. @echo. /exceptions e
  595. @echo. Exception model to use [sjlj^|seh^|dwarf]
  596. @echo. /revision e Revision of the release to use
  597. @echo. /v Sets the output to be more verbose
  598. @echo. /v[v...] Extra verbosity, /vv, /vvv, etc
  599. @echo. /q Quiets the output
  600. @echo. /? Shows this usage message
  601. @echo.
  602. @endlocal
  603. @goto :eof
  604. :script_source - Determines if the script was ran from the cli or explorer
  605. :: %1 - The return variable [cli|explorer]
  606. @verify other 2>nul
  607. @setlocal EnableDelayedExpansion
  608. @if errorlevel 1 (
  609. @call :log 0 "Failed to enable extensions"
  610. @exit /b 1
  611. )
  612. @call :log 3 "Attempting to detect the script source"
  613. @echo "The invocation command was: '%cmdcmdline%'" >> %log_path%
  614. @for /f "tokens=1-3,*" %%a in ("%cmdcmdline%") do @(
  615. set cmd=%%~a
  616. set arg1=%%~b
  617. set arg2=%%~c
  618. set rest=%%~d
  619. )
  620. @set quote="
  621. @if "!arg2:~0,1!" equ "!quote!" (
  622. if "!arg2:~-1!" neq "!quote!" (
  623. set "arg2=!arg2:~1!"
  624. )
  625. )
  626. @call :log 4 "cmd = %cmd%"
  627. @call :log 4 "arg1 = %arg1%"
  628. @call :log 4 "arg2 = %arg2%"
  629. @call :log 4 "rest = %rest%"
  630. @call :log 4 "src = %~f0"
  631. @if /i "%arg2%" == "call" (
  632. set script_source=cli
  633. ) else (
  634. @if /i "%arg1%" == "/c" (
  635. set script_source=explorer
  636. ) else (
  637. set script_source=cli
  638. )
  639. )
  640. @call :log 3 "The script was invoked from %script_source%"
  641. @endlocal & set "%~1=%script_source%"
  642. @goto :eof
  643. :architecture - Finds the system architecture
  644. :: %1 - The return variable [i686|x86_64]
  645. @setlocal
  646. @call :log 3 "Determining the processor architecture"
  647. @set "key=HKLM\System\CurrentControlSet\Control\Session Manager\Environment"
  648. @set "var=PROCESSOR_ARCHITECTURE"
  649. @for /f "skip=2 tokens=2,*" %%a in ('reg query "%key%" /v "%var%"') do @set "arch=%%b"
  650. @if "%arch%" == "AMD64" set arch=x86_64
  651. @if "%arch%" == "x64" set arch=i686
  652. @call :log 4 "arch = %arch%"
  653. @endlocal & set "%~1=%arch%"
  654. @goto :eof
  655. :md5 - Gets the MD5 checksum for a file
  656. :: %1 - The hash
  657. :: %2 - The file path
  658. @setlocal
  659. @set "var=%~1"
  660. @set "file_path=%~2"
  661. @if "%var%" == "" @exit /b 1
  662. @if "%file_path%" == "" @exit /b 1
  663. @if not exist "%file_path%" @exit /b 1
  664. @for /f "skip=3 tokens=1,*" %%a in ('powershell Get-FileHash -Algorithm MD5 "'%file_path%'"') do @set hash=%%b
  665. @if not defined hash (
  666. @call :log 6
  667. @call :log 0 "Failed to get MD5 hash for %file_path%"
  668. @exit /b 1
  669. )
  670. @endlocal & set "%var%=%hash: =%"
  671. @goto :eof
  672. :windows_version - Checks the windows version
  673. :: %1 - The windows version
  674. :: %2 - The major version number return variable
  675. :: %3 - The minor version number return variable
  676. :: %4 - The revision version number return variable
  677. @setlocal
  678. @call :log 3 "Retrieving the Windows version"
  679. @for /f "tokens=2 delims=[]" %%x in ('ver') do @set win_ver=%%x
  680. @set win_ver=%win_ver:Version =%
  681. @set win_ver_major=%win_ver:~0,1%
  682. @set win_ver_minor=%win_ver:~2,1%
  683. @set win_ver_rev=%win_ver:~4%
  684. @call :log 4 "win_ver = %win_ver%"
  685. @endlocal & set "%~1=%win_ver%" ^
  686. & set "%~2=%win_ver_major%" ^
  687. & set "%~3=%win_ver_minor%" ^
  688. & set "%~4=%win_ver_rev%"
  689. @goto :eof
  690. :find_in_path - Finds a program of file in the PATH
  691. :: %1 - return variable of the file path
  692. @setlocal
  693. @set "var=%~1"
  694. @if "%var%" == "" @exit /b 1
  695. @set "file=%~2"
  696. @if "%file%" == "" @exit /b 1
  697. @call :log 3 "Searching PATH for %file%"
  698. @for %%x in ("%file%") do @set "file_path=%%~f$PATH:x"
  699. @if not defined file_path @exit /b 1
  700. @endlocal & set "%var%=%file_path%"
  701. @goto :eof
  702. :log_append - Appends another file into the current logging file
  703. :: %1 - the file_path to the file to concatenate
  704. @setlocal
  705. @set "file_path=%~1"
  706. @if "%file_path%" == "" @exit /b 1
  707. @call :log 3 "Appending to log: %file_path%"
  708. @call :iso8601 iso8601
  709. @set temp_log=%temp%\append-%iso8601%.log
  710. @call :log 4 "Using temp file %temp_log%"
  711. @type "%log_path%" "%file_path%" > "%temp_log%" 2>nul
  712. @move /y "%temp_log%" "%log_path%" 1>nul
  713. @del "%file_path% 2>nul
  714. @del "%temp_log% 2>nul
  715. @endlocal
  716. @goto :eof
  717. :iso8601 - Returns the current time in ISO8601 format
  718. :: %1 - the return variable
  719. :: %2 - format [extended|basic*]
  720. :: iso8601 - contains the resulting timestamp
  721. @setlocal
  722. @wmic Alias /? >NUL 2>&1 || @exit /b 1
  723. @set "var=%~1"
  724. @if "%var%" == "" @exit /b 1
  725. @set "format=%~2"
  726. @if "%format%" == "" set format=basic
  727. @for /F "skip=1 tokens=1-6" %%g IN ('wmic Path Win32_UTCTime Get Day^,Hour^,Minute^,Month^,Second^,Year /Format:table') do @(
  728. @if "%%~l"=="" goto :iso8601_done
  729. @set "yyyy=%%l"
  730. @set "mm=00%%j"
  731. @set "dd=00%%g"
  732. @set "hour=00%%h"
  733. @set "minute=00%%i"
  734. @set "seconds=00%%k"
  735. )
  736. :iso8601_done
  737. @set mm=%mm:~-2%
  738. @set dd=%dd:~-2%
  739. @set hour=%hour:~-2%
  740. @set minute=%minute:~-2%
  741. @set seconds=%seconds:~-2%
  742. @if /i [%format%] == [extended] (
  743. set iso8601=%yyyy%-%mm%-%dd%T%hour%:%minute%:%seconds%Z
  744. ) else (
  745. if /i [%format%] == [basic] (
  746. set iso8601=%yyyy%%mm%%dd%T%hour%%minute%%seconds%Z
  747. ) else (
  748. @exit /b 1
  749. )
  750. )
  751. @set iso8601=%iso8601: =0%
  752. @endlocal & set %var%=%iso8601%
  753. @goto :eof
  754. :verbosity - Processes the verbosity parameter '/v[v...]
  755. :: %1 - verbosity given on the command line
  756. :: logging_level - set to the number of v's
  757. @setlocal
  758. @set logging_level=0
  759. @set verbosity=%~1
  760. :verbosity_loop
  761. @set verbosity=%verbosity:~1%
  762. @if not [%verbosity%] == [] @(
  763. set /a "logging_level=logging_level+1"
  764. goto verbosity_loop
  765. )
  766. @endlocal & set logging_level=%logging_level%
  767. @goto :eof
  768. :log - Logs a message, depending on verbosity
  769. :: %1 - level
  770. :: [0-4] for CLI logging
  771. :: [5-9] for GUI logging
  772. :: %2 - message to print
  773. @setlocal
  774. @set "level=%~1"
  775. @set "msg=%~2"
  776. @if "%log_folder%" == "" (
  777. echo Logging was used to early in the script, log_folder isn't set yet
  778. goto :eof
  779. )
  780. @if "%log_path%" == "" (
  781. echo Logging was used to early in the script, log_path isn't set yet
  782. goto :eof
  783. )
  784. @if not exist "%log_folder%" mkdir "%log_folder%"
  785. @if not exist "%log_path%" echo. 1>nul 2>"%log_path%"
  786. @echo.%msg% >> "%log_path%"
  787. @if %level% geq 5 (
  788. @if [%script_source%] == [explorer] (
  789. set /a "level=level-5"
  790. ) else (
  791. @goto :eof
  792. )
  793. )
  794. @if "%logging_level%" == "" (
  795. echo Logging was used to early in the script, logging_level isn't set yet
  796. goto :eof
  797. )
  798. @if %logging_level% geq %level% echo.%msg% 1>&2
  799. @endlocal
  800. @goto :eof
  801. :download - Downloads a file from the internet
  802. :: %1 - the url of the file to download
  803. :: %2 - the file to download to
  804. :: %3 - the MD5 checksum of the file (optional)
  805. @setlocal EnableDelayedExpansion
  806. @if errorlevel 1 (
  807. @call :print_usage "Failed to enable extensions"
  808. @exit /b 1
  809. )
  810. @set "url=%~1"
  811. @set "file_path=%~2"
  812. @set "checksum=%~3"
  813. @for %%a in (%file_path%) do @set dir_path=%%~dpa
  814. @for %%a in (%file_path%) do @set file_name=%%~nxa
  815. @if "%url%" == "" @exit /b 1
  816. @if "%file_path%" == "" @exit /b 1
  817. @if "%dir_path%" == "" @exit /b 1
  818. @if "%file_name%" == "" @exit /b 1
  819. @if not exist "%dir_path%" mkdir "%dir_path%"
  820. @call :log 2 "Downloading %url%"
  821. @call :iso8601 iso8601
  822. @set "temp_path=%temp%\download-%iso8601%-%file_name%"
  823. @set "log_path=%temp%\download-%iso8601%-log-%file_name%"
  824. @call :log 4 "Using temp file %temp_path%"
  825. @powershell Invoke-WebRequest "'%url%'" ^
  826. -OutFile "'%temp_path%'" ^
  827. -UserAgent [Microsoft.PowerShell.Commands.PSUserAgent]::IE ^
  828. 1>nul 2>"%log_path%"
  829. @if errorlevel 1 (
  830. @call :log 0 "Failed to download %url%"
  831. @call :log_append "%log_path%"
  832. @exit /b 1
  833. )
  834. @if [%checksum%] neq [] (
  835. @call :log 4 "Checking %checksum% against %temp_path%"
  836. @call :md5 hash "%temp_path%"
  837. if "!hash!" neq "%checksum%" (
  838. @call :log 0 "Failed to match checksum: %temp_path%"
  839. @call :log 0 "Hash : !hash!"
  840. @call :log 0 "Checksum: %checksum%"
  841. @exit /b 1
  842. ) else (
  843. @call :log 3 "Checksum matched: %temp_path%"
  844. @call :log 3 "Hash : !hash!"
  845. @call :log 3 "Checksum: %checksum%"
  846. )
  847. )
  848. @call :log 4 "Renaming %temp_path% to %file_path%"
  849. @move /y "%temp_path%" "%file_path%" 1>nul
  850. @endlocal
  851. @goto :eof