bmk_make.bmx 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241
  1. Strict
  2. Import "bmk_modutil.bmx"
  3. Rem
  4. Experimental speedup hack by Mark!
  5. Should allow you to modify non-interface affecting code without triggering lots of recompiles.
  6. Works by determining whether blah.bmx's .i file physically changes after blah.bmx is compiled.
  7. If not, then anything importing blah.bmx may not need to be recompiled.
  8. Uses a new '.i2' file which is updated only when actual .i file content changes.
  9. End Rem
  10. Global EXPERIMENTAL_SPEEDUP
  11. Local t$=getenv_( "BMK_SPEEDUP" )
  12. If t EXPERIMENTAL_SPEEDUP=True
  13. Global cc_opts$
  14. Global bcc_opts$
  15. Function BeginMake()
  16. cc_opts=Null
  17. bcc_opts=Null
  18. app_main=Null
  19. opt_framework=""
  20. End Function
  21. Function ConfigureAndroidPaths()
  22. CheckAndroidPaths()
  23. Local toolchain:String
  24. Local arch:String
  25. Local abi:String
  26. Select processor.CPU()
  27. Case "x86"
  28. toolchain = "x86-"
  29. arch = "arch-x86"
  30. abi = "x86"
  31. Case "x64"
  32. toolchain = "x86_64-"
  33. arch = "arch-x86_64"
  34. abi = "x86_64"
  35. Case "arm", "armeabi", "armeabiv7a"
  36. toolchain = "arm-linux-androideabi-"
  37. arch = "arch-arm"
  38. If processor.CPU() = "armeabi" Then
  39. abi = "armeabi"
  40. Else
  41. abi = "armeabi-v7a"
  42. End If
  43. Case "arm64v8a"
  44. toolchain = "aarch64-linux-android-"
  45. arch = "arch-arm64"
  46. abi = "arm64-v8a"
  47. End Select
  48. Local native:String
  49. ?macos
  50. native = "darwin"
  51. ?linux
  52. native = "linux"
  53. ?win32
  54. native = "windows"
  55. ?
  56. Local toolchainDir:String = processor.Option("android.ndk", "") + "/toolchains/" + ..
  57. toolchain + processor.Option("android.toolchain.version", "") + "/prebuilt/" + native
  58. ' look for 64 bit build first, then x86, then fallback to no architecture (generally on 32-bit dists)
  59. If FileType(toolchainDir + "-x86_64") = FILETYPE_DIR Then
  60. toolchainDir :+ "-x86_64"
  61. Else If FileType(toolchainDir + "-x86") = FILETYPE_DIR Then
  62. toolchainDir :+ "-x86"
  63. Else If FileType(toolchainDir) <> FILETYPE_DIR Then
  64. Throw "Cannot determine toolchain dir for '" + native + "', at '" + toolchainDir + "'"
  65. End If
  66. Local exe:String
  67. ?win32
  68. exe = ".exe"
  69. ?
  70. Local gccPath:String = toolchainDir + "/bin/" + toolchain + "gcc" + exe
  71. Local gppPath:String = toolchainDir + "/bin/" + toolchain + "g++" + exe
  72. Local arPath:String = toolchainDir + "/bin/" + toolchain + "ar" + exe
  73. Local libPath:String = toolchainDir + "/lib"
  74. ' check paths
  75. If Not FileType(RealPath(gccPath)) Then
  76. Throw "gcc not found at '" + gccPath + "'"
  77. End If
  78. If Not FileType(RealPath(gppPath)) Then
  79. Throw "g++ not found at '" + gppPath + "'"
  80. End If
  81. If Not FileType(RealPath(gccPath)) Then
  82. Throw "ar not found at '" + arPath + "'"
  83. End If
  84. globals.SetVar("android." + processor.CPU() + ".gcc", gccPath)
  85. globals.SetVar("android." + processor.CPU() + ".gpp", gppPath)
  86. globals.SetVar("android." + processor.CPU() + ".ar", arPath)
  87. globals.SetVar("android." + processor.CPU() + ".lib", "-L" + libPath)
  88. ' platform
  89. Local platformDir:String = processor.Option("android.ndk", "") + "/platforms/android-" + ..
  90. processor.Option("android.platform", "") + "/" + arch
  91. If Not FileType(platformDir) Then
  92. Throw "Cannot determine platform dir for '" + arch + "' at '" + platformDir + "'"
  93. End If
  94. ' platform sysroot
  95. globals.SetVar("android.platform.sysroot", "--sysroot " + platformDir)
  96. globals.AddOption("cc_opts", "android.platform.sysroot", "--sysroot " + platformDir)
  97. ' abi
  98. globals.SetVar("android.abi", abi)
  99. ' sdk target
  100. Local target:String = GetAndroidSDKTarget()
  101. If Not target Or Not FileType(processor.Option("android.sdk", "") + "/platforms/android-" + target) Then
  102. Local sdkPath:String = processor.Option("android.sdk.target", "")
  103. If sdkPath Then
  104. Throw "Cannot determine SDK target for '" + sdkPath + "'"
  105. Else
  106. Throw "Cannot determine SDK target dir. ANDROID_SDK_TARGET or android.sdk.target option is not set, and auto-lookup failed."
  107. End If
  108. End If
  109. globals.SetVar("android.sdk.target", target)
  110. End Function
  111. Function CheckAndroidPaths()
  112. ' check envs and paths
  113. Local androidHome:String = getenv_("ANDROID_HOME")
  114. If Not androidHome Then
  115. androidHome = processor.Option("android.home", "")
  116. If Not androidHome Then
  117. Throw "ANDROID_HOME or 'android.home' config option not set"
  118. End If
  119. putenv_("ANDROID_HOME=" + androidHome.Trim())
  120. Else
  121. globals.SetVar("android.home", androidHome)
  122. End If
  123. Local androidSDK:String = getenv_("ANDROID_SDK")
  124. If Not androidSDK Then
  125. androidSDK = processor.Option("android.sdk", "")
  126. If Not androidSDK Then
  127. Throw "ANDROID_SDK or 'android.sdk' config option not set"
  128. End If
  129. putenv_("ANDROID_SDK=" + androidSDK.Trim())
  130. Else
  131. globals.SetVar("android.sdk", androidSDK)
  132. End If
  133. Local androidNDK:String = getenv_("ANDROID_NDK")
  134. If Not androidNDK Then
  135. androidNDK = processor.Option("android.ndk", "")
  136. If Not androidNDK Then
  137. Throw "ANDROID_NDK or 'android.ndk' config option not set"
  138. End If
  139. putenv_("ANDROID_NDK=" + androidNDK.Trim())
  140. Else
  141. globals.SetVar("android.ndk", androidNDK)
  142. End If
  143. Local androidToolchainVersion:String = getenv_("ANDROID_TOOLCHAIN_VERSION")
  144. If Not androidToolchainVersion Then
  145. androidToolchainVersion = processor.Option("android.toolchain.version", "")
  146. If Not androidToolchainVersion Then
  147. Throw "ANDROID_TOOLCHAIN_VERSION or 'android.toolchain.version' config option not set"
  148. End If
  149. putenv_("ANDROID_TOOLCHAIN_VERSION=" + androidToolchainVersion.Trim())
  150. Else
  151. globals.SetVar("android.toolchain.version", androidToolchainVersion)
  152. End If
  153. Local androidPlatform:String = getenv_("ANDROID_PLATFORM")
  154. If Not androidPlatform Then
  155. androidPlatform = processor.Option("android.platform", "")
  156. If Not androidPlatform Then
  157. Throw "ANDROID_PLATFORM or 'android.platform' config option not set"
  158. End If
  159. putenv_("ANDROID_PLATFORM=" + androidPlatform.Trim())
  160. Else
  161. globals.SetVar("android.platform", androidPlatform)
  162. End If
  163. Local androidSDKTarget:String = getenv_("ANDROID_SDK_TARGET")
  164. If Not androidSDKTarget Then
  165. androidSDKTarget = processor.Option("android.sdk.target", "")
  166. If androidSDKTarget Then
  167. putenv_("ANDROID_SDK_TARGET=" + androidSDKTarget.Trim())
  168. End If
  169. ' NOTE : if not set, we'll try to determine the actual target later, and fail if required then.
  170. Else
  171. globals.SetVar("android.sdk.target", androidSDKTarget)
  172. End If
  173. Local antHome:String = getenv_("ANT_HOME")
  174. If Not antHome Then
  175. antHome = processor.Option("ant.home", "")
  176. If Not antHome Then
  177. ' as a further fallback, we can use the one from resources folder if it exists.
  178. Local antDir:String = RealPath(BlitzMaxPath() + "/resources/android/apache-ant")
  179. If FileType(antDir) <> FILETYPE_DIR Then
  180. Throw "ANT_HOME or 'ant.home' config option not set, and resources missing apache-ant."
  181. Else
  182. antHome = antDir
  183. globals.SetVar("ant.home", antHome)
  184. End If
  185. End If
  186. putenv_("ANT_HOME=" + antHome.Trim())
  187. Else
  188. globals.SetVar("ant.home", antHome)
  189. End If
  190. ?Not win32
  191. Local pathSeparator:String = ":"
  192. Local dirSeparator:String = "/"
  193. ?win32
  194. Local pathSeparator:String = ";"
  195. Local dirSeparator:String = "\"
  196. ?
  197. Local path:String = getenv_("PATH")
  198. path = androidSDK.Trim() + dirSeparator + "platform-tools" + pathSeparator + path
  199. path = androidSDK.Trim() + dirSeparator + "tools" + pathSeparator + path
  200. path = androidNDK.Trim() + pathSeparator + path
  201. path = antHome.Trim() + dirSeparator + "bin" + pathSeparator + path
  202. putenv_("PATH=" + path)
  203. End Function
  204. Function ConfigureIOSPaths()
  205. Select processor.CPU()
  206. Case "x86", "x64"
  207. Local path:String = "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk"
  208. globals.SetVar("ios.sysroot", path)
  209. globals.SetVar("ios.syslibroot", path)
  210. Case "armv7", "arm64"
  211. Local path:String = "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk"
  212. globals.SetVar("ios.sysroot", path)
  213. globals.SetVar("ios.syslibroot", path)
  214. End Select
  215. End Function
  216. Type TBuildManager
  217. Field sources:TMap = New TMap
  218. Field buildAll:Int
  219. Field framework_mods:TList
  220. Method New()
  221. ' pre build checks
  222. If processor.Platform() = "android" Then
  223. ConfigureAndroidPaths()
  224. Else If processor.Platform() = "ios" Then
  225. ConfigureIOSPaths()
  226. End If
  227. End Method
  228. Method MakeMods(mods:TList, rebuild:Int = False)
  229. For Local m:String = EachIn mods
  230. If (opt_modfilter And ((m).Find(opt_modfilter) = 0)) Or (Not opt_modfilter) Then
  231. GetMod(m, rebuild Or buildAll)
  232. End If
  233. Next
  234. End Method
  235. Method MakeApp(main_path:String, makelib:Int)
  236. app_main = main_path
  237. Local source:TSourceFile = GetSourceFile(app_main, False, opt_all)
  238. If Not source Then
  239. Return
  240. End If
  241. Local build_path:String = ExtractDir(main_path) + "/.bmx"
  242. source.obj_path = build_path + "/" + StripDir( main_path ) + "." + opt_apptype + opt_configmung + processor.CPU() + ".o"
  243. source.obj_time = FileTime(source.obj_path)
  244. source.iface_path = StripExt(source.obj_path) + ".o"
  245. source.iface_time = FileTime(source.iface_path)
  246. Local cc_opts:String = " -I" + CQuote(ModulePath(""))
  247. If opt_release Then
  248. cc_opts :+ " -DNDEBUG"
  249. End If
  250. Local bcc_opts:String = " -g " + processor.CPU()
  251. If opt_quiet bcc_opts:+" -q"
  252. If opt_verbose bcc_opts:+" -v"
  253. If opt_release bcc_opts:+" -r"
  254. If opt_threaded bcc_opts:+" -h"
  255. If opt_framework bcc_opts:+" -f " + opt_framework
  256. If opt_gdbdebug And processor.BCCVersion() <> "BlitzMax" Then
  257. bcc_opts:+" -d"
  258. End If
  259. source.cc_opts :+ cc_opts
  260. source.modimports.AddLast("brl.blitz")
  261. source.modimports.AddLast(opt_appstub)
  262. If source.framewk
  263. If opt_framework Then
  264. Throw "Framework already specified on commandline"
  265. End If
  266. opt_framework = source.framewk
  267. bcc_opts :+" -f " + opt_framework
  268. source.modimports.AddLast(opt_framework)
  269. Else
  270. framework_mods = New TList
  271. For Local t:String = EachIn EnumModules()
  272. If t.Find("brl.") = 0 Or t.Find("pub.") = 0 Then
  273. If t <> "brl.blitz" And t <> opt_appstub Then
  274. source.modimports.AddLast(t)
  275. framework_mods.AddLast(t)
  276. End If
  277. End If
  278. Next
  279. End If
  280. source.bcc_opts = bcc_opts
  281. source.requiresBuild = opt_all
  282. CalculateDependencies(source, False, opt_all)
  283. source.bcc_opts :+ " -t " + opt_apptype
  284. ' create bmx stages :
  285. Local gen:TSourceFile
  286. ' for osx x86 on legacy, we need to convert asm
  287. If processor.BCCVersion() = "BlitzMax" And processor.CPU() = "x86" And processor.Platform() = "macos" Then
  288. Local fasm2as:TSourceFile = CreateFasm2AsStage(source)
  289. gen = CreateGenStage(fasm2as)
  290. Else
  291. gen = CreateGenStage(source)
  292. End If
  293. Local link:TSourceFile = CreateLinkStage(gen)
  294. End Method
  295. Method DoBuild(app_build:Int = False)
  296. Local arc_order:TList = New TList
  297. Local files:TList = New TList
  298. For Local file:TSourceFile = EachIn sources.Values()
  299. files.AddLast(file)
  300. Next
  301. ' get the list of parallelizable batches
  302. ' each list of batches has no outstanding dependencies, and therefore
  303. ' can be compiled in parallel.
  304. ' the last list of batches requires all previous lists to have
  305. ' been compiled.
  306. Local batches:TList = CalculateBatches(files)
  307. For Local batch:TList = EachIn batches
  308. Local s:String
  309. For Local m:TSourceFile = EachIn batch
  310. ' sort archives for app linkage
  311. If m.modid Then
  312. Local path:String = m.arc_path
  313. If processor.Platform() = "ios" Then
  314. path = m.merge_path
  315. End If
  316. If Not arc_order.Contains(path) Then
  317. arc_order.AddFirst(path)
  318. End If
  319. End If
  320. Local build_path:String = ExtractDir(m.path) + "/.bmx"
  321. If Not FileType(build_path) Then
  322. CreateDir build_path
  323. End If
  324. If FileType(build_path) <> FILETYPE_DIR Then
  325. Throw "Unable to create temporary directory"
  326. End If
  327. ' change dir, so relative commands work as expected
  328. ' (eg. file processing in BMK-scripts called via pragma)
  329. ChangeDir ExtractDir( m.path )
  330. ' bmx file
  331. If Match(m.ext, "bmx") Then
  332. Select m.stage
  333. Case STAGE_GENERATE
  334. If m.requiresBuild Or (m.time > m.obj_time Or m.iface_time < m.MaxIfaceTime()) Then
  335. m.requiresBuild = True
  336. If Not opt_quiet Then
  337. Print ShowPct(m.pct) + "Processing:" + StripDir(m.path)
  338. End If
  339. ' process pragmas
  340. Local pragma_inDefine:Int, pragma_text:String, pragma_name:String
  341. For Local pragma:String = EachIn m.pragmas
  342. processor.ProcessPragma(pragma, pragma_inDefine, pragma_text, pragma_name)
  343. Next
  344. CompileBMX m.path, m.obj_path, m.bcc_opts
  345. m.iface_time = time_(Null)
  346. End If
  347. Case STAGE_FASM2AS
  348. For Local s:TSourceFile = EachIn m.depsList
  349. If s.requiresBuild Then
  350. m.requiresBuild = True
  351. Exit
  352. End If
  353. Next
  354. If m.requiresBuild Or (m.time > m.obj_time Or m.iface_time < m.MaxIfaceTime()) Then
  355. m.requiresBuild = True
  356. If Not opt_quiet Then
  357. Print ShowPct(m.pct) + "Converting:" + StripDir(StripExt(m.obj_path) + ".s")
  358. End If
  359. Fasm2As m.path, m.obj_path
  360. m.asm_time = time_(Null)
  361. End If
  362. Case STAGE_OBJECT
  363. If m.requiresBuild Or (m.time > m.obj_time Or m.iface_time < m.MaxIfaceTime()) Then
  364. m.requiresBuild = True
  365. If processor.BCCVersion() <> "BlitzMax" Then
  366. Local csrc_path:String = StripExt(m.obj_path) + ".c"
  367. Local cobj_path:String = StripExt(m.obj_path) + ".o"
  368. If Not opt_quiet Then
  369. Print ShowPct(m.pct) + "Compiling:" + StripDir(csrc_path)
  370. End If
  371. CompileC csrc_path,cobj_path, m.cc_opts
  372. Else
  373. ' asm compilation
  374. Local src_path:String = StripExt(m.obj_path) + ".s"
  375. Local obj_path:String = StripExt(m.obj_path) + ".o"
  376. If Not opt_quiet Then
  377. Print ShowPct(m.pct) + "Compiling:" + StripDir(src_path)
  378. End If
  379. Assemble src_path, obj_path
  380. End If
  381. m.obj_time = time_(Null)
  382. End If
  383. Case STAGE_LINK
  384. ' a module?
  385. If m.modid Then
  386. Local max_obj_time:Int = m.MaxObjTime()
  387. If max_obj_time > m.arc_time And Not m.dontbuild Then
  388. Local objs:TList = New TList
  389. m.GetObjs(objs)
  390. If Not opt_quiet Then
  391. Print ShowPct(m.pct) + "Archiving:" + StripDir(m.arc_path)
  392. End If
  393. CreateArc m.arc_path, objs
  394. m.arc_time = time_(Null)
  395. m.obj_time = time_(Null)
  396. End If
  397. Else
  398. ' this probably should never happen.
  399. ' may be a bad module?
  400. If Not opt_outfile Then
  401. Throw "Build Error: Did not expect to link against " + m.path
  402. End If
  403. ' an app!
  404. Local max_lnk_time:Int = m.MaxLinkTime()
  405. If max_lnk_time > FileTime(opt_outfile) Or opt_all Then
  406. If Not opt_quiet Then
  407. Print ShowPct(m.pct) + "Linking:" + StripDir(opt_outfile)
  408. End If
  409. Local links:TList = New TList
  410. Local opts:TList = New TList
  411. m.GetLinks(links, opts)
  412. For Local arc:String = EachIn arc_order
  413. links.AddLast(arc)
  414. Next
  415. For Local o:String = EachIn opts
  416. links.AddLast(o)
  417. Next
  418. LinkApp opt_outfile, links, False, globals.Get("ld_opts")
  419. m.obj_time = time_(Null)
  420. End If
  421. End If
  422. Case STAGE_MERGE
  423. ' a module?
  424. If m.modid Then
  425. Local max_obj_time:Int = m.MaxObjTime()
  426. If max_obj_time > m.merge_time And Not m.dontbuild Then
  427. If Not opt_quiet Then
  428. Print ShowPct(m.pct) + "Merging:" + StripDir(m.merge_path)
  429. End If
  430. CreateMergeArc m.merge_path, m.arc_path
  431. m.merge_time = time_(Null)
  432. End If
  433. End If
  434. End Select
  435. Else If Match(m.ext, "s") Then
  436. If m.time > m.obj_time Then ' object is older or doesn't exist
  437. m.requiresBuild = True
  438. End If
  439. If m.requiresBuild Then
  440. If Not opt_quiet Then
  441. Print ShowPct(m.pct) + "Compiling:" + StripDir(m.path)
  442. End If
  443. If processor.BCCVersion() = "BlitzMax" Then
  444. Assemble m.path, m.obj_path
  445. Else
  446. CompileC m.path, m.obj_path, m.cc_opts
  447. End If
  448. End If
  449. Else
  450. If Not m.dontbuild Then
  451. ' c/c++ source
  452. If m.time > m.obj_time Then ' object is older or doesn't exist
  453. m.requiresBuild = True
  454. End If
  455. If m.requiresBuild Then
  456. If Not opt_quiet Then
  457. Print ShowPct(m.pct) + "Compiling:" + StripDir(m.path)
  458. End If
  459. CompileC m.path, m.obj_path, m.cc_opts
  460. m.obj_time = time_(Null)
  461. End If
  462. End If
  463. End If
  464. Next
  465. ?threaded
  466. processManager.WaitForTasks()
  467. ?
  468. Next
  469. If app_build Then
  470. ' post process
  471. LoadBMK(ExtractDir(app_main) + "/post.bmk")
  472. If processor.Platform() = "android"
  473. ' create the apk
  474. ' copy shared object
  475. Local androidABI:String = processor.Option("android.abi", "")
  476. Local appId:String = StripDir(StripExt(opt_outfile))
  477. Local buildDir:String = ExtractDir(opt_outfile)
  478. Local projectDir:String = buildDir + "/android-project-" + appId
  479. Local abiPath:String = projectDir + "/libs/" + androidABI
  480. Local sharedObject:String = "lib" + appId + ".so"
  481. CopyFile(buildDir + "/" + sharedObject, abiPath + "/" + sharedObject)
  482. ' build the apk :
  483. Local antHome:String = processor.Option("ant.home", "").Trim()
  484. Local cmd:String = "~q" + antHome + "/bin/ant"
  485. ?win32
  486. cmd :+ ".bat"
  487. ?
  488. cmd :+ "~q debug"
  489. Local dir:String = CurrentDir()
  490. ChangeDir(projectDir)
  491. If opt_dumpbuild Then
  492. Print cmd
  493. End If
  494. If Sys( cmd ) Then
  495. Throw "Error creating apk"
  496. End If
  497. ChangeDir(dir)
  498. End If
  499. Else If processor.Platform() = "ios" Then
  500. Local iosSimulator:Int = (processor.CPU() = "x86")
  501. ' TODO - other stuff ?
  502. End If
  503. End Method
  504. Method CalculateDependencies(source:TSourceFile, isMod:Int = False, rebuildImports:Int = False, isInclude:Int = False)
  505. If source And Not source.processed Then
  506. source.processed = True
  507. For Local m:String = EachIn source.modimports
  508. Local s:TSourceFile = GetMod(m)
  509. If s Then
  510. If Not source.moddeps Then
  511. source.moddeps = New TMap
  512. End If
  513. If Not source.moddeps.ValueForKey(m) Then
  514. source.moddeps.Insert(m, s)
  515. source.deps.Insert(s.GetSourcePath(), s)
  516. source.cc_opts :+ " -I" + CQuote(ExtractDir(s.path))
  517. End If
  518. End If
  519. Next
  520. For Local f:String = EachIn source.imports
  521. If f[0] <> Asc("-") Then
  522. Local path:String = CheckPath(ExtractDir(source.path), f)
  523. Local s:TSourceFile = GetSourceFile(path, isMod)
  524. If s Then
  525. If rebuildImports Then
  526. s.requiresBuild = rebuildImports
  527. End If
  528. If Match(s.ext, "bmx") Then
  529. s.modimports.AddLast("brl.blitz")
  530. ' app source files need framework/mod dependencies applied
  531. If Not isMod Then
  532. If opt_framework Then
  533. ' add framework as dependency
  534. s.modimports.AddLast(opt_framework)
  535. Else
  536. ' add all pub/brl mods as dependency
  537. If framework_mods Then
  538. For Local m:String = EachIn framework_mods
  539. s.modimports.AddLast(m)
  540. Next
  541. End If
  542. End If
  543. End If
  544. s.bcc_opts = source.bcc_opts
  545. s.cc_opts :+ source.cc_opts
  546. CalculateDependencies(s, isMod, rebuildImports)
  547. ' if file that we generate is missing, we need to rebuild
  548. If processor.BCCVersion() = "BlitzMax" Then
  549. If Not FileType(StripExt(s.obj_path) + ".s") Then
  550. s.requiresBuild = True
  551. End If
  552. Else
  553. If Not FileType(StripExt(s.obj_path) + ".c") Then
  554. s.requiresBuild = True
  555. End If
  556. End If
  557. Local gen:TSourceFile
  558. ' for osx x86 on legacy, we need to convert asm
  559. If processor.BCCVersion() = "BlitzMax" And processor.CPU() = "x86" And processor.Platform() = "macos" Then
  560. Local fasm2as:TSourceFile = CreateFasm2AsStage(s)
  561. gen = CreateGenStage(fasm2as)
  562. Else
  563. gen = CreateGenStage(s)
  564. End If
  565. source.deps.Insert(gen.GetSourcePath(), gen)
  566. If Not source.depsList Then
  567. source.depsList = New TList
  568. End If
  569. source.depsList.AddLast(gen)
  570. Else
  571. s.cc_opts = source.cc_opts
  572. source.deps.Insert(s.GetSourcePath(), s)
  573. If Not source.depsList Then
  574. source.depsList = New TList
  575. End If
  576. source.depsList.AddLast(s)
  577. End If
  578. Else
  579. Local ext:String = ExtractExt(path)
  580. If Match(ext, "h;hpp;hxx") Then ' header?
  581. source.cc_opts :+ " -I" + CQuote(ExtractDir(path))
  582. Else If Match(ext, "o") Then ' object?
  583. Local s:TSourceFile = New TSourceFile
  584. s.time = FileTime(path)
  585. s.obj_time = s.time
  586. s.path = path
  587. s.obj_path = path
  588. s.modid = source.modid
  589. If s.time > source.time Then
  590. source.time = s.time
  591. End If
  592. If Not source.depsList Then
  593. source.depsList = New TList
  594. End If
  595. source.depsList.AddLast(s)
  596. End If
  597. End If
  598. Else
  599. If Not source.ext_files Then
  600. source.ext_files = New TList
  601. End If
  602. source.ext_files.AddLast(f)
  603. End If
  604. Next
  605. For Local f:String = EachIn source.includes
  606. Local path:String = CheckPath(ExtractDir(source.path), f)
  607. Local s:TSourceFile = GetSourceFile(path, isMod, rebuildImports, True)
  608. If s Then
  609. ' calculate included file dependencies
  610. CalculateDependencies(s, isMod, rebuildImports)
  611. ' update our time to latest included time
  612. If s.time > source.time Then
  613. source.time = s.time
  614. End If
  615. If Not source.depsList Then
  616. source.depsList = New TList
  617. End If
  618. source.depsList.AddLast(s)
  619. End If
  620. Next
  621. For Local f:String = EachIn source.incbins
  622. Local path:String = CheckPath(ExtractDir(source.path), f)
  623. Local time:Int = FileTime(path)
  624. ' update our time to the latest incbin time
  625. If time > source.time Then
  626. source.time = time
  627. End If
  628. Next
  629. If source.depsList Then
  630. For Local s:TSourceFile = EachIn source.depsList
  631. If Not Match(s.ext, "bmx") Then
  632. s.cc_opts = source.cc_opts
  633. End If
  634. Next
  635. End If
  636. End If
  637. End Method
  638. Method GetSourceFile:TSourceFile(source_path:String, isMod:Int = False, rebuild:Int = False, isInclude:Int = False)
  639. Local source:TSourceFile = TSourceFile(sources.ValueForKey(source_path))
  640. If Not source Then
  641. source = ParseSourceFile(source_path)
  642. If source Then
  643. Local ext:String = ExtractExt(source_path)
  644. If Match(ext, ALL_SRC_EXTS) Then
  645. If Not isInclude Then
  646. sources.Insert(source_path, source)
  647. source.obj_path = ExtractDir(source_path) + "/.bmx/" + StripDir(source_path) + opt_configmung + processor.CPU() + ".o"
  648. source.obj_time = FileTime(source.obj_path)
  649. If Match(ext, "bmx") Then
  650. source.iface_path = ExtractDir(source_path) + "/.bmx/" + StripDir(source_path) + opt_configmung + processor.CPU() + ".i"
  651. source.iface_time = FileTime(source.iface_path)
  652. End If
  653. End If
  654. End If
  655. End If
  656. End If
  657. Return source
  658. End Method
  659. Method GetISourceFile:TSourceFile(arc_path:String, arc_time:Int, iface_path:String, iface_time:Int, merge_path:String, merge_time:Int)
  660. Local source:TSourceFile
  661. If processor.Platform() = "ios" Then
  662. source = TSourceFile(sources.ValueForKey(merge_path))
  663. Else
  664. source = TSourceFile(sources.ValueForKey(arc_path))
  665. End If
  666. If Not source Then
  667. source = ParseISourceFile(iface_path)
  668. If source Then
  669. source.arc_path = arc_path
  670. source.arc_time = arc_time
  671. source.iface_path = iface_path
  672. source.iface_time = iface_time
  673. source.merge_time = merge_time
  674. If processor.Platform() = "ios" Then
  675. sources.Insert(merge_path, source)
  676. Else
  677. sources.Insert(arc_path, source)
  678. End If
  679. End If
  680. End If
  681. Return source
  682. End Method
  683. Method GetMod:TSourceFile(m:String, rebuild:Int = False)
  684. If (opt_all And ((opt_modfilter And ((m).Find(opt_modfilter) = 0)) Or (Not opt_modfilter)) And Not app_main) Or (app_main And opt_standalone) Then
  685. rebuild = True
  686. End If
  687. Local path:String = ModulePath(m)
  688. Local id:String = ModuleIdent(m)
  689. ' get the module interface and lib details
  690. Local arc_path:String = path + "/" + id + opt_configmung + processor.CPU() + ".a"
  691. Local arc_time:Int = FileTime(arc_path)
  692. Local iface_path:String = path + "/" + id + opt_configmung + processor.CPU() + ".i"
  693. Local iface_time:Int = FileTime(iface_path)
  694. Local merge_path:String
  695. Local merge_time:Int
  696. If processor.Platform() = "ios" Then
  697. If processor.CPU() = "x86" Or processor.CPU() = "x64" Then
  698. merge_path = path + "/" + id + opt_configmung + "sim.a"
  699. Else
  700. merge_path = path + "/" + id + opt_configmung + "dev.a"
  701. End If
  702. merge_time = FileTime(merge_path)
  703. End If
  704. Local source:TSourceFile
  705. Local link:TSourceFile
  706. If arc_time And iface_time And opt_quickscan Then
  707. source = GetISourceFile(arc_path, arc_time, iface_path, iface_time, merge_path, merge_time)
  708. If Not source Then
  709. Return Null
  710. End If
  711. If Not source.processed Then
  712. source.modid = m
  713. source.arc_path = arc_path
  714. source.arc_time = arc_time
  715. source.iface_path = iface_path
  716. source.iface_time = iface_time
  717. source.obj_path = arc_path
  718. source.merge_path = merge_path
  719. source.merge_time = merge_time
  720. CalculateDependencies(source, True, rebuild)
  721. source.dontbuild = True
  722. If processor.Platform() = "ios" Then
  723. source.stage = STAGE_MERGE
  724. sources.Insert(source.merge_path, source)
  725. Else
  726. source.stage = STAGE_LINK
  727. sources.Insert(source.arc_path, source)
  728. End If
  729. End If
  730. link = source
  731. Else
  732. Local src_path:String = path + "/" + id + ".bmx"
  733. source = GetSourceFile(src_path, True, rebuild)
  734. If Not source Then
  735. Return Null
  736. End If
  737. ' main module file without "Module" line?
  738. If Not source.modid Then
  739. Return Null
  740. End If
  741. End If
  742. If Not source.processed Then
  743. source.arc_path = arc_path
  744. source.arc_time = arc_time
  745. source.iface_path = iface_path
  746. source.iface_time = iface_time
  747. source.merge_path = merge_path
  748. source.merge_time = merge_time
  749. Local cc_opts:String = " -I" + CQuote(path)
  750. cc_opts :+ " -I" + CQuote(ModulePath(""))
  751. If opt_release Then
  752. cc_opts :+ " -DNDEBUG"
  753. End If
  754. If opt_threaded Then
  755. cc_opts :+ " -DTHREADED"
  756. End If
  757. source.cc_opts = ""
  758. If source.mod_opts Then
  759. source.cc_opts :+ source.mod_opts.cc_opts
  760. End If
  761. source.cc_opts :+ cc_opts
  762. ' Module BCC opts
  763. Local bcc_opts:String = " -g "+processor.CPU()
  764. bcc_opts :+ " -m " + m
  765. If opt_quiet bcc_opts:+" -q"
  766. If opt_verbose bcc_opts:+" -v"
  767. If opt_release bcc_opts:+" -r"
  768. If opt_threaded bcc_opts:+" -h"
  769. If opt_gdbdebug And processor.BCCVersion() <> "BlitzMax" Then
  770. bcc_opts:+" -d"
  771. End If
  772. source.bcc_opts = bcc_opts
  773. source.requiresBuild = rebuild
  774. ' interface is REQUIRED for compilation
  775. If Not iface_time Then
  776. source.requiresBuild = True
  777. End If
  778. If m <> "brl.blitz" Then
  779. source.modimports.AddLast("brl.blitz")
  780. End If
  781. CalculateDependencies(source, True, rebuild)
  782. ' create bmx stages :
  783. Local gen:TSourceFile
  784. ' for osx x86 on legacy, we need to convert asm
  785. If processor.BCCVersion() = "BlitzMax" And processor.CPU() = "x86" And processor.Platform() = "macos" Then
  786. Local fasm2as:TSourceFile = CreateFasm2AsStage(source)
  787. gen = CreateGenStage(fasm2as)
  788. Else
  789. gen = CreateGenStage(source)
  790. End If
  791. If processor.Platform() <> "ios" Then
  792. link = CreateLinkStage(gen)
  793. Else
  794. Local realLink:TSourceFile = CreateLinkStage(gen)
  795. ' create a fat archive
  796. link = CreateMergeStage(realLink)
  797. End If
  798. Else
  799. If processor.Platform() = "ios" Then
  800. link = TSourceFile(sources.ValueForKey(source.merge_path))
  801. Else
  802. link = TSourceFile(sources.ValueForKey(source.arc_path))
  803. End If
  804. If Not link Then
  805. Throw "Can't find link for : " + source.path
  806. End If
  807. End If
  808. Return link
  809. End Method
  810. Method CreateFasm2AsStage:TSourceFile(source:TSourceFile)
  811. Local fasm:TSourceFile = New TSourceFile
  812. source.CopyInfo(fasm)
  813. fasm.deps.Insert(source.path, source)
  814. fasm.stage = STAGE_FASM2AS
  815. fasm.processed = True
  816. fasm.depsList = New TList
  817. fasm.depsList.AddLast(source)
  818. sources.Insert(StripExt(fasm.obj_path) + ".s", fasm)
  819. Return fasm
  820. End Method
  821. Method CreateGenStage:TSourceFile(source:TSourceFile)
  822. Local gen:TSourceFile = New TSourceFile
  823. source.CopyInfo(gen)
  824. If processor.BCCVersion() = "BlitzMax" And processor.CPU() = "x86" And processor.Platform() = "macos" Then
  825. gen.deps.Insert(StripExt(source.obj_path) + ".s", source)
  826. Else
  827. gen.deps.Insert(source.path, source)
  828. End If
  829. gen.stage = STAGE_OBJECT
  830. gen.processed = True
  831. gen.depsList = New TList
  832. gen.depsList.AddLast(source)
  833. sources.Insert(StripExt(gen.obj_path) + ".c", gen)
  834. Return gen
  835. End Method
  836. Method CreateLinkStage:TSourceFile(source:TSourceFile)
  837. Local link:TSourceFile = New TSourceFile
  838. source.CopyInfo(link)
  839. link.deps.Insert(StripExt(link.obj_path) + ".c", source)
  840. link.stage = STAGE_LINK
  841. link.processed = True
  842. link.depsList = New TList
  843. link.depsList.AddLast(source)
  844. If processor.Platform() = "ios" Then
  845. sources.Insert(link.obj_path, link)
  846. Else
  847. sources.Insert(link.arc_path, link)
  848. End If
  849. Return link
  850. End Method
  851. Method CreateMergeStage:TSourceFile(source:TSourceFile)
  852. Local merge:TSourceFile = New TSourceFile
  853. source.CopyInfo(merge)
  854. merge.deps.Insert(merge.obj_path, source)
  855. merge.stage = STAGE_MERGE
  856. merge.processed = True
  857. merge.depsList = New TList
  858. merge.depsList.AddLast(source)
  859. sources.Insert(merge.merge_path, merge)
  860. Return merge
  861. End Method
  862. Method CalculateBatches:TList(files:TList)
  863. Local batches:TList = New TList
  864. Local count:Int
  865. Local instances:TMap = New TMap
  866. For Local m:TSourceFile = EachIn files
  867. instances.Insert(m.GetSourcePath(), m)
  868. count :+ 1
  869. Next
  870. Local dependencies:TMap = New TMap
  871. For Local m:TSourceFile = EachIn files
  872. dependencies.Insert(m.GetSourcePath(), m.deps)
  873. Next
  874. Local pct:Float = 100.0 / count
  875. Local total:Float
  876. Local num:Int
  877. While Not dependencies.IsEmpty()
  878. Local noDeps:TList = New TList
  879. For Local depName:String = EachIn dependencies.Keys()
  880. Local dep:TMap = TMap(dependencies.ValueForKey(depName))
  881. If dep.IsEmpty() Then
  882. noDeps.AddLast(depName)
  883. End If
  884. Next
  885. If noDeps.IsEmpty() Then
  886. ' circular dependency!
  887. ' TODO : dump current list for user to work out?
  888. Print "REMAINING :"
  889. For Local depName:String = EachIn dependencies.Keys()
  890. Print " " + depName
  891. Next
  892. Throw "circular dependency!"
  893. End If
  894. ' remove from dependencies
  895. For Local name:String = EachIn noDeps
  896. dependencies.Remove(name)
  897. Next
  898. For Local dep:TMap = EachIn dependencies.Values()
  899. For Local name:String = EachIn noDeps
  900. dep.Remove(name)
  901. Next
  902. Next
  903. Local list:TList = New TList
  904. For Local name:String = EachIn noDeps
  905. Local m:TSourceFile = TSourceFile(instances.ValueForKey(name))
  906. list.AddLast(m)
  907. total :+ pct
  908. num :+ 1
  909. If num = count Then
  910. m.pct = 100
  911. Else
  912. m.pct = total
  913. End If
  914. Next
  915. batches.AddLast(list)
  916. Wend
  917. Return batches
  918. End Method
  919. Method ShowPct:String(pct:Int)
  920. Local s:String = "["
  921. Local p:String = String.FromInt(pct)
  922. Select p.length
  923. Case 1
  924. s :+ " "
  925. Case 2
  926. s :+ " "
  927. End Select
  928. Return s + p + "%] "
  929. End Method
  930. Method CheckPath:String(basePath:String, path:String)
  931. Local p:String = RealPath(basePath + "/" + path)
  932. If Not FileType(p) Then
  933. ' maybe path is a full path already?
  934. p = RealPath(path)
  935. If Not FileType(p) Then
  936. ' meh... fallback to original
  937. p = RealPath(basePath + "/" + path)
  938. End If
  939. End If
  940. Return p
  941. End Method
  942. End Type