bmk_ng.bmx 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664
  1. SuperStrict
  2. Import BRL.Reflection
  3. Import BRL.Map
  4. Import BRL.LinkedList
  5. '?win32
  6. Import Pub.FreeProcess
  7. '?
  8. ?threaded
  9. Import BRL.Threads
  10. Import "bmk_proc_man.bmx"
  11. ?
  12. ?Not win32
  13. Import "waitpid.c"
  14. ?
  15. Import "bmk_config.bmx"
  16. Import "bmk_ng_utils.bmx"
  17. Global processor:TBMK = New TBMK
  18. Global globals:TBMKGlobals = New TBMKGlobals
  19. ' load in the base stuff
  20. LoadBMK(AppDir + "/core.bmk", True)
  21. LoadBMK(AppDir + "/make.bmk", True)
  22. ' optional
  23. LoadBMK(AppDir + "/config.bmk")
  24. ' add some defaults
  25. globals.SetVar("macos_version", String(macos_version))
  26. globals.SetVar("cc_opts", New TOptionVariable)
  27. globals.SetVar("ld_opts", New TOptionVariable)
  28. globals.SetVar("c_opts", New TOptionVariable)
  29. globals.SetVar("cpp_opts", New TOptionVariable)
  30. 'globals.SetVar("gcc_version", String(processor.GCCVersion()))
  31. Function LoadBMK(path:String, required:Int = False)
  32. processor.LoadBMK(path, required)
  33. End Function
  34. ' this is the core bmk processor.
  35. Type TBMK
  36. Field commands:TMap = New TMap
  37. Field buildLog:TList
  38. Field sourceList:TList
  39. Field _minGWBinPath:String
  40. Field _minGWPath:String
  41. Field _minGWLinkPaths:String
  42. Field _minGWDLLCrtPath:String
  43. Field _minGWCrtPath:String
  44. Field _minGWExePrefix:String
  45. Field callback:TCallback
  46. Field _appSettings:TMap
  47. Method New()
  48. LuaRegisterObject Self,"bmk"
  49. End Method
  50. Method Reset()
  51. buildLog = Null
  52. sourceList = Null
  53. _minGWBinPath = Null
  54. _minGWPath = Null
  55. _minGWLinkPaths = Null
  56. _minGWDLLCrtPath = Null
  57. _minGWCrtPath = Null
  58. _minGWExePrefix = Null
  59. End Method
  60. ' loads a .bmk, stores any functions, and runs any commands.
  61. Method LoadBMK(path:String, required:Int = False)
  62. Local str:String
  63. Try
  64. If FileType(path) = 1 Then
  65. str = LoadText( path )
  66. If Int(globals.Get("verbose")) Or opt_verbose
  67. Print "Loading " + path
  68. End If
  69. Else
  70. If FileType(AppDir + "/" + path) = 1 Then
  71. str = LoadText( AppDir + "/" + path )
  72. If Int(globals.Get("verbose")) Or opt_verbose
  73. Print "Loading " + AppDir + "/" + path
  74. End If
  75. Else
  76. If FileType(globals.Get("BUILDPATH") + "/" + path) = 1 Then
  77. str = LoadText(globals.Get("BUILDPATH") + "/" + path )
  78. If Int(globals.Get("verbose")) Or opt_verbose
  79. Print "Loading " + globals.Get("BUILDPATH") + "/" + path
  80. End If
  81. Else
  82. If required Then
  83. Throw "Could not load required config '" + path + "'"
  84. End If
  85. Return
  86. End If
  87. End If
  88. End If
  89. Catch e:Object
  90. Try
  91. If FileType(AppDir + "/" + path) = 1 Then
  92. str = LoadText( AppDir + "/" + path )
  93. If Int(globals.Get("verbose")) Or opt_verbose
  94. Print "Loading " + AppDir + "/" + path
  95. End If
  96. Else
  97. If FileType(globals.Get("BUILDPATH") + "/" + path) = 1 Then
  98. str = LoadText(globals.Get("BUILDPATH") + "/" + path )
  99. If Int(globals.Get("verbose")) Or opt_verbose
  100. Print "Loading " + globals.Get("BUILDPATH") + "/" + path
  101. End If
  102. Else
  103. If required Then
  104. Throw "Could not load required config '" + path + "'"
  105. End If
  106. Return
  107. End If
  108. End If
  109. Catch e:Object
  110. ' we tried... twice
  111. ' fail silently...
  112. ' unless the file was required!
  113. If required Then
  114. Throw "Could not load required config '" + path + "'"
  115. End If
  116. Return
  117. End Try
  118. End Try
  119. Local pos:Int, inDefine:Int, Text:String, name:String
  120. While pos < str.length
  121. Local eol:Int = str.Find( "~n",pos )
  122. If eol = -1 Then
  123. eol = str.length
  124. End If
  125. Local line:String = str[pos..eol].Trim()
  126. pos = eol+1
  127. ProcessLine(line, inDefine, Text, name)
  128. ' anything else?
  129. Wend
  130. End Method
  131. ' processes a pragma
  132. Method ProcessPragma(line:String, inDefine:Int Var, Text:String Var, name:String Var)
  133. ProcessLine(line, inDefine, Text, name)
  134. End Method
  135. Method ProcessLine(line:String, inDefine:Int Var, Text:String Var, name:String Var)
  136. If line.StartsWith("#") Then
  137. Return
  138. End If
  139. Local lline:String = line.ToLower()
  140. If line.StartsWith("@") Then
  141. If lline[1..].StartsWith("define") Then
  142. inDefine = True
  143. name = line[8..].Trim()
  144. Local cmd:TBMKCommand = New TBMKCommand
  145. cmd.name = name
  146. commands.Insert(name.ToLower(), cmd)
  147. Return
  148. End If
  149. If lline[1..].StartsWith("end") Then
  150. If inDefine Then
  151. Local cmd:TBMKCommand = TBMKCommand(commands.ValueForKey(name.ToLower()))
  152. cmd.LoadCommand(Text)
  153. Text = ""
  154. inDefine = False
  155. End If
  156. Return
  157. End If
  158. End If
  159. If inDefine Then
  160. Text:+ line + "~n"
  161. Return
  162. End If
  163. If line.length = 0 Then
  164. Return
  165. End If
  166. ' find command, and run
  167. Local i:Int=1
  168. While i < lline.length And (CharIsAlpha(lline[i]) Or CharIsDigit(lline[i]))
  169. i:+1
  170. Wend
  171. 'If i = lline.length Then
  172. ' Continue
  173. 'End If
  174. Local command:String = lline[..i]
  175. Local cmd:TBMKCommand = TBMKCommand(commands.ValueForKey(command))
  176. ' this is a command!
  177. If cmd Then
  178. cmd.RunCommand(line[i+1..])
  179. Return
  180. End If
  181. ' what's left?
  182. ' setting a variable?
  183. i = line.Find("=")
  184. If i <> -1 Then
  185. ' hmm. maybe a variable...
  186. Local variable:String = line[..i].Trim()
  187. Local value:String = Parse(line[i+1..].Trim())
  188. globals.SetVar(variable, value)
  189. End If
  190. End Method
  191. Method Parse:String(str:String)
  192. Local done:Int
  193. While Not done
  194. Local pos:Int, restart:Int, changed:Int
  195. While pos < str.length And Not restart
  196. Local eol:Int = str.Find( "~n",pos )
  197. If eol = -1 Then
  198. eol = str.length
  199. End If
  200. Local line:String = str[pos..eol].Trim()
  201. pos = eol+1
  202. Local i:Int
  203. While i < line.length
  204. i = line.find("%", i)
  205. If i = -1 Then
  206. i = line.length
  207. Continue
  208. End If
  209. Local start:Int = i
  210. i:+ 1
  211. While i < line.length And (CharIsAlpha(line[i]) Or CharIsDigit(line[i]))
  212. i:+1
  213. Wend
  214. If i > start Then
  215. If line[i..i+1] = "%" Then
  216. i:+ 1
  217. Local toReplace:String = line[start..i]
  218. ' we want to replace this with something, so we
  219. ' will look in the globals list and env for a match.
  220. ' Otherwise, it will swap % with $, and leave it as is.
  221. Local with:String = FindValue(toReplace)
  222. If with Then
  223. str = str.Replace(toReplace, with)
  224. restart = True
  225. End If
  226. End If
  227. End If
  228. Wend
  229. Wend
  230. If Not restart Then
  231. done = True
  232. End If
  233. Wend
  234. Return str
  235. End Method
  236. Method FindValue:String(variable:String)
  237. Local plainVar:String = variable.Replace("%", "")
  238. Local value:String = globals.Get(plainVar)
  239. If value Then
  240. Return value
  241. End If
  242. ' look for environment variable ?
  243. Local env:String = getenv_(plainVar)
  244. If env Then
  245. Return env
  246. End If
  247. ' return the original
  248. Return variable.Replace("%", "$")
  249. End Method
  250. ' quotes a string, if required (does it have spaces in it?)
  251. Method Quote:String(t:String)
  252. Return CQuote(t)
  253. End Method
  254. ' returns the platform as a string
  255. Method Platform:String()
  256. If Not opt_target_platform Then
  257. ' the native target platform
  258. ?raspberrypi
  259. Return "raspberrypi"
  260. ?android
  261. Return "android"
  262. ?macos
  263. Return "macos"
  264. ?linux
  265. Return "linux"
  266. ?win32
  267. Return "win32"
  268. ?emscripten
  269. Return "emscripten"
  270. ?haiku
  271. Return "haiku"
  272. ?
  273. Else
  274. ' the custom target platform
  275. Return opt_target_platform
  276. End If
  277. End Method
  278. Method OSPlatform:String()
  279. ?raspberrypi
  280. Return "raspberrypi"
  281. ?android
  282. Return "android"
  283. ?macos
  284. Return "macos"
  285. ?linux
  286. Return "linux"
  287. ?win32
  288. Return "win32"
  289. ?emscripten
  290. Return "emscripten"
  291. ?haiku
  292. Return "haiku"
  293. ?
  294. End Method
  295. 'returns the app type as a string ("gui", "console" ...)
  296. Method AppType:String()
  297. Return opt_apptype
  298. End Method
  299. ' returns the cpu type, as a string
  300. Method CPU:String()
  301. Return opt_arch
  302. ' Return cputypes[cputype]
  303. End Method
  304. Method ToggleCPU()
  305. If opt_universal Then
  306. Select Platform()
  307. Case "macos"
  308. Select CPU()
  309. Case "ppc"
  310. opt_arch = "x86"
  311. Case "x86"
  312. opt_arch = "ppc"
  313. Case "x64"
  314. opt_arch = "arm64"
  315. Case "arm64"
  316. opt_arch = "x64"
  317. End Select
  318. Case "ios"
  319. Select CPU()
  320. Case "x86"
  321. opt_arch = "x64"
  322. Case "x64"
  323. opt_arch = "x86"
  324. Case "armv7"
  325. opt_arch = "arm64"
  326. Case "arm64"
  327. opt_arch = "armv7"
  328. End Select
  329. End Select
  330. End If
  331. End Method
  332. Method BuildName:String(v:String)
  333. Local s:String = Platform() + "." + CPU() + "." + v
  334. Return s.ToLower()
  335. End Method
  336. Method Sys:Int(cmd:String)
  337. If Int(globals.Get("verbose")) Or opt_verbose
  338. Print cmd
  339. Else If Int(globals.Get("dumpbuild"))
  340. Local p$=cmd
  341. p = p.Replace( BlitzMaxPath()+"/","./" )
  342. WriteStdout p+"~n"
  343. Local t$="mkdir "
  344. If cmd.StartsWith( t ) And FileType( cmd[t.length..] ) Return False
  345. EndIf
  346. If opt_standalone And Not opt_nolog PushLog(cmd)
  347. If Not opt_standalone Or (opt_standalone And opt_nolog) Then
  348. ?win32
  349. Return system_( cmd )
  350. ?Not win32
  351. Local s:Byte Ptr = cmd.ToUtf8String()
  352. Local res:Int = bmx_system(s)
  353. MemFree(s)
  354. Return res
  355. ?
  356. End If
  357. End Method
  358. Method MultiSys:Int(cmd:String, src:String, obj:String, supp:String)
  359. If Int(globals.Get("verbose")) Or opt_verbose
  360. Print cmd
  361. Else If Int(globals.Get("dumpbuild"))
  362. Local p$=cmd
  363. p = p.Replace( BlitzMaxPath()+"/","./" )
  364. WriteStdout p+"~n"
  365. Local t$="mkdir "
  366. If cmd.StartsWith( t ) And FileType( cmd[t.length..] ) Return False
  367. EndIf
  368. If opt_standalone And Not opt_nolog PushLog(cmd)
  369. If Not opt_standalone Or (opt_standalone And opt_nolog) Then
  370. Local threaded:Int
  371. ?threaded
  372. threaded = True
  373. If threaded And Not opt_single Then
  374. processManager.DoSystem(cmd, src, obj, supp)
  375. Else
  376. ?
  377. If obj Then
  378. DeleteFile obj
  379. End If
  380. If supp Then
  381. DeleteFile supp
  382. End If
  383. Local res:Int = system_( cmd )
  384. If Not res Then
  385. If src.EndsWith(".bmx") Then
  386. processor.DoCallback(src)
  387. End If
  388. End If
  389. Return res
  390. ?threaded
  391. End If
  392. ?
  393. End If
  394. End Method
  395. Method ThrowNew(e:String)
  396. Throw e
  397. End Method
  398. Method Call(name:String, args:String[])
  399. RunCommand(name, args)
  400. End Method
  401. Method AddArg(option:String, extra:String)
  402. Local args:String[] = [option]
  403. If extra Then
  404. args:+ [extra]
  405. End If
  406. ParseConfigArgs args
  407. End Method
  408. Method Option:String(key:String, defaultValue:String)
  409. Local value:String = globals.Get(key)
  410. If Not value Then
  411. Return defaultValue
  412. Else
  413. Return value
  414. End If
  415. End Method
  416. Method GCCVersion:String(getVersionNum:Int = False, getRawVersion:Int = False)
  417. '?win32
  418. Global compiler:String
  419. Global version:String
  420. Global rawVersion:String
  421. If compiler Then
  422. If getVersionNum Then
  423. If getRawVersion Then
  424. Return rawVersion
  425. Else
  426. Return version
  427. End If
  428. Else
  429. Return compiler + " " + version
  430. End If
  431. End If
  432. Local process:TProcess
  433. If Platform() = "win32" Then
  434. process = CreateProcess(Option("path_to_gcc", MinGWBinPath() + "/gcc.exe") + " --version", HIDECONSOLE)
  435. Else
  436. process = CreateProcess(Option(BuildName("gcc"), "gcc") + " --version")
  437. End If
  438. If Not process Then
  439. Throw "Cannot find a valid GCC compiler. Please check your paths and environment."
  440. End If
  441. While True
  442. Delay 10
  443. Local line:String = process.pipe.ReadLine()
  444. If Not process.Status() And Not line Then
  445. Exit
  446. End If
  447. Local parts:String[] = line.Split(" ")
  448. If line.startswith("gcc") or parts[0].EndsWith("gcc") Then
  449. compiler = "gcc"
  450. Else If line.startswith("Target:") Then
  451. _target = line[7..].Trim()
  452. Else
  453. Local pos:Int = line.Find("clang")
  454. If pos >= 0 Then
  455. compiler = "clang"
  456. _clang = True
  457. End If
  458. End If
  459. Wend
  460. If process Then
  461. process.Close()
  462. End If
  463. If Int(globals.Get("verbose")) Or opt_verbose
  464. Print "Compiler : " + compiler
  465. Print "Is clang : " + _clang
  466. End If
  467. ' get version
  468. If Platform() = "win32" Then
  469. process = CreateProcess(Option("path_to_gcc", MinGWBinPath() + "/gcc.exe") + " -dumpversion -dumpfullversion", HIDECONSOLE)
  470. Else
  471. process = CreateProcess(Option(BuildName("gcc"), "gcc") + " -dumpversion -dumpfullversion")
  472. End If
  473. Local s:String
  474. While True
  475. Delay 10
  476. Local line:String = process.pipe.ReadLine()
  477. If Not process.Status() And Not line Then
  478. Exit
  479. End If
  480. If Not rawVersion and line Then
  481. rawVersion = line.Trim()
  482. Local count:Int = 0
  483. Local parts:String[] = rawVersion.split("-") ' First split by "-"
  484. For Local part:String = EachIn parts
  485. Local values:String[] = part.split(".") ' Then split by "."
  486. For Local v:String = EachIn values
  487. If IsNumeric(v)
  488. Local n:String = "0" + v
  489. s :+ n[n.length - 2..]
  490. count :+ 1
  491. EndIf
  492. Next
  493. Next
  494. ' Append "00" for each missing segment
  495. For Local i:Int = count To 2
  496. s:+ "00"
  497. Next
  498. End If
  499. Wend
  500. If process Then
  501. process.Close()
  502. End If
  503. version = s
  504. If getVersionNum Then
  505. If getRawVersion Then
  506. Return rawVersion
  507. Else
  508. Return version
  509. End If
  510. End If
  511. If Int(globals.Get("verbose")) Or opt_verbose
  512. Print "Version : " + version
  513. Print "Raw version : " + rawVersion
  514. End If
  515. Return compiler + " " + version
  516. '?
  517. End Method
  518. Function IsNumeric:Int(value:String)
  519. For Local i:Int = 0 Until value.length
  520. If Not CharIsDigit(value[i]) Then
  521. Return False
  522. End If
  523. Next
  524. Return True
  525. End Function
  526. Method XCodeVersion:String()
  527. ?macos
  528. Global xcode:String
  529. Global version:String
  530. If xcode Then
  531. Return version
  532. End If
  533. Local process:TProcess
  534. process = CreateProcess(Option(BuildName("xcodebuild"), "xcodebuild") + " -version")
  535. Local s:String
  536. If Not process Then
  537. Throw "Cannot find xcodebuild. Please check your paths and environment."
  538. End If
  539. While True
  540. Delay 10
  541. Local line:String = process.pipe.ReadLine()
  542. If Not process.Status() And Not line Then
  543. Exit
  544. End If
  545. If line.startswith("Xcode") Then
  546. xcode = line
  547. Local parts:String[] = line.split(" ")
  548. version =parts[1].Trim()
  549. End If
  550. Wend
  551. If process Then
  552. process.Close()
  553. End If
  554. Return version
  555. ?Not macos
  556. Return Null
  557. ?
  558. End Method
  559. Global _target:String
  560. Global _clang:Int
  561. Method HasTarget:Int(find:String)
  562. If Not _target Then
  563. GCCVersion()
  564. End If
  565. If _target Then
  566. If _target.Find(find) >= 0 Then
  567. Return True
  568. End If
  569. End If
  570. Return False
  571. End Method
  572. Method GCCVersionInt:Int()
  573. End Method
  574. Method HasClang:Int()
  575. Return _clang
  576. End Method
  577. Method BCCVersion:String()
  578. Global bcc:String
  579. If bcc Then
  580. Return bcc
  581. End If
  582. Local exe:String = "bcc"
  583. If OSPlatform() = "win32" Then
  584. exe :+ ".exe"
  585. End If
  586. Local process:TProcess = CreateProcess(CQuote(BlitzMaxPath() + "/bin/" + exe), HIDECONSOLE)
  587. Local s:String
  588. If Not process Then
  589. Throw "Cannot find a valid bcc. I am looking for it here : " + BlitzMaxPath() + "/bin/" + exe
  590. End If
  591. While True
  592. Delay 10
  593. Local line:String = process.pipe.ReadLine()
  594. If Not process.Status() And Not line Then
  595. Exit
  596. End If
  597. If line.startswith("BlitzMax") Then
  598. bcc = "BlitzMax"
  599. Else
  600. bcc = line[..line.Find(" ")]
  601. End If
  602. Wend
  603. If process Then
  604. process.Close()
  605. End If
  606. Return bcc
  607. End Method
  608. Method MinGWBinPath:String()
  609. If Not _minGWBinPath Then
  610. _minGWBinPath = MinGWPath() + "/bin"
  611. ?win32
  612. Local PATH:String = _wgetenv("PATH")
  613. PATH = _minGWBinPath + ";" + PATH
  614. _wputenv("PATH=" + PATH)
  615. ?
  616. End If
  617. Return _minGWBinPath
  618. End Method
  619. Method MinGWPath:String()
  620. If Not _minGWPath Then
  621. Local path:String
  622. ' look for local MinGW32 dir
  623. ' some distros (eg. MinGW-w64) only support a single target architecture - x86 or x64
  624. ' to compile for both, requires two separate MinGW installations. Check against
  625. ' CPU target based dir first, before working through the fallbacks.
  626. Local cpuMinGW:String = "/MinGW32x86"
  627. If processor.CPU()="x64" Then
  628. cpuMinGW = "/MinGW32x64"
  629. EndIf
  630. path = BlitzMaxPath() + cpuMinGW + "/bin"
  631. If FileType(path) = FILETYPE_DIR Then
  632. ' bin dir exists, go with that
  633. _minGWPath = BlitzMaxPath() + cpuMinGW
  634. Return _minGWPath
  635. End If
  636. path = BlitzMaxPath() + "/MinGW32/bin"
  637. If FileType(path) = FILETYPE_DIR Then
  638. ' bin dir exists, go with that
  639. _minGWPath = BlitzMaxPath() + "/MinGW32"
  640. Return _minGWPath
  641. End If
  642. path = BlitzMaxPath() + "/MinGW32x86/bin"
  643. If FileType(path) = FILETYPE_DIR Then
  644. ' bin dir exists, go with that
  645. _minGWPath = BlitzMaxPath() + "/MinGW32x86"
  646. Return _minGWPath
  647. End If
  648. path = BlitzMaxPath() + "/MinGW32x64/bin"
  649. If FileType(path) = FILETYPE_DIR Then
  650. ' bin dir exists, go with that
  651. _minGWPath = BlitzMaxPath() + "/MinGW32x64"
  652. Return _minGWPath
  653. End If
  654. path = BlitzMaxPath() + "/llvm-mingw/bin"
  655. If FileType(path) = FILETYPE_DIR Then
  656. ' bin dir exists, go with that
  657. _minGWPath = BlitzMaxPath() + "/llvm-mingw"
  658. Return _minGWPath
  659. End If
  660. ' try MINGW environment variable
  661. path = getenv_("MINGW")
  662. If path And FileType(path) = FILETYPE_DIR Then
  663. ' check for bin dir
  664. If FileType(path + "/bin") = FILETYPE_DIR Then
  665. ' go with that
  666. _minGWPath = path
  667. Return _minGWPath
  668. End If
  669. End If
  670. ' none of the above? fallback to BlitzMax dir (for bin and lib)
  671. _minGWPath = BlitzMaxPath()
  672. End If
  673. Return _minGWPath
  674. End Method
  675. Method MinGWLinkPaths:String()
  676. If Not _minGWLinkPaths Then
  677. Local links:String
  678. If HasClang() Then
  679. Select processor.CPU()
  680. Case "x86"
  681. links :+ " -L" + CQuote(RealPath(MinGWPath() + "/i686-w64-mingw32/lib"))
  682. Case "x64"
  683. links :+ " -L" + CQuote(RealPath(MinGWPath() + "/x86_64-w64-mingw32/lib"))
  684. Case "armv7"
  685. links :+ " -L" + CQuote(RealPath(MinGWPath() + "/armv7-w64-mingw32/lib"))
  686. Case "arm64"
  687. links :+ " -L" + CQuote(RealPath(MinGWPath() + "/aarch64-w64-mingw32/lib"))
  688. End Select
  689. Else If processor.HasTarget("x86_64") Then
  690. If processor.CPU()="x86" Then
  691. links :+ " -L" + CQuote(RealPath(MinGWPath() + "/lib/gcc/x86_64-w64-mingw32/" + GCCVersion(True, True) + "/32"))
  692. links :+ " -L" + CQuote(RealPath(MinGWPath() + "/x86_64-w64-mingw32/lib32"))
  693. Else
  694. links :+ " -L" + CQuote(RealPath(MinGWPath() + "/lib/gcc/x86_64-w64-mingw32/" + GCCVersion(True, True)))
  695. links :+ " -L" + CQuote(RealPath(MinGWPath() + "/x86_64-w64-mingw32/lib"))
  696. End If
  697. Else
  698. links :+ " -L" + CQuote(RealPath(MinGWPath() + "/lib"))
  699. links :+ " -L" + CQuote(RealPath(MinGWPath() +"/lib/gcc/mingw32/" + GCCVersion(True, True)))
  700. End If
  701. _minGWLinkPaths = links
  702. End If
  703. Return _minGWLinkPaths
  704. End Method
  705. ' the path where dllcrt2.o resides
  706. Method MinGWDLLCrtPath:String()
  707. If Not _minGWDLLCrtPath Then
  708. ' mingw64 ?
  709. Local path:String = MinGWPath() + "/"
  710. If processor.HasTarget("x86_64") Then
  711. path :+ "x86_64-w64-mingw32/"
  712. If processor.CPU()="x86" Then
  713. path :+ "lib32"
  714. Else
  715. path :+ "lib"
  716. End If
  717. If FileType(path) = 0 Then
  718. Throw "Could not determine MinGWDLLCrtPath : Expecting '" + path + "'"
  719. End If
  720. _minGWDLLCrtPath = path
  721. Else
  722. path :+ "lib"
  723. If FileType(path) = 0 Then
  724. Throw "Could not determine MinGWDLLCrtPath : Expecting '" + path + "'"
  725. End If
  726. _minGWDLLCrtPath = path
  727. End If
  728. End If
  729. Return RealPath(_minGWDLLCrtPath)
  730. End Method
  731. ' the path where crtbegin.o resides
  732. Method MinGWCrtPath:String()
  733. If Not _minGWCrtPath Then
  734. ' mingw64 ?
  735. Local path:String = MinGWPath() + "/"
  736. If processor.HasTarget("x86_64") Then
  737. path :+ "x86_64-w64-mingw32/"
  738. If processor.CPU()="x86" Then
  739. path :+ "lib32"
  740. Else
  741. path :+ "lib"
  742. End If
  743. If FileType(path) = 0 Then
  744. Throw "Could not determine MinGWCrtPath: Expecting '" + path + "'"
  745. End If
  746. _minGWCrtPath = path
  747. Else
  748. Local p:String = path + "lib/gcc/mingw32/" + GCCVersion(True, True)
  749. If FileType(p) = 0 Then
  750. path :+ "lib/gcc/i686-w64-mingw32/" + GCCVersion(True, True)
  751. Else
  752. path = p
  753. End If
  754. If FileType(path) = 0 Then
  755. Throw "Could not determine MinGWCrtPath: Expecting '" + p + "' or '" + path + "'"
  756. End If
  757. _minGWCrtPath = path
  758. End If
  759. End If
  760. Return RealPath(_minGWCrtPath)
  761. End Method
  762. Method MinGWExePrefix:String()
  763. If Not _minGWExePrefix Then
  764. GCCVersion()
  765. If processor.HasClang() Then
  766. Select processor.CPU()
  767. Case "x86"
  768. _minGWExePrefix = "i686-w64-mingw32uwp-"
  769. Case "x64"
  770. _minGWExePrefix = "x86_64-w64-mingw32uwp-"
  771. Case "armv7"
  772. _minGWExePrefix = "armv7-w64-mingw32-"
  773. Case "arm64"
  774. _minGWExePrefix = "aarch64-w64-mingw32-"
  775. End Select
  776. End If
  777. End If
  778. Return _minGWExePrefix
  779. End Method
  780. Method IsDebugBuild:Int()
  781. Return opt_debug
  782. End Method
  783. Method IsGdbDebugBuild:Int()
  784. Return opt_gdbdebug
  785. End Method
  786. Method IsReleaseBuild:Int()
  787. Return opt_release
  788. End Method
  789. Method IsThreadedBuild:Int()
  790. Return opt_threaded
  791. End Method
  792. Method IsQuickscanBuild:Int()
  793. Return opt_quickscan
  794. End Method
  795. Method IsUniversalBuild:Int()
  796. Return opt_universal
  797. End Method
  798. Method GetModFilter:String()
  799. Return opt_modfilter
  800. End Method
  801. Method GetConfigMung:String()
  802. Return opt_configmung
  803. End Method
  804. Method SupportsHiRes:Int()
  805. Return opt_hi
  806. End Method
  807. Method RunCommand:Object(command:String, args:String[])
  808. Local cmd:TBMKCommand = TBMKCommand(commands.ValueForKey(command.ToLower()))
  809. If cmd Then
  810. ' we need to add the "arg0" string to the front of the array
  811. Local all:String
  812. For Local i:Int = 0 Until args.length
  813. Local arg:String = args[i]
  814. all:+ CQuote$(arg) + " "
  815. Next
  816. args = [ all.Trim() ] + args
  817. ' now we can run the command
  818. Return cmd.RunCommandArgs(args)
  819. End If
  820. End Method
  821. Method PushLog(cmd:String)
  822. If Not buildLog Then
  823. buildLog = New TList
  824. End If
  825. Local p:String = FixPaths(cmd)
  826. buildLog.AddLast(p)
  827. End Method
  828. Method PushSource(src:String)
  829. If Not sourceList Then
  830. sourceList = New TList
  831. End If
  832. Local p:String = FixPaths(src)
  833. sourceList.AddLast(p)
  834. End Method
  835. Method PushEcho(cmd:String)
  836. PushLog("echo ~q" + cmd + "~q")
  837. End Method
  838. Method FixPaths:String(Text:String)
  839. Local p:String = Text
  840. Local bmxRoot:String = "$BMX_ROOT"
  841. If Platform() = "win32" Then
  842. bmxRoot = "%BMX_ROOT%"
  843. End If
  844. Local appRoot:String = "$APP_ROOT"
  845. If Platform() = "win32" Then
  846. appRoot = "%APP_ROOT%"
  847. End If
  848. p = p.Replace(BlitzMaxPath()+"/", bmxRoot + "/")
  849. p = p.Replace(String(globals.GetRawVar("EXEPATH")), appRoot)
  850. Return p
  851. End Method
  852. Method AppDet:String()
  853. Return StripExt(StripDir(app_main)) + "." + opt_apptype + opt_configmung + processor.CPU()
  854. End Method
  855. Method DoCallback(src:String)
  856. If callback Then
  857. callback.DoCallback(src)
  858. End If
  859. End Method
  860. Method VerboseBuild:Int()
  861. Return opt_verbose
  862. End Method
  863. Method AppSetting:String(key:String)
  864. If Not _appSettings Then
  865. _appSettings = ParseApplicationIniFile()
  866. End If
  867. Return String(_appSettings.ValueForKey(key))
  868. End Method
  869. End Type
  870. ?win32
  871. Extern
  872. Function _wgetenv$w(varname$w)
  873. Function _wputenv:Int(varname$w)
  874. End Extern
  875. ?
  876. ' stores variables, as well as a variable stack which can be pushed and popped.
  877. Type TBMKGlobals
  878. ' current value of variables
  879. Field vars:TMap = New TMap
  880. ' variable stack
  881. Field stack:TMap = New TMap
  882. Method New()
  883. LuaRegisterObject Self,"globals"
  884. End Method
  885. ' sets the variable with value
  886. Method SetVar(variable:String, value:Object)
  887. 'Print "SetVar : " + variable + " : " + String(value)
  888. vars.Insert(variable.ToUpper(), value)
  889. End Method
  890. ' returns the current value for variable
  891. Method Get:String(variable:String)
  892. Local obj:Object = vars.ValueForKey(variable.ToUpper())
  893. If obj Then
  894. If String(obj) Then
  895. Return String(obj)
  896. End If
  897. Return obj.ToString()
  898. End If
  899. End Method
  900. Method GetRawVar:Object(variable:String)
  901. Local obj:Object = vars.ValueForKey(variable.ToUpper())
  902. If TOptionVariable(obj) Then
  903. ' return a copy of the object - any changes to this won't affect the current value.
  904. Return TOptionVariable(obj).Clone()
  905. End If
  906. Return obj
  907. End Method
  908. Method GetOptionVar:String(variable:String, name:String)
  909. Local obj:TOptionVariable = TOptionVariable(vars.ValueForKey(variable.ToUpper()))
  910. If obj Then
  911. Return obj.GetVar(name)
  912. End If
  913. End Method
  914. ' push the variable onto the stack (save the value)
  915. Method Push(variable:String)
  916. variable = variable.ToUpper()
  917. Local list:TList = TList(stack.ValueForKey(variable))
  918. If Not list Then
  919. list = New TList
  920. stack.Insert(variable, list)
  921. End If
  922. list.AddLast(GetRawVar(variable))
  923. End Method
  924. ' pop the variable from the stack (load the value)
  925. Method Pop(variable:String)
  926. variable = variable.ToUpper()
  927. Local list:TList = TList(stack.ValueForKey(variable))
  928. If list And Not list.IsEmpty() Then
  929. SetVar(variable, list.RemoveLast())
  930. End If
  931. End Method
  932. ' push all the variables
  933. Method PushAll(exclude:String[] = Null)
  934. For Local v:String = EachIn vars.Keys()
  935. If Not exclude
  936. Push(v)
  937. Else
  938. For Local s:String = EachIn exclude
  939. If s <> v Then
  940. Push(v)
  941. Exit
  942. End If
  943. Next
  944. End If
  945. Next
  946. End Method
  947. ' pop all the variables
  948. Method PopAll()
  949. For Local v:String = EachIn vars.Keys()
  950. Pop(v)
  951. Next
  952. End Method
  953. ' adds value to the end of variable
  954. Method Add(variable:String, value:String, once:Int = False)
  955. If Not AsConfigurable(variable.ToLower(), value) Then
  956. variable = variable.ToUpper()
  957. Local v:Object = vars.ValueForKey(variable)
  958. If Not TOptionVariable(v) Then
  959. If v And Not once Then
  960. SetVar(variable, String(v) + " " + value)
  961. Else
  962. SetVar(variable, value)
  963. End If
  964. End If
  965. End If
  966. End Method
  967. ' adds comma separated value to the end of variable
  968. Method AddC(variable:String, value:String)
  969. If Not AsConfigurable(variable.ToLower(), value) Then
  970. variable = variable.ToUpper()
  971. Local v:Object = vars.ValueForKey(variable)
  972. If Not TOptionVariable(v) Then
  973. If v Then
  974. SetVar(variable, String(v) + "," + value)
  975. Else
  976. SetVar(variable, value)
  977. End If
  978. End If
  979. End If
  980. End Method
  981. Method AddOption(variable:String, key:String, value:String)
  982. variable = variable.ToUpper()
  983. Local v:Object = vars.ValueForKey(variable)
  984. If TOptionVariable(v) Then
  985. TOptionVariable(v).AddVar(key, value)
  986. Else
  987. Local opt:TOptionVariable = New TOptionVariable
  988. opt.addVar(key, value)
  989. setVar(variable, opt)
  990. End If
  991. End Method
  992. Method SetOption(variable:String, key:String, value:String)
  993. variable = variable.ToUpper()
  994. Local v:Object = vars.ValueForKey(variable)
  995. If TOptionVariable(v) Then
  996. TOptionVariable(v).SetVar(key, value)
  997. Else
  998. Local opt:TOptionVariable = New TOptionVariable
  999. opt.SetVar(key, value)
  1000. setVar(variable, opt)
  1001. End If
  1002. End Method
  1003. ' only appropriate for TOptionVariables
  1004. Method RemoveVar(variable:String, name:String)
  1005. variable = variable.ToUpper()
  1006. Local v:Object = vars.ValueForKey(variable)
  1007. If TOptionVariable(v) Then
  1008. TOptionVariable(v).RemoveVar(name)
  1009. End If
  1010. End Method
  1011. Method Clear(variable:String)
  1012. variable = variable.ToUpper()
  1013. Local v:Object = vars.ValueForKey(variable)
  1014. If TOptionVariable(v) Then
  1015. vars.remove(variable)
  1016. End If
  1017. End Method
  1018. Method Reset()
  1019. stack.Clear()
  1020. End Method
  1021. Method Dump()
  1022. For Local k:String = EachIn vars.Keys()
  1023. Print k + " : " + Get(k)
  1024. Next
  1025. End Method
  1026. End Type
  1027. Type TOpt
  1028. Field name:String
  1029. Field value:String
  1030. End Type
  1031. ' holds a list of options.
  1032. ' useful for storing a list of cc_opts, for example.
  1033. ' the list can be modified as required, and cloned during push/pop calls.
  1034. Type TOptionVariable
  1035. Field options:TMap = New TMap
  1036. Field orderedOptions:TList = New TList
  1037. Method AddVar(name:String, value:String)', insertBefore:Int = False)
  1038. Local opt:TOpt = New TOpt
  1039. If Not name Then
  1040. Global count:Int
  1041. count:+1
  1042. name = "VAR" + count
  1043. opt.name = name
  1044. Else
  1045. opt.name = name
  1046. End If
  1047. opt.value = value
  1048. options.Insert(name, opt)
  1049. orderedOptions.AddLast(opt)
  1050. End Method
  1051. Method SetVar(name:String, value:String)', insertBefore:Int = False)
  1052. Local opt:TOpt = New TOpt
  1053. If Not name Then
  1054. Global count:Int
  1055. count:+1
  1056. name = "VAR" + count
  1057. opt.name = name
  1058. Else
  1059. opt.name = name
  1060. End If
  1061. opt.value = value
  1062. ' option already exists?
  1063. Local o:TOpt = TOpt(options.ValueForKey(name))
  1064. If o Then
  1065. orderedOptions.Remove(o)
  1066. End If
  1067. options.Insert(name, opt)
  1068. orderedOptions.AddLast(opt)
  1069. End Method
  1070. Method GetVar:String(name:String)
  1071. Return String(options.ValueForKey(name))
  1072. End Method
  1073. ' finds and removes a matching value
  1074. Method RemoveVar(name:String)
  1075. Local opt:TOpt = TOpt(options.ValueForKey(name))
  1076. options.Remove(opt)
  1077. orderedOptions.Remove(opt)
  1078. End Method
  1079. Method ToString:String()
  1080. Local s:String = " "
  1081. For Local opt:TOpt = EachIn orderedOptions
  1082. s:+ opt.value + " "
  1083. Next
  1084. Return s
  1085. End Method
  1086. ' create an exact copy of me
  1087. Method Clone:TOptionVariable()
  1088. Local me:TOptionVariable = New TOptionVariable
  1089. For Local name:String = EachIn options.Keys()
  1090. me.options.insert(name, options.ValueForKey(name))
  1091. Next
  1092. For Local opt:TOpt = EachIn orderedOptions
  1093. me.orderedOptions.AddLast(opt)
  1094. Next
  1095. Return me
  1096. End Method
  1097. End Type
  1098. ' a bmk function/command
  1099. Type TBMKCommand
  1100. Field name:String
  1101. Field command:String
  1102. Field argCount:Int = 0
  1103. Field class:TLuaClass
  1104. Field instance:TLuaObject
  1105. Method LoadCommand(cmd:String)
  1106. cmd = WrapVariables(ParseArgs(cmd))
  1107. Local code:String = "function bmk_" + name + "(...)~n" + ..
  1108. GetArgs() + ..
  1109. "nvl = function(a1,a2) if a1 == nil then return a2 else return a1 end end~n" + ..
  1110. cmd + ..
  1111. "end"
  1112. class = New TLuaClass.SetSourceCode( code )
  1113. instance = New TLuaObject.Init( class, Null )
  1114. End Method
  1115. Method RunCommand:Object(args:String)
  1116. Return RunCommandArgs([args] + ExtractArgs(args))
  1117. End Method
  1118. ' This assumes we have arg0 + other args
  1119. Method RunCommandArgs:Object(args:Object[])
  1120. Return instance.invoke("bmk_" + name, args)
  1121. End Method
  1122. ' handles quotes and arrays [].
  1123. ' [] inside quotes are ignored.
  1124. Method ExtractArgs:Object[](args:String)
  1125. Local argArray:Object[]
  1126. Local arg:String, arr:String[]
  1127. Local i:Int, inString:Int, inArray:Int
  1128. While i < args.length
  1129. Local c:String = args[i..i+1]
  1130. i:+ 1
  1131. If c = "~q" Then
  1132. If inString Then
  1133. If arg Then
  1134. If Not inArray Then
  1135. argArray:+ [ arg ]
  1136. Else
  1137. arr:+ [ arg ]
  1138. End If
  1139. End If
  1140. arg = ""
  1141. inString = False
  1142. Continue
  1143. Else
  1144. arg = ""
  1145. inString = True
  1146. Continue
  1147. End If
  1148. End If
  1149. If c = " " And Not inString Then
  1150. If arg Then
  1151. If Not inArray Then
  1152. argArray:+ [ arg ]
  1153. Else
  1154. arr:+ [ arg ]
  1155. End If
  1156. arg = ""
  1157. End If
  1158. Continue
  1159. End If
  1160. If c = "[" And Not inString Then
  1161. If Not inArray Then
  1162. inArray = True
  1163. arr = Null
  1164. arg = ""
  1165. Continue
  1166. End If
  1167. End If
  1168. If c = "]" And Not inString Then
  1169. If inArray Then
  1170. If arg Then
  1171. arr:+ [ arg ]
  1172. End If
  1173. inArray = False
  1174. argArray:+ [ arr ]
  1175. arr = Null
  1176. arg = ""
  1177. Continue
  1178. End If
  1179. End If
  1180. arg:+ c
  1181. Wend
  1182. If arg Then
  1183. If arr Then
  1184. arr:+ [arg]
  1185. argArray:+ [arr]
  1186. Else
  1187. argArray:+ [arg]
  1188. End If
  1189. Else
  1190. If arr Then
  1191. argArray:+ [arr]
  1192. End If
  1193. End If
  1194. Return argArray
  1195. End Method
  1196. Method ParseArgs:String(cmd:String)
  1197. ' This needs to process the command text to work out what args are used.
  1198. ' so, for example, arg0, arg1 and arg2.
  1199. ' That way, we generate the correct functionality when we build the function code.
  1200. Local pos:Int
  1201. While pos < cmd.length
  1202. Local eol:Int = cmd.Find( "~n",pos )
  1203. If eol = -1 Then
  1204. eol = cmd.length
  1205. End If
  1206. Local line:String = cmd[pos..eol].Trim()
  1207. pos = eol+1
  1208. Local i:Int
  1209. While i < line.length
  1210. i = line.find("arg", i)
  1211. If i = -1 Then
  1212. i = line.length
  1213. Continue
  1214. End If
  1215. i:+ 3
  1216. Local start:Int = i
  1217. While i < line.length And CharIsDigit(line[i])
  1218. i:+1
  1219. Wend
  1220. Local num:Int = line[start..i].ToInt()
  1221. If num Then
  1222. argCount = Max(argCount, num)
  1223. End If
  1224. Wend
  1225. Wend
  1226. Return cmd
  1227. End Method
  1228. Method GetArgs:String()
  1229. Local args:String = "local arg0"
  1230. Local rep:String = "arg0 = bmk.Parse(arg0)~n"
  1231. If argCount > 0 Then
  1232. For Local i:Int = 1 To argCount
  1233. args:+ ",arg" + i
  1234. rep :+ "arg" + i + " = bmk.Parse(arg" + i + ")~n"
  1235. Next
  1236. End If
  1237. args :+ " = unpack({...})~n"
  1238. args :+ rep
  1239. Return args
  1240. End Method
  1241. Method WrapVariables:String(str:String)
  1242. Local done:Int
  1243. While Not done
  1244. Local pos:Int, restart:Int, changed:Int
  1245. While pos < str.length And Not restart
  1246. Local eol:Int = str.Find( "~n",pos )
  1247. If eol = -1 Then
  1248. eol = str.length
  1249. End If
  1250. Local line:String = str[pos..eol].Trim()
  1251. pos = eol+1
  1252. Local i:Int
  1253. While i < line.length
  1254. i = line.find("%", i)
  1255. If i = -1 Then
  1256. i = line.length
  1257. Continue
  1258. End If
  1259. Local start:Int = i
  1260. i:+ 1
  1261. While i < line.length And (CharIsAlpha(line[i]) Or CharIsDigit(line[i]))
  1262. i:+1
  1263. Wend
  1264. If i > start Then
  1265. If line[i..i+1] = "%" Then
  1266. i:+ 1
  1267. Local toReplace:String = line[start..i]
  1268. Local with:String = "globals.Get(~q" + toReplace.Replace("%", "") + "~q)"
  1269. str = str.Replace(toReplace, with)
  1270. restart = True
  1271. End If
  1272. End If
  1273. Wend
  1274. Wend
  1275. If Not restart Then
  1276. done = True
  1277. End If
  1278. Wend
  1279. Return str
  1280. End Method
  1281. End Type
  1282. ?Not win32
  1283. Extern
  1284. Function bmx_system:Int(cmd:Byte Ptr)
  1285. End Extern
  1286. ?
  1287. Type TProcessTaskFactoryImpl Extends TProcessTaskFactory
  1288. Method Create:TProcessTask( cmd:String, src:String, obj:String, supp:String )
  1289. Return new TProcessTaskImpl.Create(cmd, src, obj, supp)
  1290. End Method
  1291. End Type
  1292. new TProcessTaskFactoryImpl
  1293. Type TProcessTaskImpl Extends TProcessTask
  1294. Field command:String
  1295. Field source:String
  1296. Field obj:String
  1297. Field supp:String
  1298. Method Create:TProcessTask(cmd:String, src:String, obj:String, supp:String)
  1299. command = cmd
  1300. source = src
  1301. Self.obj = obj
  1302. Self.supp = supp
  1303. Return Self
  1304. End Method
  1305. Method DoTasks:Object()
  1306. Local res:Int
  1307. If obj Then
  1308. DeleteFile(obj)
  1309. End If
  1310. If supp Then
  1311. DeleteFile(supp)
  1312. End If
  1313. ?Not win32
  1314. Local s:Byte Ptr = command.ToUtf8String()
  1315. res = bmx_system(s)
  1316. MemFree(s)
  1317. ?win32
  1318. res = system_(command)
  1319. ?
  1320. If res Then
  1321. Local s:String = "Build Error: failed to compile (" + res + ") " + source
  1322. Throw s
  1323. End If
  1324. If source.EndsWith(".bmx") Then
  1325. processor.DoCallback(source)
  1326. End If
  1327. End Method
  1328. End Type
  1329. Type TCallback
  1330. Method DoCallback(src:String) Abstract
  1331. End Type
  1332. ?threaded
  1333. Global processManager:TProcessManager = New TProcessManager
  1334. ?