bmk_make.bmx 52 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928
  1. SuperStrict
  2. Import "bmk_modutil.bmx"
  3. Global cc_opts$
  4. Global bcc_opts$
  5. Global cpp_opts$
  6. Global c_opts$
  7. Global asm_opts:String
  8. Function BeginMake()
  9. cc_opts=Null
  10. cpp_opts=Null
  11. c_opts=Null
  12. bcc_opts=Null
  13. asm_opts=Null
  14. app_main=Null
  15. opt_framework=""
  16. End Function
  17. Function ConfigureAndroidPaths()
  18. CheckAndroidPaths()
  19. Local toolchain:String
  20. Local toolchainBin:String
  21. Local arch:String
  22. Local abi:String
  23. Select processor.CPU()
  24. Case "x86"
  25. toolchain = "x86-"
  26. toolchainBin = "i686-linux-android-"
  27. arch = "arch-x86"
  28. abi = "x86"
  29. Case "x64"
  30. toolchain = "x86_64-"
  31. toolchainBin = "x86_64-linux-android-"
  32. arch = "arch-x86_64"
  33. abi = "x86_64"
  34. Case "arm", "armeabi", "armeabiv7a"
  35. toolchain = "arm-linux-androideabi-"
  36. toolchainBin = "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. toolchainBin = "aarch64-linux-android-"
  46. arch = "arch-arm64"
  47. abi = "arm64-v8a"
  48. End Select
  49. Local native:String
  50. ?macos
  51. native = "darwin"
  52. ?linux
  53. native = "linux"
  54. ?win32
  55. native = "windows"
  56. ?
  57. Local toolchainDir:String = processor.Option("android.ndk", "") + "/toolchains/" + ..
  58. toolchain + processor.Option("android.toolchain.version", "") + "/prebuilt/" + native
  59. ' look for 64 bit build first, then x86, then fallback to no architecture (generally on 32-bit dists)
  60. If FileType(toolchainDir + "-x86_64") = FILETYPE_DIR Then
  61. toolchainDir :+ "-x86_64"
  62. Else If FileType(toolchainDir + "-x86") = FILETYPE_DIR Then
  63. toolchainDir :+ "-x86"
  64. Else If FileType(toolchainDir) <> FILETYPE_DIR Then
  65. Throw "Cannot determine toolchain dir for '" + native + "', at '" + toolchainDir + "'"
  66. End If
  67. Local exe:String
  68. ?win32
  69. exe = ".exe"
  70. ?
  71. Local gccPath:String = toolchainDir + "/bin/" + toolchainBin + "gcc" + exe
  72. Local gppPath:String = toolchainDir + "/bin/" + toolchainBin + "g++" + exe
  73. Local arPath:String = toolchainDir + "/bin/" + toolchainBin + "ar" + exe
  74. Local libPath:String = toolchainDir + "/lib"
  75. ' check paths
  76. If Not FileType(RealPath(gccPath)) Then
  77. Throw "gcc not found at '" + gccPath + "'"
  78. End If
  79. If Not FileType(RealPath(gppPath)) Then
  80. Throw "g++ not found at '" + gppPath + "'"
  81. End If
  82. If Not FileType(RealPath(gccPath)) Then
  83. Throw "ar not found at '" + arPath + "'"
  84. End If
  85. globals.SetVar("android." + processor.CPU() + ".gcc", gccPath)
  86. globals.SetVar("android." + processor.CPU() + ".gpp", gppPath)
  87. globals.SetVar("android." + processor.CPU() + ".ar", arPath)
  88. globals.SetVar("android." + processor.CPU() + ".lib", "-L" + libPath)
  89. ' platform
  90. Local platformDir:String = processor.Option("android.ndk", "") + "/platforms/android-" + ..
  91. processor.Option("android.platform", "") + "/" + arch
  92. If Not FileType(platformDir) Then
  93. Throw "Cannot determine platform dir for '" + arch + "' at '" + platformDir + "'"
  94. End If
  95. ' platform sysroot
  96. globals.SetVar("android.platform.sysroot", "--sysroot " + platformDir)
  97. globals.AddOption("cc_opts", "android.platform.sysroot", "--sysroot " + platformDir)
  98. ' abi
  99. globals.SetVar("android.abi", abi)
  100. ' sdk target
  101. Local target:String = GetAndroidSDKTarget()
  102. If Not target Or Not FileType(processor.Option("android.sdk", "") + "/platforms/android-" + target) Then
  103. Local sdkPath:String = processor.Option("android.sdk.target", "")
  104. If sdkPath Then
  105. Throw "Cannot determine SDK target for '" + sdkPath + "'"
  106. Else
  107. Throw "Cannot determine SDK target dir. ANDROID_SDK_TARGET or android.sdk.target option is not set, and auto-lookup failed."
  108. End If
  109. End If
  110. globals.SetVar("android.sdk.target", target)
  111. End Function
  112. Function CheckAndroidPaths()
  113. ' check envs and paths
  114. Local androidHome:String = processor.Option("android.home", getenv_("ANDROID_HOME")).Trim()
  115. If Not androidHome Then
  116. Throw "ANDROID_HOME or 'android.home' config option not set"
  117. End If
  118. putenv_("ANDROID_HOME=" + androidHome)
  119. globals.SetVar("android.home", androidHome)
  120. Local androidSDK:String = processor.Option("android.sdk", getenv_("ANDROID_SDK")).Trim()
  121. If Not androidSDK Then
  122. Throw "ANDROID_SDK or 'android.sdk' config option not set"
  123. End If
  124. putenv_("ANDROID_SDK=" + androidSDK)
  125. globals.SetVar("android.sdk", androidSDK)
  126. Local androidNDK:String = processor.Option("android.ndk", getenv_("ANDROID_NDK")).Trim()
  127. If Not androidNDK Then
  128. Throw "ANDROID_NDK or 'android.ndk' config option not set"
  129. End If
  130. putenv_("ANDROID_NDK=" + androidNDK)
  131. globals.SetVar("android.ndk", androidNDK)
  132. Local androidToolchainVersion:String = processor.Option("android.toolchain.version", getenv_("ANDROID_TOOLCHAIN_VERSION")).Trim()
  133. If Not androidToolchainVersion Then
  134. Throw "ANDROID_TOOLCHAIN_VERSION or 'android.toolchain.version' config option not set"
  135. End If
  136. putenv_("ANDROID_TOOLCHAIN_VERSION=" + androidToolchainVersion)
  137. globals.SetVar("android.toolchain.version", androidToolchainVersion)
  138. Local androidPlatform:String = processor.Option("android.platform", getenv_("ANDROID_PLATFORM")).Trim()
  139. If Not androidPlatform Then
  140. Throw "ANDROID_PLATFORM or 'android.platform' config option not set"
  141. End If
  142. putenv_("ANDROID_PLATFORM=" + androidPlatform.Trim())
  143. globals.SetVar("android.platform", androidPlatform)
  144. Local androidSDKTarget:String = processor.Option("android.sdk.target", getenv_("ANDROID_SDK_TARGET")).Trim()
  145. ' NOTE : if not set, we'll try to determine the actual target later, and fail if required then.
  146. If androidSDKTarget Then
  147. putenv_("ANDROID_SDK_TARGET=" + androidSDKTarget)
  148. globals.SetVar("android.sdk.target", androidSDKTarget)
  149. End If
  150. Local antHome:String = processor.Option("ant.home", getenv_("ANT_HOME")).Trim()
  151. If Not antHome Then
  152. ' as a further fallback, we can use the one from resources folder if it exists.
  153. Local antDir:String = RealPath(BlitzMaxPath() + "/resources/android/apache-ant")
  154. If FileType(antDir) <> FILETYPE_DIR Then
  155. Throw "ANT_HOME or 'ant.home' config option not set, and resources missing apache-ant."
  156. Else
  157. antHome = antDir
  158. globals.SetVar("ant.home", antHome)
  159. End If
  160. End If
  161. putenv_("ANT_HOME=" + antHome)
  162. globals.SetVar("ant.home", antHome)
  163. ?Not win32
  164. Local pathSeparator:String = ":"
  165. Local dirSeparator:String = "/"
  166. ?win32
  167. Local pathSeparator:String = ";"
  168. Local dirSeparator:String = "\"
  169. ?
  170. Local path:String = getenv_("PATH")
  171. path = androidSDK + dirSeparator + "platform-tools" + pathSeparator + path
  172. path = androidSDK + dirSeparator + "tools" + pathSeparator + path
  173. path = androidNDK + pathSeparator + path
  174. path = antHome + dirSeparator + "bin" + pathSeparator + path
  175. putenv_("PATH=" + path)
  176. End Function
  177. Function ConfigureIOSPaths()
  178. Select processor.CPU()
  179. Case "x86", "x64"
  180. Local path:String = "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk"
  181. globals.SetVar("ios." + processor.CPU() + ".sysroot", path)
  182. globals.SetVar("ios." + processor.CPU() + ".syslibroot", path)
  183. Case "armv7", "arm64"
  184. Local path:String = "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk"
  185. globals.SetVar("ios." + processor.CPU() + ".sysroot", path)
  186. globals.SetVar("ios." + processor.CPU() + ".syslibroot", path)
  187. End Select
  188. End Function
  189. Function ConfigureNXPaths()
  190. CheckNXPaths()
  191. Local toolchainBin:String
  192. Select processor.CPU()
  193. Case "arm64"
  194. toolchainBin = "aarch64-none-elf-"
  195. End Select
  196. Local toolchainDir:String = processor.Option("nx.devkitpro", "") + "/devkitA64/"
  197. If FileType(RealPath(toolchainDir)) <> FILETYPE_DIR Then
  198. Throw "Cannot determine toolchain dir for NX, at '" + toolchainDir + "'"
  199. End If
  200. Local exe:String
  201. ?win32
  202. exe = ".exe"
  203. ?
  204. Local gccPath:String = toolchainDir + "/bin/" + toolchainBin + "gcc" + exe
  205. Local gppPath:String = toolchainDir + "/bin/" + toolchainBin + "g++" + exe
  206. Local arPath:String = toolchainDir + "/bin/" + toolchainBin + "ar" + exe
  207. Local libPath:String = toolchainDir + "/lib"
  208. ' check paths
  209. If Not FileType(RealPath(gccPath)) Then
  210. Throw "gcc not found at '" + gccPath + "'"
  211. End If
  212. If Not FileType(RealPath(gppPath)) Then
  213. Throw "g++ not found at '" + gppPath + "'"
  214. End If
  215. If Not FileType(RealPath(gccPath)) Then
  216. Throw "ar not found at '" + arPath + "'"
  217. End If
  218. globals.SetVar("nx." + processor.CPU() + ".gcc", gccPath)
  219. globals.SetVar("nx." + processor.CPU() + ".gpp", gppPath)
  220. globals.SetVar("nx." + processor.CPU() + ".ar", arPath)
  221. globals.SetVar("nx." + processor.CPU() + ".lib", "-L" + libPath)
  222. ?Not win32
  223. Local pathSeparator:String = ":"
  224. Local dirSeparator:String = "/"
  225. ?win32
  226. Local pathSeparator:String = ";"
  227. Local dirSeparator:String = "\"
  228. ?
  229. Local path:String = getenv_("PATH")
  230. path = toolchainDir + dirSeparator + "bin" + pathSeparator + path
  231. putenv_("PATH=" + path)
  232. End Function
  233. Function CheckNXPaths()
  234. ' check envs and paths
  235. Local devkitpro:String = processor.Option("nx.devkitpro", getenv_("DEVKITPRO")).Trim()
  236. If Not devkitpro Then
  237. Throw "DEVKITPRO or 'nx.devkitpro' config option not set"
  238. End If
  239. putenv_("DEVKITPRO=" + devkitpro)
  240. globals.SetVar("nx.devkitpro", devkitpro)
  241. End Function
  242. Type TBuildManager Extends TCallback
  243. Field sources:TMap = New TMap
  244. Field buildAll:Int
  245. Field framework_mods:TList
  246. Field app_iface:String
  247. Method New()
  248. ' pre build checks
  249. If processor.Platform() = "android" Then
  250. ConfigureAndroidPaths()
  251. Else If processor.Platform() = "ios" Then
  252. ConfigureIOSPaths()
  253. Else If processor.Platform() = "nx" Then
  254. ConfigureNXPaths()
  255. End If
  256. If processor.Platform() = "linux" Or processor.Platform() = "raspberrypi" Then
  257. If opt_nopie Then
  258. globals.SetVar("nopie", "true")
  259. End If
  260. End If
  261. processor.callback = Self
  262. End Method
  263. Method MakeMods(mods:TList, rebuild:Int = False)
  264. For Local m:String = EachIn mods
  265. If (opt_modfilter And ((m).Find(opt_modfilter) = 0)) Or (Not opt_modfilter) Then
  266. GetMod(m, rebuild Or buildAll)
  267. End If
  268. Next
  269. End Method
  270. Method MakeApp(main_path:String, makelib:Int, compileOnly:Int = False)
  271. app_main = main_path
  272. Local source:TSourceFile = GetSourceFile(app_main, False, opt_all)
  273. If Not source Then
  274. Return
  275. End If
  276. Local build_path:String = ExtractDir(main_path) + "/.bmx"
  277. Local appType:String
  278. If Not compileOnly Or source.framewk Then
  279. appType = "." + opt_apptype
  280. End If
  281. source.obj_path = build_path + "/" + StripDir( main_path ) + appType + opt_configmung + processor.CPU() + ".o"
  282. source.obj_time = FileTime(source.obj_path)
  283. source.iface_path = StripExt(source.obj_path) + ".i"
  284. source.iface_time = FileTime(source.iface_path)
  285. app_iface = source.iface_path
  286. Local cc_opts:String
  287. source.AddIncludePath(" -I" + CQuote(ModulePath("")))
  288. If opt_release And Not opt_gdbdebug Then
  289. cc_opts :+ " -DNDEBUG"
  290. End If
  291. If processor.BCCVersion() <> "BlitzMax" Then
  292. If opt_gdbdebug Then
  293. cc_opts :+ " -g"
  294. End If
  295. If opt_gprof Then
  296. cc_opts :+ " -pg"
  297. End If
  298. If opt_coverage Then
  299. cc_opts :+ " -DBMX_COVERAGE"
  300. End If
  301. End If
  302. Local sb:TStringBuffer = New TStringBuffer
  303. sb.Append(" -g ").Append(processor.CPU())
  304. If opt_quiet sb.Append(" -q")
  305. If opt_verbose sb.Append(" -v")
  306. If opt_release sb.Append(" -r")
  307. If opt_threaded sb.Append(" -h")
  308. If opt_framework sb.Append(" -f ").Append(opt_framework)
  309. If processor.BCCVersion() <> "BlitzMax" Then
  310. If opt_gdbdebug Then
  311. sb.Append(" -d")
  312. End If
  313. If Not opt_nostrictupgrade Then
  314. sb.Append(" -s")
  315. End If
  316. If opt_warnover Then
  317. sb.Append(" -w")
  318. End If
  319. If opt_musl Then
  320. sb.Append(" -musl")
  321. End If
  322. If makelib Then
  323. sb.Append(" -makelib")
  324. If opt_nodef Then
  325. sb.append(" -nodef")
  326. End If
  327. If opt_nohead Then
  328. sb.append(" -nohead")
  329. End If
  330. End If
  331. If opt_require_override Then
  332. sb.Append(" -override")
  333. If opt_override_error Then
  334. sb.Append(" -overerr")
  335. End If
  336. End If
  337. Local defs:String = opt_userdefs
  338. If globals.Get("user_defs") Then
  339. If defs Then
  340. defs :+ ","
  341. End If
  342. defs :+ globals.Get("user_defs")
  343. End If
  344. If defs Then
  345. sb.Append(" -ud ").Append(defs)
  346. End If
  347. If opt_standalone Then
  348. sb.Append(" -ib")
  349. End If
  350. If opt_coverage Then
  351. sb.Append(" -cov")
  352. End If
  353. If opt_no_auto_superstrict Then
  354. sb.Append(" -nas")
  355. End If
  356. End If
  357. source.cc_opts :+ cc_opts
  358. source.cpp_opts :+ cpp_opts
  359. source.c_opts :+ c_opts
  360. source.modimports.AddLast("brl.blitz")
  361. source.modimports.AddLast(opt_appstub)
  362. If source.framewk
  363. If opt_framework Then
  364. Throw "Framework already specified on commandline"
  365. End If
  366. opt_framework = source.framewk
  367. sb.Append(" -f ").Append(opt_framework)
  368. source.modimports.AddLast(opt_framework)
  369. Else
  370. framework_mods = New TList
  371. For Local t:String = EachIn EnumModules()
  372. If t.Find("brl.") = 0 Or t.Find("pub.") = 0 Then
  373. If t <> "brl.blitz" And t <> opt_appstub Then
  374. source.modimports.AddLast(t)
  375. framework_mods.AddLast(t)
  376. End If
  377. End If
  378. Next
  379. End If
  380. source.bcc_opts = sb.ToString()
  381. source.SetRequiresBuild(opt_all)
  382. CalculateDependencies(source, False, opt_all)
  383. source.bcc_opts :+ " -t " + opt_apptype
  384. ' create bmx stages :
  385. Local gen:TSourceFile
  386. ' for osx x86 on legacy, we need to convert asm
  387. If processor.BCCVersion() = "BlitzMax" And processor.CPU() = "x86" And processor.Platform() = "macos" Then
  388. Local fasm2as:TSourceFile = CreateFasm2AsStage(source)
  389. gen = CreateGenStage(fasm2as)
  390. Else
  391. gen = CreateGenStage(source)
  392. End If
  393. If Not compileOnly Then
  394. Local link:TSourceFile = CreateLinkStage(gen, STAGE_APP_LINK)
  395. End If
  396. End Method
  397. Method DoBuild(makelib:Int, app_build:Int = False)
  398. Local arc_order:TList = New TList
  399. Local files:TList = New TList
  400. For Local file:TSourceFile = EachIn sources.Values()
  401. files.AddLast(file)
  402. Next
  403. ' get the list of parallelizable batches
  404. ' each list of batches has no outstanding dependencies, and therefore
  405. ' can be compiled in parallel.
  406. ' the last list of batches requires all previous lists to have
  407. ' been compiled.
  408. Local batches:TList = CalculateBatches(files)
  409. For Local batch:TList = EachIn batches
  410. Local s:String
  411. For Local m:TSourceFile = EachIn batch
  412. ' sort archives for app linkage
  413. If m.modid Then
  414. Local path:String = m.arc_path
  415. If IOS_HAS_MERGE And processor.Platform() = "ios" Then
  416. path = m.merge_path
  417. End If
  418. If Not arc_order.Contains(path) Then
  419. arc_order.AddFirst(path)
  420. End If
  421. End If
  422. Local build_path:String
  423. If m.obj_path Then
  424. build_path = ExtractDir(m.obj_path)
  425. Else
  426. build_path = ExtractDir(m.path) + "/.bmx"
  427. End If
  428. If Not FileType(build_path) Then
  429. CreateDir build_path
  430. End If
  431. If FileType(build_path) <> FILETYPE_DIR Then
  432. Throw "Unable to create temporary directory : " + build_path
  433. End If
  434. ' change dir, so relative commands work as expected
  435. ' (eg. file processing in BMK-scripts called via pragma)
  436. ChangeDir ExtractDir( m.path )
  437. ' bmx file
  438. If Match(m.ext, "bmx") Then
  439. Select m.stage
  440. Case STAGE_GENERATE
  441. If m.requiresBuild Or (m.time > m.gen_time Or m.iface_time < m.MaxIfaceTime() Or Not m.MaxIfaceTime()) Then
  442. If Not opt_quiet Then
  443. Print ShowPct(m.pct) + "Processing:" + StripDir(m.path)
  444. End If
  445. ' process pragmas
  446. Local pragma_inDefine:Int, pragma_text:String, pragma_name:String
  447. For Local pragma:String = EachIn m.pragmas
  448. processor.ProcessPragma(pragma, pragma_inDefine, pragma_text, pragma_name)
  449. Next
  450. CompileBMX m.path, m.obj_path, m.bcc_opts
  451. End If
  452. Case STAGE_FASM2AS
  453. For Local s:TSourceFile = EachIn m.depsList
  454. If s.requiresBuild Then
  455. m.SetRequiresBuild(True)
  456. Exit
  457. End If
  458. Next
  459. If m.requiresBuild Or (m.time > m.obj_time Or m.iface_time < m.MaxIfaceTime()) Then
  460. m.SetRequiresBuild(True)
  461. If Not opt_quiet Then
  462. Print ShowPct(m.pct) + "Converting:" + StripDir(StripExt(m.obj_path) + ".s")
  463. End If
  464. Fasm2As m.path, m.obj_path
  465. m.asm_time = time_(Null)
  466. End If
  467. Case STAGE_OBJECT
  468. If m.requiresBuild Or (m.time > m.obj_time Or m.iface_time < m.MaxIfaceTime()) Then
  469. m.SetRequiresBuild(True)
  470. If processor.BCCVersion() <> "BlitzMax" Then
  471. Local csrc_path:String = StripExt(m.obj_path) + ".c"
  472. Local cobj_path:String = StripExt(m.obj_path) + ".o"
  473. If Not opt_quiet Then
  474. Local s:String = ShowPct(m.pct) + "Compiling:" + StripDir(csrc_path)
  475. If opt_standalone And Not opt_nolog processor.PushEcho(FixPct(s))
  476. Print s
  477. End If
  478. If opt_standalone And opt_boot Then
  479. processor.PushSource(csrc_path)
  480. processor.PushSource(StripExt(m.obj_path) + ".h")
  481. End If
  482. CompileC csrc_path,cobj_path, m.GetIncludePaths() + " " + m.cc_opts + " " + m.c_opts
  483. Else
  484. ' asm compilation
  485. Local src_path:String = StripExt(m.obj_path) + ".s"
  486. Local obj_path:String = StripExt(m.obj_path) + ".o"
  487. If Not opt_quiet Then
  488. Print ShowPct(m.pct) + "Compiling:" + StripDir(src_path)
  489. End If
  490. Assemble src_path, obj_path
  491. End If
  492. m.obj_time = time_(Null)
  493. End If
  494. Case STAGE_LINK
  495. Local max_obj_time:Int = m.MaxObjTime()
  496. If max_obj_time > m.arc_time And Not m.dontbuild Then
  497. Local objs:TList = New TList
  498. m.GetObjs(objs)
  499. If Not opt_quiet Then
  500. Local s:String = ShowPct(m.pct) + "Archiving:" + StripDir(m.arc_path)
  501. If opt_standalone And Not opt_nolog processor.PushEcho(FixPct(s))
  502. Print s
  503. End If
  504. Local at:TArcTask = New TArcTask.Create(m, m.arc_path, objs)
  505. ?threaded
  506. If opt_single Then
  507. at.CreateArc()
  508. Else
  509. processManager.AddTask(TArcTask._CreateArc, at)
  510. End If
  511. ?Not threaded
  512. at.CreateArc()
  513. ?
  514. End If
  515. Case STAGE_APP_LINK
  516. ' this probably should never happen.
  517. ' may be a bad module?
  518. If Not opt_outfile Then
  519. Throw "Build Error: Did not expect to link against " + m.path
  520. End If
  521. ' an app!
  522. Local max_lnk_time:Int = m.MaxLinkTime()
  523. ' include settings and icon times in calculation
  524. If opt_manifest And processor.Platform() = "win32" And opt_apptype="gui" Then
  525. Local settings:String = ExtractDir(opt_infile) + "/" + StripDir(StripExt(opt_outfile)) + ".settings"
  526. If Not FileType(settings) Then
  527. settings = ExtractDir(opt_infile) + "/" + StripDir(StripExt(opt_infile)) + ".settings"
  528. End If
  529. max_lnk_time = Max(FileTime(settings), max_lnk_time)
  530. Local icon:String = ExtractDir(opt_infile) + "/" + StripDir(StripExt(opt_outfile)) + ".ico"
  531. If Not FileType(icon) Then
  532. icon = ExtractDir(opt_infile) + "/" + StripDir(StripExt(opt_infile)) + ".ico"
  533. End If
  534. max_lnk_time = Max(FileTime(icon), max_lnk_time)
  535. End If
  536. If max_lnk_time > FileTime(opt_outfile) Or opt_all Then
  537. ' generate manifest for app
  538. If opt_manifest And processor.Platform() = "win32" And opt_apptype="gui" Then
  539. processor.RunCommand("make_win32_resource", Null)
  540. Local res:String = ExtractDir(opt_infile) + "/.bmx/" + StripDir(StripExt(opt_outfile)) + "." + processor.CPU() + ".res.o"
  541. If Not FileType(res) Then
  542. res = ExtractDir(opt_infile) + "/.bmx/" + StripDir(StripExt(opt_infile)) + "." + processor.CPU() + ".res.o"
  543. End If
  544. If FileType(res) = FILETYPE_FILE Then
  545. Local s:TSourceFile = New TSourceFile
  546. s.obj_path = res
  547. s.stage = STAGE_LINK
  548. s.exti = SOURCE_RES
  549. m.depslist.AddLast(s)
  550. End If
  551. End If
  552. If Not opt_quiet Then
  553. Local s:String = ShowPct(m.pct) + "Linking:" + StripDir(opt_outfile)
  554. If opt_standalone And Not opt_nolog processor.PushEcho(FixPct(s))
  555. Print s
  556. End If
  557. Local links:TList = New TList
  558. Local opts:TList = New TList
  559. m.GetLinks(links, opts)
  560. For Local arc:String = EachIn arc_order
  561. links.AddLast(arc)
  562. Next
  563. For Local o:String = EachIn opts
  564. links.AddLast(o)
  565. Next
  566. LinkApp opt_outfile, links, makelib, globals.Get("ld_opts")
  567. m.obj_time = time_(Null)
  568. End If
  569. Case STAGE_MERGE
  570. If IOS_HAS_MERGE Then
  571. ' a module?
  572. If m.modid Then
  573. Local max_obj_time:Int = m.MaxObjTime()
  574. If max_obj_time > m.merge_time And Not m.dontbuild Then
  575. If Not opt_quiet Then
  576. Print ShowPct(m.pct) + "Merging:" + StripDir(m.merge_path)
  577. End If
  578. CreateMergeArc m.merge_path, m.arc_path
  579. m.merge_time = time_(Null)
  580. End If
  581. End If
  582. End If
  583. End Select
  584. Else If Match(m.ext, "s") Then
  585. If m.time > m.obj_time Then ' object is older or doesn't exist
  586. m.SetRequiresBuild(True)
  587. End If
  588. If m.requiresBuild Then
  589. If Not opt_quiet Then
  590. Local s:String = ShowPct(m.pct) + "Compiling:" + StripDir(m.path)
  591. If opt_standalone And Not opt_nolog processor.PushEcho(FixPct(s))
  592. Print s
  593. End If
  594. If processor.BCCVersion() = "BlitzMax" Then
  595. Assemble m.path, m.obj_path
  596. Else
  597. CompileC m.path, m.obj_path, m.GetIncludePaths() + " " + m.cc_opts + " " + m.c_opts
  598. End If
  599. End If
  600. Else
  601. If Not m.dontbuild Then
  602. ' c/c++ source
  603. If m.time > m.obj_time Then ' object is older or doesn't exist
  604. m.SetRequiresBuild(True)
  605. End If
  606. If m.requiresBuild Then
  607. If Not opt_quiet Then
  608. Local s:String = ShowPct(m.pct) + "Compiling:" + StripDir(m.path)
  609. If opt_standalone And Not opt_nolog processor.PushEcho(FixPct(s))
  610. Print s
  611. End If
  612. If m.path.EndsWith(".cpp") Or m.path.EndsWith(".cc") Or m.path.EndsWith(".mm") Or m.path.EndsWith(".cxx") Then
  613. CompileC m.path, m.obj_path, m.GetIncludePaths() + " " + m.cc_opts + " " + m.cpp_opts
  614. ElseIf m.path.EndsWith(".S") Or m.path.EndsWith("asm") Then
  615. AssembleNative m.path, m.obj_path, m.asm_opts
  616. Else
  617. CompileC m.path, m.obj_path, m.GetIncludePaths() + " " + m.cc_opts + " " + m.c_opts
  618. End If
  619. m.obj_time = time_(Null)
  620. End If
  621. End If
  622. End If
  623. Next
  624. ?threaded
  625. If Not opt_single Then
  626. processManager.WaitForTasks()
  627. End If
  628. ?
  629. Next
  630. If app_build Then
  631. ' global post process
  632. LoadBMK("post.bmk")
  633. ' generic post process
  634. LoadBMK(ExtractDir(app_main) + "/post.bmk")
  635. ' project-specific post process
  636. LoadBMK(ExtractDir(app_main) + "/" + StripDir( opt_outfile ) + ".post.bmk")
  637. Select processor.Platform()
  638. Case "android"
  639. ' create the apk
  640. ' copy shared object
  641. Local androidABI:String = processor.Option("android.abi", "")
  642. Local appId:String = StripDir(StripExt(opt_outfile))
  643. If opt_debug And opt_outfile.EndsWith(".debug") Then
  644. appId :+ ".debug"
  645. End If
  646. Local buildDir:String = ExtractDir(opt_outfile)
  647. Local projectDir:String = buildDir + "/android-project-" + appId
  648. Local abiPath:String = projectDir + "/libs/" + androidABI
  649. Local sharedObject:String = "lib" + appId
  650. sharedObject :+ ".so"
  651. CopyFile(buildDir + "/" + sharedObject, abiPath + "/" + sharedObject)
  652. ' build the apk :
  653. Local antHome:String = processor.Option("ant.home", "").Trim()
  654. Local cmd:String = "~q" + antHome + "/bin/ant"
  655. ?win32
  656. cmd :+ ".bat"
  657. ?
  658. cmd :+ "~q debug"
  659. Local dir:String = CurrentDir()
  660. ChangeDir(projectDir)
  661. If opt_dumpbuild Then
  662. Print cmd
  663. End If
  664. If Sys( cmd ) Then
  665. Throw "Error creating apk"
  666. End If
  667. ChangeDir(dir)
  668. 'End If
  669. Case "ios"
  670. Local iosSimulator:Int = (processor.CPU() = "x86")
  671. ' TODO - other stuff ?
  672. Case "nx"
  673. ' TODO - build nro, nso, psf0 and nacp
  674. End Select
  675. End If
  676. End Method
  677. Method CalculateDependencies(source:TSourceFile, isMod:Int = False, rebuildImports:Int = False, isInclude:Int = False)
  678. If source And Not source.processed Then
  679. source.processed = True
  680. For Local m:String = EachIn source.modimports
  681. Local s:TSourceFile = GetMod(m)
  682. If s Then
  683. If Not source.moddeps Then
  684. source.moddeps = New TMap
  685. End If
  686. If Not source.moddeps.ValueForKey(m) Then
  687. source.moddeps.Insert(m, s)
  688. source.deps.Insert(s.GetSourcePath(), s)
  689. source.AddIncludePath(" -I" + CQuote(ExtractDir(s.path)))
  690. End If
  691. End If
  692. Next
  693. Local ib:TSourceFile
  694. If processor.BCCVersion() <> "BlitzMax" And Not source.incbins.IsEmpty() Then
  695. If source.owner_path Then
  696. ib = CreateIncBin(source, source.owner_path)
  697. Else
  698. ib = CreateIncBin(source, source.path)
  699. End If
  700. End If
  701. For Local f:String = EachIn source.imports
  702. If f[0] <> Asc("-") Then
  703. Local path:String = CheckPath(ExtractDir(source.path), f)
  704. Local s:TSourceFile = GetSourceFile(path, isMod)
  705. ' imported sourcefile not there? Maybe it's relative to the owner path instead?
  706. ' For example, an incbin as part of an included source file.
  707. If Not s Then
  708. Local p:String = CheckPath(ExtractDir(source.owner_path), f)
  709. s = GetSourceFile(p, isMod)
  710. If s Then
  711. path = p
  712. End If
  713. End If
  714. If s Then
  715. If rebuildImports Then
  716. s.SetRequiresBuild(rebuildImports)
  717. End If
  718. If Match(s.ext, "bmx") Then
  719. s.modimports.AddLast("brl.blitz")
  720. ' app source files need framework/mod dependencies applied
  721. If Not isMod Then
  722. If opt_framework Then
  723. ' add framework as dependency
  724. s.modimports.AddLast(opt_framework)
  725. Else
  726. ' add all pub/brl mods as dependency
  727. If framework_mods Then
  728. For Local m:String = EachIn framework_mods
  729. s.modimports.AddLast(m)
  730. Next
  731. End If
  732. End If
  733. End If
  734. s.bcc_opts = source.bcc_opts
  735. s.cc_opts :+ source.cc_opts
  736. s.cpp_opts :+ source.cpp_opts
  737. s.c_opts :+ source.c_opts
  738. s.asm_opts :+ source.asm_opts
  739. s.CopyIncludePaths(source.includePaths)
  740. CalculateDependencies(s, isMod, rebuildImports)
  741. ' if file that we generate is missing, we need to rebuild
  742. If processor.BCCVersion() = "BlitzMax" Then
  743. If Not FileType(StripExt(s.obj_path) + ".s") Then
  744. s.SetRequiresBuild(True)
  745. End If
  746. Else
  747. If Not FileType(StripExt(s.obj_path) + ".c") Then
  748. s.SetRequiresBuild(True)
  749. End If
  750. End If
  751. Local gen:TSourceFile
  752. ' for osx x86 on legacy, we need to convert asm
  753. If processor.BCCVersion() = "BlitzMax" And processor.CPU() = "x86" And processor.Platform() = "macos" Then
  754. Local fasm2as:TSourceFile = CreateFasm2AsStage(s)
  755. gen = CreateGenStage(fasm2as)
  756. Else
  757. gen = CreateGenStage(s)
  758. End If
  759. source.deps.Insert(gen.GetSourcePath(), gen)
  760. If Not source.depsList Then
  761. source.depsList = New TList
  762. End If
  763. source.depsList.AddLast(gen)
  764. Else
  765. s.cc_opts = source.cc_opts
  766. s.cpp_opts = source.cpp_opts
  767. s.c_opts = source.c_opts
  768. s.asm_opts = source.asm_opts
  769. s.CopyIncludePaths(source.includePaths)
  770. source.deps.Insert(s.GetSourcePath(), s)
  771. If Not source.depsList Then
  772. source.depsList = New TList
  773. End If
  774. source.depsList.AddLast(s)
  775. End If
  776. Else
  777. Local ext:String = ExtractExt(path)
  778. If Match(ext, "h;hpp;hxx") Then ' header?
  779. source.AddIncludePath(" -I" + CQuote(ExtractDir(path)))
  780. Else If Match(ext, "o;a;lib") Then ' object or archive?
  781. Local s:TSourceFile = New TSourceFile
  782. s.time = FileTime(path)
  783. s.obj_time = s.time
  784. s.path = path
  785. s.obj_path = path
  786. s.modid = source.modid
  787. If s.time > source.time Then
  788. source.time = s.time
  789. End If
  790. If Not source.depsList Then
  791. source.depsList = New TList
  792. End If
  793. source.depsList.AddLast(s)
  794. End If
  795. End If
  796. Else
  797. If Not source.ext_files Then
  798. source.ext_files = New TList
  799. End If
  800. source.ext_files.AddLast(f)
  801. End If
  802. Next
  803. For Local f:String = EachIn source.includes
  804. Local path:String = CheckPath(ExtractDir(source.path), f)
  805. Local s:TSourceFile = GetSourceFile(path, isMod, rebuildImports, True)
  806. If s Then
  807. s.owner_path = source.path
  808. If s.includePaths.IsEmpty() Then
  809. s.CopyIncludePaths(source.includePaths)
  810. End If
  811. ' calculate included file dependencies
  812. CalculateDependencies(s, isMod, rebuildImports)
  813. ' update our time to latest included time
  814. If s.time > source.time Then
  815. source.time = s.time
  816. End If
  817. If Not source.depsList Then
  818. source.depsList = New TList
  819. End If
  820. source.depsList.AddLast(s)
  821. End If
  822. Next
  823. For Local f:String = EachIn source.incbins
  824. Local path:String = CheckPath(ExtractDir(source.path), f)
  825. If FileType(path) = FILETYPE_FILE Then
  826. source.hashes.Insert(f, CalculateFileHash(path))
  827. End If
  828. Local time:Int = FileTime(path)
  829. ' update our time to the latest incbin time
  830. If time > source.time Then
  831. source.time = time
  832. End If
  833. ' update ib time to the latest incbin time
  834. If ib And ib.time And ib.time < time Then
  835. ib.time = time
  836. End If
  837. Next
  838. ' incbin file
  839. If ib Then
  840. Local requiresBuild:Int = False
  841. ' missing source.. generate and compile
  842. If Not ib.time Then
  843. requiresBuild = True
  844. Else If IncbinsDifference(source.incbins, ib.incbins) Then
  845. requiresBuild = True
  846. Else If IncbinsHashDifference(source, ib) Then
  847. requiresBuild = True
  848. End If
  849. If requiresBuild Then
  850. ib.SetRequiresBuild(True)
  851. source.SetRequiresBuild(True)
  852. End If
  853. ' sync timestamps
  854. If ib.time > source.time Then
  855. source.time = ib.time
  856. End If
  857. End If
  858. If source.depsList Then
  859. For Local s:TSourceFile = EachIn source.depsList
  860. If Not Match(s.ext, "bmx") Then
  861. s.cc_opts = source.cc_opts
  862. s.cpp_opts = source.cpp_opts
  863. s.c_opts = source.c_opts
  864. s.asm_opts = source.asm_opts
  865. s.CopyIncludePaths(source.includePaths)
  866. End If
  867. Next
  868. End If
  869. End If
  870. End Method
  871. Method GetSourceFile:TSourceFile(source_path:String, isMod:Int = False, rebuild:Int = False, isInclude:Int = False, doCreate:Int = True)
  872. Local source:TSourceFile = TSourceFile(sources.ValueForKey(source_path))
  873. If Not source And doCreate Then
  874. source = ParseSourceFile(source_path)
  875. If source Then
  876. Local ext:String = ExtractExt(source_path)
  877. If Match(ext, ALL_SRC_EXTS) Then
  878. If Not isInclude Then
  879. sources.Insert(source_path, source)
  880. Local sp:String
  881. If app_main = source_path Then
  882. sp = ConcatString(ExtractDir(source_path), "/.bmx/", StripDir(source_path), "." + opt_apptype, opt_configmung, processor.CPU())
  883. Else
  884. sp = ConcatString(ExtractDir(source_path), "/.bmx/", StripDir(source_path), opt_configmung, processor.CPU())
  885. End If
  886. If Match(ext, "bmx") Then
  887. source.obj_path = sp + ".o"
  888. source.obj_time = FileTime(source.obj_path)
  889. source.iface_path = sp + ".i"
  890. source.iface_path2 = source.iface_path + "2"
  891. source.iface_time = FileTime(source.iface_path2)
  892. ' gen file times
  893. If processor.BCCVersion() <> "BlitzMax" Then
  894. Local p:String = sp + ".c"
  895. source.gen_time = FileTime(p)
  896. If source.gen_time Then
  897. p = sp + ".h"
  898. source.gen_time = Min(source.gen_time, FileTime(p))
  899. End If
  900. Else
  901. Local p:String = sp + ".s"
  902. source.gen_time = FileTime(p)
  903. End If
  904. Else
  905. source.obj_path = PPFix(sp) + ".o"
  906. source.obj_time = FileTime(source.obj_path)
  907. End If
  908. Else
  909. source.isInclude = True
  910. End If
  911. End If
  912. End If
  913. End If
  914. Return source
  915. End Method
  916. Method PPFix:String(path:String)
  917. Local dir:String = ExtractDir(ExtractDir(path))
  918. Local s:String
  919. For Local i:Int = 0 Until 3
  920. Local t:String = StripDir(dir)
  921. If Not t Then
  922. t = "x"
  923. End If
  924. s = t[..1] + s
  925. dir = ExtractDir(dir)
  926. Next
  927. Return ExtractDir(path) + "/" + s + "_" + StripDir(path)
  928. End Method
  929. Method GetISourceFile:TSourceFile(arc_path:String, arc_time:Int, iface_path:String, iface_time:Int, merge_path:String, merge_time:Int)
  930. Local source:TSourceFile
  931. If IOS_HAS_MERGE And processor.Platform() = "ios" Then
  932. source = TSourceFile(sources.ValueForKey(merge_path))
  933. Else
  934. source = TSourceFile(sources.ValueForKey(arc_path))
  935. End If
  936. If Not source Then
  937. Local iface_path2:String = iface_path + 2
  938. source = ParseISourceFile(iface_path2)
  939. If source Then
  940. source.arc_path = arc_path
  941. source.arc_time = arc_time
  942. source.iface_path = iface_path
  943. source.iface_path2 = iface_path2
  944. source.iface_time = iface_time
  945. source.merge_time = merge_time
  946. If IOS_HAS_MERGE And processor.Platform() = "ios" Then
  947. sources.Insert(merge_path, source)
  948. Else
  949. sources.Insert(arc_path, source)
  950. End If
  951. End If
  952. End If
  953. Return source
  954. End Method
  955. Method GetMod:TSourceFile(m:String, rebuild:Int = False)
  956. 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
  957. rebuild = True
  958. End If
  959. Local path:String = ModulePath(m)
  960. Local id:String = ModuleIdent(m)
  961. Local mp:String = ConcatString(path, "/", id, opt_configmung, processor.CPU())
  962. ' get the module interface and lib details
  963. Local arc_path:String = mp + ".a"
  964. Local arc_time:Int = FileTime(arc_path)
  965. Local iface_path:String = mp + ".i"
  966. Local iface_path2:String = iface_path + "2"
  967. Local iface_time:Int = FileTime(iface_path2)
  968. Local merge_path:String
  969. Local merge_time:Int
  970. If IOS_HAS_MERGE And processor.Platform() = "ios" Then
  971. If processor.CPU() = "x86" Or processor.CPU() = "x64" Then
  972. merge_path = ConcatString(path, "/", id, opt_configmung, "sim.a")
  973. Else
  974. merge_path = ConcatString(path, "/", id, opt_configmung, "dev.a")
  975. End If
  976. merge_time = FileTime(merge_path)
  977. End If
  978. Local source:TSourceFile
  979. Local link:TSourceFile
  980. ' do a quick scan only when building apps. For module builds we want to check required modules.
  981. If arc_time And iface_time And opt_quickscan And app_main Then
  982. source = GetISourceFile(arc_path, arc_time, iface_path, iface_time, merge_path, merge_time)
  983. If Not source Then
  984. Return Null
  985. End If
  986. If Not source.processed Then
  987. source.modid = m
  988. source.arc_path = arc_path
  989. source.arc_time = arc_time
  990. source.iface_path = iface_path
  991. source.iface_path2 = iface_path2
  992. source.iface_time = iface_time
  993. source.obj_path = arc_path
  994. source.merge_path = merge_path
  995. source.merge_time = merge_time
  996. CalculateDependencies(source, True, rebuild)
  997. source.dontbuild = True
  998. If IOS_HAS_MERGE And processor.Platform() = "ios" Then
  999. source.stage = STAGE_MERGE
  1000. sources.Insert(source.merge_path, source)
  1001. Else
  1002. source.stage = STAGE_LINK
  1003. sources.Insert(source.arc_path, source)
  1004. End If
  1005. End If
  1006. link = source
  1007. Else
  1008. Local src_path:String = ConcatString(path, "/", id, ".bmx")
  1009. source = GetSourceFile(src_path, True, rebuild)
  1010. If Not source Then
  1011. Return Null
  1012. End If
  1013. ' main module file without "Module" line?
  1014. If Not source.modid Then
  1015. Return Null
  1016. End If
  1017. End If
  1018. If Not source.processed Then
  1019. source.arc_path = arc_path
  1020. source.arc_time = arc_time
  1021. source.iface_path = iface_path
  1022. source.iface_path2 = iface_path2
  1023. source.iface_time = iface_time
  1024. source.merge_path = merge_path
  1025. source.merge_time = merge_time
  1026. Local cc_opts:String
  1027. source.AddIncludePath(" -I" + CQuote(path))
  1028. source.AddIncludePath(" -I" + CQuote(ModulePath("")))
  1029. If opt_release And Not opt_gdbdebug Then
  1030. cc_opts :+ " -DNDEBUG"
  1031. End If
  1032. If opt_threaded Then
  1033. cc_opts :+ " -DTHREADED"
  1034. End If
  1035. If processor.BCCVersion() <> "BlitzMax" Then
  1036. If opt_gdbdebug Then
  1037. cc_opts :+ " -g"
  1038. End If
  1039. If opt_gprof Then
  1040. cc_opts :+ " -pg"
  1041. End If
  1042. If opt_coverage Then
  1043. cc_opts :+ " -DBMX_COVERAGE"
  1044. End If
  1045. End If
  1046. source.cc_opts = ""
  1047. If source.mod_opts Then
  1048. source.cc_opts :+ source.mod_opts.cc_opts
  1049. source.cpp_opts :+ source.mod_opts.cpp_opts
  1050. source.c_opts :+ source.mod_opts.c_opts
  1051. source.asm_opts :+ source.mod_opts.asm_opts
  1052. End If
  1053. source.cc_opts :+ cc_opts
  1054. source.cpp_opts :+ cpp_opts
  1055. source.c_opts :+ c_opts
  1056. source.asm_opts :+ asm_opts
  1057. ' Module BCC opts
  1058. Local sb:TStringBuffer = New TStringBuffer
  1059. sb.Append(" -g ").Append(processor.CPU())
  1060. sb.Append(" -m ").Append(m)
  1061. If opt_quiet sb.Append(" -q")
  1062. If opt_verbose sb.Append(" -v")
  1063. If opt_release sb.Append(" -r")
  1064. If opt_threaded sb.Append(" -h")
  1065. If processor.BCCVersion() <> "BlitzMax" Then
  1066. If opt_gdbdebug Then
  1067. sb.Append(" -d")
  1068. End If
  1069. If Not opt_nostrictupgrade Then
  1070. sb.Append(" -s")
  1071. End If
  1072. If opt_warnover Then
  1073. sb.Append(" -w")
  1074. End If
  1075. If opt_musl Then
  1076. sb.Append(" -musl")
  1077. End If
  1078. If opt_require_override Then
  1079. sb.Append(" -override")
  1080. If opt_override_error Then
  1081. sb.Append(" -overerr")
  1082. End If
  1083. End If
  1084. Local defs:String = opt_userdefs
  1085. If globals.Get("user_defs") Then
  1086. If defs Then
  1087. defs :+ ","
  1088. End If
  1089. defs :+ globals.Get("user_defs")
  1090. End If
  1091. If defs Then
  1092. sb.Append(" -ud ").Append(defs)
  1093. End If
  1094. If opt_standalone Then
  1095. sb.Append(" -ib")
  1096. End If
  1097. If opt_coverage Then
  1098. sb.Append(" -cov")
  1099. End If
  1100. If opt_no_auto_superstrict Then
  1101. sb.Append(" -nas")
  1102. End If
  1103. End If
  1104. source.bcc_opts = sb.ToString()
  1105. source.SetRequiresBuild(rebuild)
  1106. ' interface is REQUIRED for compilation
  1107. If Not iface_time Then
  1108. source.SetRequiresBuild(True)
  1109. End If
  1110. If m <> "brl.blitz" Then
  1111. source.modimports.AddLast("brl.blitz")
  1112. End If
  1113. CalculateDependencies(source, True, rebuild)
  1114. ' create bmx stages :
  1115. Local gen:TSourceFile
  1116. ' for osx x86 on legacy, we need to convert asm
  1117. If processor.BCCVersion() = "BlitzMax" And processor.CPU() = "x86" And processor.Platform() = "macos" Then
  1118. Local fasm2as:TSourceFile = CreateFasm2AsStage(source)
  1119. gen = CreateGenStage(fasm2as)
  1120. Else
  1121. gen = CreateGenStage(source)
  1122. End If
  1123. If processor.Platform() <> "ios" Then
  1124. link = CreateLinkStage(gen)
  1125. Else
  1126. If IOS_HAS_MERGE Then
  1127. Local realLink:TSourceFile = CreateLinkStage(gen)
  1128. ' create a fat archive
  1129. link = CreateMergeStage(realLink)
  1130. Else
  1131. link = CreateLinkStage(gen)
  1132. End If
  1133. End If
  1134. Else
  1135. If IOS_HAS_MERGE And processor.Platform() = "ios" Then
  1136. link = TSourceFile(sources.ValueForKey(source.merge_path))
  1137. Else
  1138. link = TSourceFile(sources.ValueForKey(source.arc_path))
  1139. End If
  1140. If Not link Then
  1141. Throw "Can't find link for : " + source.path
  1142. End If
  1143. End If
  1144. Return link
  1145. End Method
  1146. Method CreateFasm2AsStage:TSourceFile(source:TSourceFile)
  1147. Local fasm:TSourceFile = New TSourceFile
  1148. source.CopyInfo(fasm)
  1149. fasm.deps.Insert(source.path, source)
  1150. fasm.stage = STAGE_FASM2AS
  1151. fasm.processed = True
  1152. fasm.depsList = New TList
  1153. fasm.depsList.AddLast(source)
  1154. sources.Insert(StripExt(fasm.obj_path) + ".s", fasm)
  1155. Return fasm
  1156. End Method
  1157. Method CreateGenStage:TSourceFile(source:TSourceFile)
  1158. Local gen:TSourceFile = New TSourceFile
  1159. source.CopyInfo(gen)
  1160. If processor.BCCVersion() = "BlitzMax" And processor.CPU() = "x86" And processor.Platform() = "macos" Then
  1161. gen.deps.Insert(StripExt(source.obj_path) + ".s", source)
  1162. Else
  1163. gen.deps.Insert(source.path, source)
  1164. End If
  1165. gen.stage = STAGE_OBJECT
  1166. gen.processed = True
  1167. gen.depsList = New TList
  1168. gen.depsList.AddLast(source)
  1169. sources.Insert(StripExt(gen.obj_path) + ".c", gen)
  1170. Return gen
  1171. End Method
  1172. Method CreateIncBin:TSourceFile(source:TSourceFile, sourcePath:String)
  1173. Local path:String = StripDir(sourcePath) + opt_configmung + processor.CPU()
  1174. If opt_standalone Or (processor.CPU() = "x86" And processor.Platform() = "win32") Then
  1175. path :+ ".incbin.c"
  1176. Else
  1177. path :+ ".incbin2.c"
  1178. End If
  1179. Local ibPath:String = ExtractDir(sourcePath) + "/.bmx/" + path
  1180. Local ib:TSourceFile = GetSourceFile(ibPath,,,,False)
  1181. If Not ib Then
  1182. ib = New TSourceFile
  1183. ib.path = ibPath
  1184. ib.obj_path = StripExt(ib.path) + ".o"
  1185. ib.ext = "c"
  1186. ib.exti = String(processor.RunCommand("source_type", [ib.ext])).ToInt()
  1187. source.imports.AddLast(".bmx/" + StripDir(path) )
  1188. End If
  1189. If ib.includePaths.IsEmpty() Then
  1190. ib.CopyIncludePaths(source.includePaths)
  1191. End If
  1192. GetIncBinFileList(ib)
  1193. ib.time = FileTime(ib.path)
  1194. ib.obj_time = FileTime(ib.obj_path)
  1195. sources.Insert(ib.path, ib)
  1196. If opt_standalone And opt_boot Then
  1197. processor.PushSource(ib.path)
  1198. End If
  1199. Return ib
  1200. End Method
  1201. Method GetIncBinFileList(source:TSourceFile)
  1202. Local stream:TStream = ReadStream(source.path)
  1203. If stream Then
  1204. While Not stream.Eof()
  1205. Local line:String = stream.ReadLine()
  1206. If line.StartsWith("// FILE : ") Then
  1207. Local parts:String[] = line[10..].Split("~t")
  1208. Local ib:String = parts[0].Replace("~q", "")
  1209. If ib Then
  1210. source.incbins.AddLast(ib)
  1211. If parts.length = 2 Then
  1212. source.hashes.Insert(ib, parts[1])
  1213. End If
  1214. End If
  1215. Else If line.StartsWith("// ----") Then
  1216. Exit
  1217. EndIf
  1218. Wend
  1219. stream.Close()
  1220. End If
  1221. End Method
  1222. Method IncbinsDifference:Int(ib1:TList, ib2:TList)
  1223. If ib1.Count() <> ib2.Count() Then
  1224. Return True
  1225. End If
  1226. For Local ib:String = EachIn ib1
  1227. If Not ib2.Contains(ib) Then
  1228. Return True
  1229. End If
  1230. Next
  1231. For Local ib:String = EachIn ib2
  1232. If Not ib1.Contains(ib) Then
  1233. Return True
  1234. End If
  1235. Next
  1236. Return False
  1237. End Method
  1238. Method IncbinsHashDifference:Int(source:TSourceFile, ib:TSourceFile)
  1239. If source.hashes.IsEmpty() Then
  1240. Return True
  1241. End If
  1242. For Local file:String = EachIn source.hashes.Keys()
  1243. Local sourceHash:String = String(source.hashes.ValueForKey(file))
  1244. If sourceHash <> String(ib.hashes.ValueForKey(file)) Then
  1245. Return True
  1246. End If
  1247. Next
  1248. For Local file:String = EachIn ib.hashes.Keys()
  1249. Local ibHash:String = String(ib.hashes.ValueForKey(file))
  1250. If ibHash <> String(source.hashes.ValueForKey(file)) Then
  1251. Return True
  1252. End If
  1253. Next
  1254. End Method
  1255. Method CreateLinkStage:TSourceFile(source:TSourceFile, stage:Int = STAGE_LINK)
  1256. Local link:TSourceFile = New TSourceFile
  1257. source.CopyInfo(link)
  1258. link.deps.Insert(StripExt(link.obj_path) + ".c", source)
  1259. link.stage = stage
  1260. link.processed = True
  1261. link.depsList = New TList
  1262. link.depsList.AddLast(source)
  1263. If IOS_HAS_MERGE And processor.Platform() = "ios" Then
  1264. sources.Insert(link.obj_path, link)
  1265. Else
  1266. sources.Insert(link.arc_path, link)
  1267. End If
  1268. Return link
  1269. End Method
  1270. Method CreateMergeStage:TSourceFile(source:TSourceFile)
  1271. Local merge:TSourceFile = New TSourceFile
  1272. source.CopyInfo(merge)
  1273. merge.deps.Insert(merge.obj_path, source)
  1274. merge.stage = STAGE_MERGE
  1275. merge.processed = True
  1276. merge.depsList = New TList
  1277. merge.depsList.AddLast(source)
  1278. sources.Insert(merge.merge_path, merge)
  1279. Return merge
  1280. End Method
  1281. Method CalculateBatches:TList(files:TList)
  1282. Local batches:TList = New TList
  1283. Local count:Int
  1284. Local instances:TMap = New TMap
  1285. For Local m:TSourceFile = EachIn files
  1286. instances.Insert(m.GetSourcePath(), m)
  1287. count :+ 1
  1288. Next
  1289. Local dependencies:TMap = New TMap
  1290. For Local m:TSourceFile = EachIn files
  1291. dependencies.Insert(m.GetSourcePath(), m.deps)
  1292. Next
  1293. Local pct:Float = 100.0 / count
  1294. Local total:Float
  1295. Local num:Int
  1296. While Not dependencies.IsEmpty()
  1297. Local noDeps:TList = New TList
  1298. For Local depName:String = EachIn dependencies.Keys()
  1299. Local dep:TMap = TMap(dependencies.ValueForKey(depName))
  1300. If dep.IsEmpty() Then
  1301. noDeps.AddLast(depName)
  1302. End If
  1303. Next
  1304. If noDeps.IsEmpty() Then
  1305. ' circular dependency!
  1306. ' TODO : dump current list for user to work out?
  1307. Print "REMAINING :"
  1308. For Local depName:String = EachIn dependencies.Keys()
  1309. Print " " + depName
  1310. Next
  1311. Throw "circular dependency!"
  1312. End If
  1313. ' remove from dependencies
  1314. For Local name:String = EachIn noDeps
  1315. dependencies.Remove(name)
  1316. Next
  1317. For Local dep:TMap = EachIn dependencies.Values()
  1318. For Local name:String = EachIn noDeps
  1319. dep.Remove(name)
  1320. Next
  1321. Next
  1322. Local list:TList = New TList
  1323. For Local name:String = EachIn noDeps
  1324. Local m:TSourceFile = TSourceFile(instances.ValueForKey(name))
  1325. list.AddLast(m)
  1326. Next
  1327. batches.AddLast(list)
  1328. Wend
  1329. ' post process batches
  1330. Local suffix:String[]
  1331. Local stage:Int
  1332. For Local i:Int = 0 Until 3
  1333. Select i
  1334. Case 0
  1335. suffix = ["c", "cpp", "cc", "cxx", "m", "mm"]
  1336. Case 1
  1337. suffix = ["o"]
  1338. stage = STAGE_LINK
  1339. Case 2
  1340. suffix = ["o"]
  1341. stage = STAGE_APP_LINK
  1342. End Select
  1343. Local newList:TList = New TList
  1344. For Local list:TList = EachIn batches
  1345. For Local f:TSourceFile = EachIn list
  1346. Local p:String = f.GetSourcePath()
  1347. If Not p.EndsWith("bmx") Then
  1348. For Local s:String = EachIn suffix
  1349. If p.EndsWith(s) Then
  1350. If app_iface And stage Then
  1351. If (stage = STAGE_LINK And app_iface = f.iface_path) Or (stage = STAGE_APP_LINK And app_iface <> f.iface_path) Then
  1352. Continue
  1353. End If
  1354. End If
  1355. newList.AddLast(f)
  1356. list.Remove(f)
  1357. If list.IsEmpty() Then
  1358. batches.Remove(list)
  1359. End If
  1360. ' found, no need to loop further
  1361. Exit
  1362. End If
  1363. Next
  1364. End If
  1365. Next
  1366. Next
  1367. If Not newList.IsEmpty() Then
  1368. batches.AddLast(newList)
  1369. End If
  1370. Next
  1371. For Local list:TList = EachIn batches
  1372. For Local m:TSourceFile = EachIn list
  1373. total :+ pct
  1374. num :+ 1
  1375. If num = count Then
  1376. m.pct = 100
  1377. Else
  1378. m.pct = total
  1379. End If
  1380. Next
  1381. Next
  1382. Return batches
  1383. End Method
  1384. Method ShowPct:String(pct:Int)
  1385. Local s:String = "["
  1386. Local p:String = String.FromInt(pct)
  1387. Select p.length
  1388. Case 1
  1389. s :+ " "
  1390. Case 2
  1391. s :+ " "
  1392. End Select
  1393. Return s + p + "%] "
  1394. End Method
  1395. Method FixPct:String(pct:String)
  1396. If processor.Platform() = "win32" Then
  1397. Return pct.Replace("%", "%%")
  1398. Else
  1399. Return pct
  1400. End If
  1401. End Method
  1402. Method CheckPath:String(basePath:String, path:String)
  1403. Local p:String = RealPath(basePath + "/" + path)
  1404. If Not FileType(p) Then
  1405. ' maybe path is a full path already?
  1406. p = RealPath(path)
  1407. If Not FileType(p) Then
  1408. ' meh... fallback to original
  1409. p = RealPath(basePath + "/" + path)
  1410. End If
  1411. End If
  1412. Return p
  1413. End Method
  1414. Method DoCallback(src:String)
  1415. Local update:Int = True
  1416. Local m:TSourceFile = TSourceFile(sources.ValueForKey(src))
  1417. If m Then
  1418. If FileType(m.iface_path) = FILETYPE_FILE Then
  1419. ' has the interface/api changed since the last build?
  1420. If FileType(m.iface_path2) = FILETYPE_FILE And m.time = FileTime( m.path ) Then
  1421. If FileSize(m.iface_path) = FileSize(m.iface_path2) Then
  1422. Local i_bytes:Byte[] = LoadByteArray(m.iface_path)
  1423. Local i_bytes2:Byte[] = LoadByteArray(m.iface_path2)
  1424. ?bmxng
  1425. If i_bytes.length = i_bytes2.length And memcmp_( i_bytes, i_bytes2, Size_T(i_bytes.length) )=0 Then
  1426. ?Not bmxng
  1427. If i_bytes.length = i_bytes2.length And memcmp_( i_bytes, i_bytes2, i_bytes.length )=0 Then
  1428. ?
  1429. update = False
  1430. End If
  1431. End If
  1432. End If
  1433. If update Then
  1434. CopyFile m.iface_path, m.iface_path2
  1435. Else If m.iface_time < m.MaxIfaceTime() Then
  1436. SetFileTimeNow(m.iface_path2)
  1437. m.iface_time = time_(Null)
  1438. m.maxIfaceTimeCache = -1
  1439. End If
  1440. End If
  1441. If update Then
  1442. m.SetRequiresBuild(True)
  1443. m.iface_time = time_(Null)
  1444. m.maxIfaceTimeCache = -1
  1445. m.gen_time = time_(Null)
  1446. End If
  1447. End If
  1448. End Method
  1449. End Type
  1450. Type TArcTask
  1451. Field m:TSourceFile
  1452. Field path:String
  1453. Field oobjs:TList
  1454. Method Create:TArcTask(m:TSourceFile, path$ , oobjs:TList )
  1455. Self.m = m
  1456. Self.path = path
  1457. Self.oobjs = oobjs
  1458. Return Self
  1459. End Method
  1460. Function _CreateArc:Object(data:Object)
  1461. Return TArcTask(data).CreateArc()
  1462. End Function
  1463. Method CreateArc:Object()
  1464. DeleteFile path
  1465. Local cmd$,t$
  1466. If processor.Platform() = "win32"
  1467. For t$=EachIn oobjs
  1468. If Len(cmd)+Len(t)>1000
  1469. If opt_standalone And Not opt_nolog processor.PushLog(cmd)
  1470. If processor.Sys( cmd )
  1471. DeleteFile path
  1472. Throw "Build Error: Failed to create archive "+path
  1473. EndIf
  1474. cmd=""
  1475. EndIf
  1476. If Not cmd Then
  1477. Local prefix:String = processor.MinGWExePrefix()
  1478. Local ext:String = ""
  1479. If processor.OSPlatform() = "win32" Then
  1480. ext = ".exe"
  1481. End If
  1482. cmd= processor.Option("path_to_ar", processor.MinGWBinPath() + "/" + prefix + "ar" + ext) + " -rc "+CQuote(path)
  1483. End If
  1484. cmd:+" "+CQuote(t)
  1485. Next
  1486. End If
  1487. If processor.Platform() = "macos" Or processor.Platform() = "osx" Then
  1488. cmd=processor.Option(processor.BuildName("libtool"), "libtool") + " -o "+CQuote(path)
  1489. For Local t$=EachIn oobjs
  1490. cmd:+" "+CQuote(t)
  1491. Next
  1492. End If
  1493. If processor.Platform() = "ios" Then
  1494. Local proc:String = processor.CPU()
  1495. Select proc
  1496. Case "x86"
  1497. proc = "i386"
  1498. Case "x64"
  1499. proc = "x86_64"
  1500. End Select
  1501. cmd= processor.Option(processor.BuildName("libtool"), "libtool") + " -static -arch_only " + proc + " -o "+CQuote(path)
  1502. For Local t$=EachIn oobjs
  1503. cmd:+" "+CQuote(t)
  1504. Next
  1505. End If
  1506. If processor.Platform() = "linux" Or processor.Platform() = "raspberrypi" Or processor.Platform() = "android" Or processor.Platform() = "emscripten" Or processor.Platform() = "nx" Or processor.Platform() = "haiku"
  1507. For Local t$=EachIn oobjs
  1508. If Len(cmd)+Len(t)>1000
  1509. If opt_standalone And Not opt_nolog processor.PushLog(cmd)
  1510. If processor.Sys( cmd )
  1511. DeleteFile path
  1512. Throw "Build Error: Failed to create archive "+path
  1513. EndIf
  1514. cmd=""
  1515. EndIf
  1516. If processor.Platform() = "emscripten" Then
  1517. If Not cmd cmd=processor.Option(processor.BuildName("ar"), "emar") + " r "+CQuote(path)
  1518. Else
  1519. If Not cmd cmd=processor.Option(processor.BuildName("ar"), "ar") + " -r "+CQuote(path)
  1520. End If
  1521. cmd:+" "+CQuote(t)
  1522. Next
  1523. End If
  1524. If cmd
  1525. If opt_standalone And Not opt_nolog processor.PushLog(cmd)
  1526. If processor.Sys( cmd )
  1527. DeleteFile path
  1528. Throw "Build Error: Failed to create archive "+path
  1529. End If
  1530. EndIf
  1531. m.arc_time = time_(Null)
  1532. m.obj_time = time_(Null)
  1533. End Method
  1534. End Type