bmk_ng.bmx 32 KB

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