bmk_make.bmx 52 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922
  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. End If
  354. source.cc_opts :+ cc_opts
  355. source.cpp_opts :+ cpp_opts
  356. source.c_opts :+ c_opts
  357. source.modimports.AddLast("brl.blitz")
  358. source.modimports.AddLast(opt_appstub)
  359. If source.framewk
  360. If opt_framework Then
  361. Throw "Framework already specified on commandline"
  362. End If
  363. opt_framework = source.framewk
  364. sb.Append(" -f ").Append(opt_framework)
  365. source.modimports.AddLast(opt_framework)
  366. Else
  367. framework_mods = New TList
  368. For Local t:String = EachIn EnumModules()
  369. If t.Find("brl.") = 0 Or t.Find("pub.") = 0 Then
  370. If t <> "brl.blitz" And t <> opt_appstub Then
  371. source.modimports.AddLast(t)
  372. framework_mods.AddLast(t)
  373. End If
  374. End If
  375. Next
  376. End If
  377. source.bcc_opts = sb.ToString()
  378. source.SetRequiresBuild(opt_all)
  379. CalculateDependencies(source, False, opt_all)
  380. source.bcc_opts :+ " -t " + opt_apptype
  381. ' create bmx stages :
  382. Local gen:TSourceFile
  383. ' for osx x86 on legacy, we need to convert asm
  384. If processor.BCCVersion() = "BlitzMax" And processor.CPU() = "x86" And processor.Platform() = "macos" Then
  385. Local fasm2as:TSourceFile = CreateFasm2AsStage(source)
  386. gen = CreateGenStage(fasm2as)
  387. Else
  388. gen = CreateGenStage(source)
  389. End If
  390. If Not compileOnly Then
  391. Local link:TSourceFile = CreateLinkStage(gen, STAGE_APP_LINK)
  392. End If
  393. End Method
  394. Method DoBuild(makelib:Int, app_build:Int = False)
  395. Local arc_order:TList = New TList
  396. Local files:TList = New TList
  397. For Local file:TSourceFile = EachIn sources.Values()
  398. files.AddLast(file)
  399. Next
  400. ' get the list of parallelizable batches
  401. ' each list of batches has no outstanding dependencies, and therefore
  402. ' can be compiled in parallel.
  403. ' the last list of batches requires all previous lists to have
  404. ' been compiled.
  405. Local batches:TList = CalculateBatches(files)
  406. For Local batch:TList = EachIn batches
  407. Local s:String
  408. For Local m:TSourceFile = EachIn batch
  409. ' sort archives for app linkage
  410. If m.modid Then
  411. Local path:String = m.arc_path
  412. If IOS_HAS_MERGE And processor.Platform() = "ios" Then
  413. path = m.merge_path
  414. End If
  415. If Not arc_order.Contains(path) Then
  416. arc_order.AddFirst(path)
  417. End If
  418. End If
  419. Local build_path:String
  420. If m.obj_path Then
  421. build_path = ExtractDir(m.obj_path)
  422. Else
  423. build_path = ExtractDir(m.path) + "/.bmx"
  424. End If
  425. If Not FileType(build_path) Then
  426. CreateDir build_path
  427. End If
  428. If FileType(build_path) <> FILETYPE_DIR Then
  429. Throw "Unable to create temporary directory : " + build_path
  430. End If
  431. ' change dir, so relative commands work as expected
  432. ' (eg. file processing in BMK-scripts called via pragma)
  433. ChangeDir ExtractDir( m.path )
  434. ' bmx file
  435. If Match(m.ext, "bmx") Then
  436. Select m.stage
  437. Case STAGE_GENERATE
  438. If m.requiresBuild Or (m.time > m.gen_time Or m.iface_time < m.MaxIfaceTime() Or Not m.MaxIfaceTime()) Then
  439. If Not opt_quiet Then
  440. Print ShowPct(m.pct) + "Processing:" + StripDir(m.path)
  441. End If
  442. ' process pragmas
  443. Local pragma_inDefine:Int, pragma_text:String, pragma_name:String
  444. For Local pragma:String = EachIn m.pragmas
  445. processor.ProcessPragma(pragma, pragma_inDefine, pragma_text, pragma_name)
  446. Next
  447. CompileBMX m.path, m.obj_path, m.bcc_opts
  448. End If
  449. Case STAGE_FASM2AS
  450. For Local s:TSourceFile = EachIn m.depsList
  451. If s.requiresBuild Then
  452. m.SetRequiresBuild(True)
  453. Exit
  454. End If
  455. Next
  456. If m.requiresBuild Or (m.time > m.obj_time Or m.iface_time < m.MaxIfaceTime()) Then
  457. m.SetRequiresBuild(True)
  458. If Not opt_quiet Then
  459. Print ShowPct(m.pct) + "Converting:" + StripDir(StripExt(m.obj_path) + ".s")
  460. End If
  461. Fasm2As m.path, m.obj_path
  462. m.asm_time = time_(Null)
  463. End If
  464. Case STAGE_OBJECT
  465. If m.requiresBuild Or (m.time > m.obj_time Or m.iface_time < m.MaxIfaceTime()) Then
  466. m.SetRequiresBuild(True)
  467. If processor.BCCVersion() <> "BlitzMax" Then
  468. Local csrc_path:String = StripExt(m.obj_path) + ".c"
  469. Local cobj_path:String = StripExt(m.obj_path) + ".o"
  470. If Not opt_quiet Then
  471. Local s:String = ShowPct(m.pct) + "Compiling:" + StripDir(csrc_path)
  472. If opt_standalone And Not opt_nolog processor.PushEcho(FixPct(s))
  473. Print s
  474. End If
  475. If opt_standalone And opt_boot Then
  476. processor.PushSource(csrc_path)
  477. processor.PushSource(StripExt(m.obj_path) + ".h")
  478. End If
  479. CompileC csrc_path,cobj_path, m.GetIncludePaths() + " " + m.cc_opts + " " + m.c_opts
  480. Else
  481. ' asm compilation
  482. Local src_path:String = StripExt(m.obj_path) + ".s"
  483. Local obj_path:String = StripExt(m.obj_path) + ".o"
  484. If Not opt_quiet Then
  485. Print ShowPct(m.pct) + "Compiling:" + StripDir(src_path)
  486. End If
  487. Assemble src_path, obj_path
  488. End If
  489. m.obj_time = time_(Null)
  490. End If
  491. Case STAGE_LINK
  492. Local max_obj_time:Int = m.MaxObjTime()
  493. If max_obj_time > m.arc_time And Not m.dontbuild Then
  494. Local objs:TList = New TList
  495. m.GetObjs(objs)
  496. If Not opt_quiet Then
  497. Local s:String = ShowPct(m.pct) + "Archiving:" + StripDir(m.arc_path)
  498. If opt_standalone And Not opt_nolog processor.PushEcho(FixPct(s))
  499. Print s
  500. End If
  501. Local at:TArcTask = New TArcTask.Create(m, m.arc_path, objs)
  502. ?threaded
  503. If opt_single Then
  504. at.CreateArc()
  505. Else
  506. processManager.AddTask(TArcTask._CreateArc, at)
  507. End If
  508. ?Not threaded
  509. at.CreateArc()
  510. ?
  511. End If
  512. Case STAGE_APP_LINK
  513. ' this probably should never happen.
  514. ' may be a bad module?
  515. If Not opt_outfile Then
  516. Throw "Build Error: Did not expect to link against " + m.path
  517. End If
  518. ' an app!
  519. Local max_lnk_time:Int = m.MaxLinkTime()
  520. ' include settings and icon times in calculation
  521. If opt_manifest And processor.Platform() = "win32" And opt_apptype="gui" Then
  522. Local settings:String = ExtractDir(opt_infile) + "/" + StripDir(StripExt(opt_outfile)) + ".settings"
  523. If Not FileType(settings) Then
  524. settings = ExtractDir(opt_infile) + "/" + StripDir(StripExt(opt_infile)) + ".settings"
  525. End If
  526. max_lnk_time = Max(FileTime(settings), max_lnk_time)
  527. Local icon:String = ExtractDir(opt_infile) + "/" + StripDir(StripExt(opt_outfile)) + ".ico"
  528. If Not FileType(icon) Then
  529. icon = ExtractDir(opt_infile) + "/" + StripDir(StripExt(opt_infile)) + ".ico"
  530. End If
  531. max_lnk_time = Max(FileTime(icon), max_lnk_time)
  532. End If
  533. If max_lnk_time > FileTime(opt_outfile) Or opt_all Then
  534. ' generate manifest for app
  535. If opt_manifest And processor.Platform() = "win32" And opt_apptype="gui" Then
  536. processor.RunCommand("make_win32_resource", Null)
  537. Local res:String = ExtractDir(opt_infile) + "/.bmx/" + StripDir(StripExt(opt_outfile)) + "." + processor.CPU() + ".res.o"
  538. If Not FileType(res) Then
  539. res = ExtractDir(opt_infile) + "/.bmx/" + StripDir(StripExt(opt_infile)) + "." + processor.CPU() + ".res.o"
  540. End If
  541. If FileType(res) = FILETYPE_FILE Then
  542. Local s:TSourceFile = New TSourceFile
  543. s.obj_path = res
  544. s.stage = STAGE_LINK
  545. s.exti = SOURCE_RES
  546. m.depslist.AddLast(s)
  547. End If
  548. End If
  549. If Not opt_quiet Then
  550. Local s:String = ShowPct(m.pct) + "Linking:" + StripDir(opt_outfile)
  551. If opt_standalone And Not opt_nolog processor.PushEcho(FixPct(s))
  552. Print s
  553. End If
  554. Local links:TList = New TList
  555. Local opts:TList = New TList
  556. m.GetLinks(links, opts)
  557. For Local arc:String = EachIn arc_order
  558. links.AddLast(arc)
  559. Next
  560. For Local o:String = EachIn opts
  561. links.AddLast(o)
  562. Next
  563. LinkApp opt_outfile, links, makelib, globals.Get("ld_opts")
  564. m.obj_time = time_(Null)
  565. End If
  566. Case STAGE_MERGE
  567. If IOS_HAS_MERGE Then
  568. ' a module?
  569. If m.modid Then
  570. Local max_obj_time:Int = m.MaxObjTime()
  571. If max_obj_time > m.merge_time And Not m.dontbuild Then
  572. If Not opt_quiet Then
  573. Print ShowPct(m.pct) + "Merging:" + StripDir(m.merge_path)
  574. End If
  575. CreateMergeArc m.merge_path, m.arc_path
  576. m.merge_time = time_(Null)
  577. End If
  578. End If
  579. End If
  580. End Select
  581. Else If Match(m.ext, "s") Then
  582. If m.time > m.obj_time Then ' object is older or doesn't exist
  583. m.SetRequiresBuild(True)
  584. End If
  585. If m.requiresBuild Then
  586. If Not opt_quiet Then
  587. Local s:String = ShowPct(m.pct) + "Compiling:" + StripDir(m.path)
  588. If opt_standalone And Not opt_nolog processor.PushEcho(FixPct(s))
  589. Print s
  590. End If
  591. If processor.BCCVersion() = "BlitzMax" Then
  592. Assemble m.path, m.obj_path
  593. Else
  594. CompileC m.path, m.obj_path, m.GetIncludePaths() + " " + m.cc_opts + " " + m.c_opts
  595. End If
  596. End If
  597. Else
  598. If Not m.dontbuild Then
  599. ' c/c++ source
  600. If m.time > m.obj_time Then ' object is older or doesn't exist
  601. m.SetRequiresBuild(True)
  602. End If
  603. If m.requiresBuild Then
  604. If Not opt_quiet Then
  605. Local s:String = ShowPct(m.pct) + "Compiling:" + StripDir(m.path)
  606. If opt_standalone And Not opt_nolog processor.PushEcho(FixPct(s))
  607. Print s
  608. End If
  609. If m.path.EndsWith(".cpp") Or m.path.EndsWith(".cc") Or m.path.EndsWith(".mm") Or m.path.EndsWith(".cxx") Then
  610. CompileC m.path, m.obj_path, m.GetIncludePaths() + " " + m.cc_opts + " " + m.cpp_opts
  611. ElseIf m.path.EndsWith(".S") Or m.path.EndsWith("asm") Then
  612. AssembleNative m.path, m.obj_path, m.asm_opts
  613. Else
  614. CompileC m.path, m.obj_path, m.GetIncludePaths() + " " + m.cc_opts + " " + m.c_opts
  615. End If
  616. m.obj_time = time_(Null)
  617. End If
  618. End If
  619. End If
  620. Next
  621. ?threaded
  622. If Not opt_single Then
  623. processManager.WaitForTasks()
  624. End If
  625. ?
  626. Next
  627. If app_build Then
  628. ' global post process
  629. LoadBMK("post.bmk")
  630. ' generic post process
  631. LoadBMK(ExtractDir(app_main) + "/post.bmk")
  632. ' project-specific post process
  633. LoadBMK(ExtractDir(app_main) + "/" + StripDir( opt_outfile ) + ".post.bmk")
  634. Select processor.Platform()
  635. Case "android"
  636. ' create the apk
  637. ' copy shared object
  638. Local androidABI:String = processor.Option("android.abi", "")
  639. Local appId:String = StripDir(StripExt(opt_outfile))
  640. If opt_debug And opt_outfile.EndsWith(".debug") Then
  641. appId :+ ".debug"
  642. End If
  643. Local buildDir:String = ExtractDir(opt_outfile)
  644. Local projectDir:String = buildDir + "/android-project-" + appId
  645. Local abiPath:String = projectDir + "/libs/" + androidABI
  646. Local sharedObject:String = "lib" + appId
  647. sharedObject :+ ".so"
  648. CopyFile(buildDir + "/" + sharedObject, abiPath + "/" + sharedObject)
  649. ' build the apk :
  650. Local antHome:String = processor.Option("ant.home", "").Trim()
  651. Local cmd:String = "~q" + antHome + "/bin/ant"
  652. ?win32
  653. cmd :+ ".bat"
  654. ?
  655. cmd :+ "~q debug"
  656. Local dir:String = CurrentDir()
  657. ChangeDir(projectDir)
  658. If opt_dumpbuild Then
  659. Print cmd
  660. End If
  661. If Sys( cmd ) Then
  662. Throw "Error creating apk"
  663. End If
  664. ChangeDir(dir)
  665. 'End If
  666. Case "ios"
  667. Local iosSimulator:Int = (processor.CPU() = "x86")
  668. ' TODO - other stuff ?
  669. Case "nx"
  670. ' TODO - build nro, nso, psf0 and nacp
  671. End Select
  672. End If
  673. End Method
  674. Method CalculateDependencies(source:TSourceFile, isMod:Int = False, rebuildImports:Int = False, isInclude:Int = False)
  675. If source And Not source.processed Then
  676. source.processed = True
  677. For Local m:String = EachIn source.modimports
  678. Local s:TSourceFile = GetMod(m)
  679. If s Then
  680. If Not source.moddeps Then
  681. source.moddeps = New TMap
  682. End If
  683. If Not source.moddeps.ValueForKey(m) Then
  684. source.moddeps.Insert(m, s)
  685. source.deps.Insert(s.GetSourcePath(), s)
  686. source.AddIncludePath(" -I" + CQuote(ExtractDir(s.path)))
  687. End If
  688. End If
  689. Next
  690. Local ib:TSourceFile
  691. If processor.BCCVersion() <> "BlitzMax" And Not source.incbins.IsEmpty() Then
  692. If source.owner_path Then
  693. ib = CreateIncBin(source, source.owner_path)
  694. Else
  695. ib = CreateIncBin(source, source.path)
  696. End If
  697. End If
  698. For Local f:String = EachIn source.imports
  699. If f[0] <> Asc("-") Then
  700. Local path:String = CheckPath(ExtractDir(source.path), f)
  701. Local s:TSourceFile = GetSourceFile(path, isMod)
  702. ' imported sourcefile not there? Maybe it's relative to the owner path instead?
  703. ' For example, an incbin as part of an included source file.
  704. If Not s Then
  705. Local p:String = CheckPath(ExtractDir(source.owner_path), f)
  706. s = GetSourceFile(p, isMod)
  707. If s Then
  708. path = p
  709. End If
  710. End If
  711. If s Then
  712. If rebuildImports Then
  713. s.SetRequiresBuild(rebuildImports)
  714. End If
  715. If Match(s.ext, "bmx") Then
  716. s.modimports.AddLast("brl.blitz")
  717. ' app source files need framework/mod dependencies applied
  718. If Not isMod Then
  719. If opt_framework Then
  720. ' add framework as dependency
  721. s.modimports.AddLast(opt_framework)
  722. Else
  723. ' add all pub/brl mods as dependency
  724. If framework_mods Then
  725. For Local m:String = EachIn framework_mods
  726. s.modimports.AddLast(m)
  727. Next
  728. End If
  729. End If
  730. End If
  731. s.bcc_opts = source.bcc_opts
  732. s.cc_opts :+ source.cc_opts
  733. s.cpp_opts :+ source.cpp_opts
  734. s.c_opts :+ source.c_opts
  735. s.asm_opts :+ source.asm_opts
  736. s.CopyIncludePaths(source.includePaths)
  737. CalculateDependencies(s, isMod, rebuildImports)
  738. ' if file that we generate is missing, we need to rebuild
  739. If processor.BCCVersion() = "BlitzMax" Then
  740. If Not FileType(StripExt(s.obj_path) + ".s") Then
  741. s.SetRequiresBuild(True)
  742. End If
  743. Else
  744. If Not FileType(StripExt(s.obj_path) + ".c") Then
  745. s.SetRequiresBuild(True)
  746. End If
  747. End If
  748. Local gen:TSourceFile
  749. ' for osx x86 on legacy, we need to convert asm
  750. If processor.BCCVersion() = "BlitzMax" And processor.CPU() = "x86" And processor.Platform() = "macos" Then
  751. Local fasm2as:TSourceFile = CreateFasm2AsStage(s)
  752. gen = CreateGenStage(fasm2as)
  753. Else
  754. gen = CreateGenStage(s)
  755. End If
  756. source.deps.Insert(gen.GetSourcePath(), gen)
  757. If Not source.depsList Then
  758. source.depsList = New TList
  759. End If
  760. source.depsList.AddLast(gen)
  761. Else
  762. s.cc_opts = source.cc_opts
  763. s.cpp_opts = source.cpp_opts
  764. s.c_opts = source.c_opts
  765. s.asm_opts = source.asm_opts
  766. s.CopyIncludePaths(source.includePaths)
  767. source.deps.Insert(s.GetSourcePath(), s)
  768. If Not source.depsList Then
  769. source.depsList = New TList
  770. End If
  771. source.depsList.AddLast(s)
  772. End If
  773. Else
  774. Local ext:String = ExtractExt(path)
  775. If Match(ext, "h;hpp;hxx") Then ' header?
  776. source.AddIncludePath(" -I" + CQuote(ExtractDir(path)))
  777. Else If Match(ext, "o;a;lib") Then ' object or archive?
  778. Local s:TSourceFile = New TSourceFile
  779. s.time = FileTime(path)
  780. s.obj_time = s.time
  781. s.path = path
  782. s.obj_path = path
  783. s.modid = source.modid
  784. If s.time > source.time Then
  785. source.time = s.time
  786. End If
  787. If Not source.depsList Then
  788. source.depsList = New TList
  789. End If
  790. source.depsList.AddLast(s)
  791. End If
  792. End If
  793. Else
  794. If Not source.ext_files Then
  795. source.ext_files = New TList
  796. End If
  797. source.ext_files.AddLast(f)
  798. End If
  799. Next
  800. For Local f:String = EachIn source.includes
  801. Local path:String = CheckPath(ExtractDir(source.path), f)
  802. Local s:TSourceFile = GetSourceFile(path, isMod, rebuildImports, True)
  803. If s Then
  804. s.owner_path = source.path
  805. If s.includePaths.IsEmpty() Then
  806. s.CopyIncludePaths(source.includePaths)
  807. End If
  808. ' calculate included file dependencies
  809. CalculateDependencies(s, isMod, rebuildImports)
  810. ' update our time to latest included time
  811. If s.time > source.time Then
  812. source.time = s.time
  813. End If
  814. If Not source.depsList Then
  815. source.depsList = New TList
  816. End If
  817. source.depsList.AddLast(s)
  818. End If
  819. Next
  820. For Local f:String = EachIn source.incbins
  821. Local path:String = CheckPath(ExtractDir(source.path), f)
  822. If FileType(path) = FILETYPE_FILE Then
  823. source.hashes.Insert(f, CalculateFileHash(path))
  824. End If
  825. Local time:Int = FileTime(path)
  826. ' update our time to the latest incbin time
  827. If time > source.time Then
  828. source.time = time
  829. End If
  830. ' update ib time to the latest incbin time
  831. If ib And ib.time And ib.time < time Then
  832. ib.time = time
  833. End If
  834. Next
  835. ' incbin file
  836. If ib Then
  837. Local requiresBuild:Int = False
  838. ' missing source.. generate and compile
  839. If Not ib.time Then
  840. requiresBuild = True
  841. Else If IncbinsDifference(source.incbins, ib.incbins) Then
  842. requiresBuild = True
  843. Else If IncbinsHashDifference(source, ib) Then
  844. requiresBuild = True
  845. End If
  846. If requiresBuild Then
  847. ib.SetRequiresBuild(True)
  848. source.SetRequiresBuild(True)
  849. End If
  850. ' sync timestamps
  851. If ib.time > source.time Then
  852. source.time = ib.time
  853. End If
  854. End If
  855. If source.depsList Then
  856. For Local s:TSourceFile = EachIn source.depsList
  857. If Not Match(s.ext, "bmx") Then
  858. s.cc_opts = source.cc_opts
  859. s.cpp_opts = source.cpp_opts
  860. s.c_opts = source.c_opts
  861. s.asm_opts = source.asm_opts
  862. s.CopyIncludePaths(source.includePaths)
  863. End If
  864. Next
  865. End If
  866. End If
  867. End Method
  868. Method GetSourceFile:TSourceFile(source_path:String, isMod:Int = False, rebuild:Int = False, isInclude:Int = False, doCreate:Int = True)
  869. Local source:TSourceFile = TSourceFile(sources.ValueForKey(source_path))
  870. If Not source And doCreate Then
  871. source = ParseSourceFile(source_path)
  872. If source Then
  873. Local ext:String = ExtractExt(source_path)
  874. If Match(ext, ALL_SRC_EXTS) Then
  875. If Not isInclude Then
  876. sources.Insert(source_path, source)
  877. Local sp:String
  878. If app_main = source_path Then
  879. sp = ConcatString(ExtractDir(source_path), "/.bmx/", StripDir(source_path), "." + opt_apptype, opt_configmung, processor.CPU())
  880. Else
  881. sp = ConcatString(ExtractDir(source_path), "/.bmx/", StripDir(source_path), opt_configmung, processor.CPU())
  882. End If
  883. If Match(ext, "bmx") Then
  884. source.obj_path = sp + ".o"
  885. source.obj_time = FileTime(source.obj_path)
  886. source.iface_path = sp + ".i"
  887. source.iface_path2 = source.iface_path + "2"
  888. source.iface_time = FileTime(source.iface_path2)
  889. ' gen file times
  890. If processor.BCCVersion() <> "BlitzMax" Then
  891. Local p:String = sp + ".c"
  892. source.gen_time = FileTime(p)
  893. If source.gen_time Then
  894. p = sp + ".h"
  895. source.gen_time = Min(source.gen_time, FileTime(p))
  896. End If
  897. Else
  898. Local p:String = sp + ".s"
  899. source.gen_time = FileTime(p)
  900. End If
  901. Else
  902. source.obj_path = PPFix(sp) + ".o"
  903. source.obj_time = FileTime(source.obj_path)
  904. End If
  905. Else
  906. source.isInclude = True
  907. End If
  908. End If
  909. End If
  910. End If
  911. Return source
  912. End Method
  913. Method PPFix:String(path:String)
  914. Local dir:String = ExtractDir(ExtractDir(path))
  915. Local s:String
  916. For Local i:Int = 0 Until 3
  917. Local t:String = StripDir(dir)
  918. If Not t Then
  919. t = "x"
  920. End If
  921. s = t[..1] + s
  922. dir = ExtractDir(dir)
  923. Next
  924. Return ExtractDir(path) + "/" + s + "_" + StripDir(path)
  925. End Method
  926. Method GetISourceFile:TSourceFile(arc_path:String, arc_time:Int, iface_path:String, iface_time:Int, merge_path:String, merge_time:Int)
  927. Local source:TSourceFile
  928. If IOS_HAS_MERGE And processor.Platform() = "ios" Then
  929. source = TSourceFile(sources.ValueForKey(merge_path))
  930. Else
  931. source = TSourceFile(sources.ValueForKey(arc_path))
  932. End If
  933. If Not source Then
  934. Local iface_path2:String = iface_path + 2
  935. source = ParseISourceFile(iface_path2)
  936. If source Then
  937. source.arc_path = arc_path
  938. source.arc_time = arc_time
  939. source.iface_path = iface_path
  940. source.iface_path2 = iface_path2
  941. source.iface_time = iface_time
  942. source.merge_time = merge_time
  943. If IOS_HAS_MERGE And processor.Platform() = "ios" Then
  944. sources.Insert(merge_path, source)
  945. Else
  946. sources.Insert(arc_path, source)
  947. End If
  948. End If
  949. End If
  950. Return source
  951. End Method
  952. Method GetMod:TSourceFile(m:String, rebuild:Int = False)
  953. 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
  954. rebuild = True
  955. End If
  956. Local path:String = ModulePath(m)
  957. Local id:String = ModuleIdent(m)
  958. Local mp:String = ConcatString(path, "/", id, opt_configmung, processor.CPU())
  959. ' get the module interface and lib details
  960. Local arc_path:String = mp + ".a"
  961. Local arc_time:Int = FileTime(arc_path)
  962. Local iface_path:String = mp + ".i"
  963. Local iface_path2:String = iface_path + "2"
  964. Local iface_time:Int = FileTime(iface_path2)
  965. Local merge_path:String
  966. Local merge_time:Int
  967. If IOS_HAS_MERGE And processor.Platform() = "ios" Then
  968. If processor.CPU() = "x86" Or processor.CPU() = "x64" Then
  969. merge_path = ConcatString(path, "/", id, opt_configmung, "sim.a")
  970. Else
  971. merge_path = ConcatString(path, "/", id, opt_configmung, "dev.a")
  972. End If
  973. merge_time = FileTime(merge_path)
  974. End If
  975. Local source:TSourceFile
  976. Local link:TSourceFile
  977. ' do a quick scan only when building apps. For module builds we want to check required modules.
  978. If arc_time And iface_time And opt_quickscan And app_main Then
  979. source = GetISourceFile(arc_path, arc_time, iface_path, iface_time, merge_path, merge_time)
  980. If Not source Then
  981. Return Null
  982. End If
  983. If Not source.processed Then
  984. source.modid = m
  985. source.arc_path = arc_path
  986. source.arc_time = arc_time
  987. source.iface_path = iface_path
  988. source.iface_path2 = iface_path2
  989. source.iface_time = iface_time
  990. source.obj_path = arc_path
  991. source.merge_path = merge_path
  992. source.merge_time = merge_time
  993. CalculateDependencies(source, True, rebuild)
  994. source.dontbuild = True
  995. If IOS_HAS_MERGE And processor.Platform() = "ios" Then
  996. source.stage = STAGE_MERGE
  997. sources.Insert(source.merge_path, source)
  998. Else
  999. source.stage = STAGE_LINK
  1000. sources.Insert(source.arc_path, source)
  1001. End If
  1002. End If
  1003. link = source
  1004. Else
  1005. Local src_path:String = ConcatString(path, "/", id, ".bmx")
  1006. source = GetSourceFile(src_path, True, rebuild)
  1007. If Not source Then
  1008. Return Null
  1009. End If
  1010. ' main module file without "Module" line?
  1011. If Not source.modid Then
  1012. Return Null
  1013. End If
  1014. End If
  1015. If Not source.processed Then
  1016. source.arc_path = arc_path
  1017. source.arc_time = arc_time
  1018. source.iface_path = iface_path
  1019. source.iface_path2 = iface_path2
  1020. source.iface_time = iface_time
  1021. source.merge_path = merge_path
  1022. source.merge_time = merge_time
  1023. Local cc_opts:String
  1024. source.AddIncludePath(" -I" + CQuote(path))
  1025. source.AddIncludePath(" -I" + CQuote(ModulePath("")))
  1026. If opt_release And Not opt_gdbdebug Then
  1027. cc_opts :+ " -DNDEBUG"
  1028. End If
  1029. If opt_threaded Then
  1030. cc_opts :+ " -DTHREADED"
  1031. End If
  1032. If processor.BCCVersion() <> "BlitzMax" Then
  1033. If opt_gdbdebug Then
  1034. cc_opts :+ " -g"
  1035. End If
  1036. If opt_gprof Then
  1037. cc_opts :+ " -pg"
  1038. End If
  1039. If opt_coverage Then
  1040. cc_opts :+ " -DBMX_COVERAGE"
  1041. End If
  1042. End If
  1043. source.cc_opts = ""
  1044. If source.mod_opts Then
  1045. source.cc_opts :+ source.mod_opts.cc_opts
  1046. source.cpp_opts :+ source.mod_opts.cpp_opts
  1047. source.c_opts :+ source.mod_opts.c_opts
  1048. source.asm_opts :+ source.mod_opts.asm_opts
  1049. End If
  1050. source.cc_opts :+ cc_opts
  1051. source.cpp_opts :+ cpp_opts
  1052. source.c_opts :+ c_opts
  1053. source.asm_opts :+ asm_opts
  1054. ' Module BCC opts
  1055. Local sb:TStringBuffer = New TStringBuffer
  1056. sb.Append(" -g ").Append(processor.CPU())
  1057. sb.Append(" -m ").Append(m)
  1058. If opt_quiet sb.Append(" -q")
  1059. If opt_verbose sb.Append(" -v")
  1060. If opt_release sb.Append(" -r")
  1061. If opt_threaded sb.Append(" -h")
  1062. If processor.BCCVersion() <> "BlitzMax" Then
  1063. If opt_gdbdebug Then
  1064. sb.Append(" -d")
  1065. End If
  1066. If Not opt_nostrictupgrade Then
  1067. sb.Append(" -s")
  1068. End If
  1069. If opt_warnover Then
  1070. sb.Append(" -w")
  1071. End If
  1072. If opt_musl Then
  1073. sb.Append(" -musl")
  1074. End If
  1075. If opt_require_override Then
  1076. sb.Append(" -override")
  1077. If opt_override_error Then
  1078. sb.Append(" -overerr")
  1079. End If
  1080. End If
  1081. Local defs:String = opt_userdefs
  1082. If globals.Get("user_defs") Then
  1083. If defs Then
  1084. defs :+ ","
  1085. End If
  1086. defs :+ globals.Get("user_defs")
  1087. End If
  1088. If defs Then
  1089. sb.Append(" -ud ").Append(defs)
  1090. End If
  1091. If opt_standalone Then
  1092. sb.Append(" -ib")
  1093. End If
  1094. If opt_coverage Then
  1095. sb.Append(" -cov")
  1096. End If
  1097. End If
  1098. source.bcc_opts = sb.ToString()
  1099. source.SetRequiresBuild(rebuild)
  1100. ' interface is REQUIRED for compilation
  1101. If Not iface_time Then
  1102. source.SetRequiresBuild(True)
  1103. End If
  1104. If m <> "brl.blitz" Then
  1105. source.modimports.AddLast("brl.blitz")
  1106. End If
  1107. CalculateDependencies(source, True, rebuild)
  1108. ' create bmx stages :
  1109. Local gen:TSourceFile
  1110. ' for osx x86 on legacy, we need to convert asm
  1111. If processor.BCCVersion() = "BlitzMax" And processor.CPU() = "x86" And processor.Platform() = "macos" Then
  1112. Local fasm2as:TSourceFile = CreateFasm2AsStage(source)
  1113. gen = CreateGenStage(fasm2as)
  1114. Else
  1115. gen = CreateGenStage(source)
  1116. End If
  1117. If processor.Platform() <> "ios" Then
  1118. link = CreateLinkStage(gen)
  1119. Else
  1120. If IOS_HAS_MERGE Then
  1121. Local realLink:TSourceFile = CreateLinkStage(gen)
  1122. ' create a fat archive
  1123. link = CreateMergeStage(realLink)
  1124. Else
  1125. link = CreateLinkStage(gen)
  1126. End If
  1127. End If
  1128. Else
  1129. If IOS_HAS_MERGE And processor.Platform() = "ios" Then
  1130. link = TSourceFile(sources.ValueForKey(source.merge_path))
  1131. Else
  1132. link = TSourceFile(sources.ValueForKey(source.arc_path))
  1133. End If
  1134. If Not link Then
  1135. Throw "Can't find link for : " + source.path
  1136. End If
  1137. End If
  1138. Return link
  1139. End Method
  1140. Method CreateFasm2AsStage:TSourceFile(source:TSourceFile)
  1141. Local fasm:TSourceFile = New TSourceFile
  1142. source.CopyInfo(fasm)
  1143. fasm.deps.Insert(source.path, source)
  1144. fasm.stage = STAGE_FASM2AS
  1145. fasm.processed = True
  1146. fasm.depsList = New TList
  1147. fasm.depsList.AddLast(source)
  1148. sources.Insert(StripExt(fasm.obj_path) + ".s", fasm)
  1149. Return fasm
  1150. End Method
  1151. Method CreateGenStage:TSourceFile(source:TSourceFile)
  1152. Local gen:TSourceFile = New TSourceFile
  1153. source.CopyInfo(gen)
  1154. If processor.BCCVersion() = "BlitzMax" And processor.CPU() = "x86" And processor.Platform() = "macos" Then
  1155. gen.deps.Insert(StripExt(source.obj_path) + ".s", source)
  1156. Else
  1157. gen.deps.Insert(source.path, source)
  1158. End If
  1159. gen.stage = STAGE_OBJECT
  1160. gen.processed = True
  1161. gen.depsList = New TList
  1162. gen.depsList.AddLast(source)
  1163. sources.Insert(StripExt(gen.obj_path) + ".c", gen)
  1164. Return gen
  1165. End Method
  1166. Method CreateIncBin:TSourceFile(source:TSourceFile, sourcePath:String)
  1167. Local path:String = StripDir(sourcePath) + opt_configmung + processor.CPU()
  1168. If opt_standalone Or (processor.CPU() = "x86" And processor.Platform() = "win32") Then
  1169. path :+ ".incbin.c"
  1170. Else
  1171. path :+ ".incbin2.c"
  1172. End If
  1173. Local ibPath:String = ExtractDir(sourcePath) + "/.bmx/" + path
  1174. Local ib:TSourceFile = GetSourceFile(ibPath,,,,False)
  1175. If Not ib Then
  1176. ib = New TSourceFile
  1177. ib.path = ibPath
  1178. ib.obj_path = StripExt(ib.path) + ".o"
  1179. ib.ext = "c"
  1180. ib.exti = String(processor.RunCommand("source_type", [ib.ext])).ToInt()
  1181. source.imports.AddLast(".bmx/" + StripDir(path) )
  1182. End If
  1183. If ib.includePaths.IsEmpty() Then
  1184. ib.CopyIncludePaths(source.includePaths)
  1185. End If
  1186. GetIncBinFileList(ib)
  1187. ib.time = FileTime(ib.path)
  1188. ib.obj_time = FileTime(ib.obj_path)
  1189. sources.Insert(ib.path, ib)
  1190. If opt_standalone And opt_boot Then
  1191. processor.PushSource(ib.path)
  1192. End If
  1193. Return ib
  1194. End Method
  1195. Method GetIncBinFileList(source:TSourceFile)
  1196. Local stream:TStream = ReadStream(source.path)
  1197. If stream Then
  1198. While Not stream.Eof()
  1199. Local line:String = stream.ReadLine()
  1200. If line.StartsWith("// FILE : ") Then
  1201. Local parts:String[] = line[10..].Split("~t")
  1202. Local ib:String = parts[0].Replace("~q", "")
  1203. If ib Then
  1204. source.incbins.AddLast(ib)
  1205. If parts.length = 2 Then
  1206. source.hashes.Insert(ib, parts[1])
  1207. End If
  1208. End If
  1209. Else If line.StartsWith("// ----") Then
  1210. Exit
  1211. EndIf
  1212. Wend
  1213. stream.Close()
  1214. End If
  1215. End Method
  1216. Method IncbinsDifference:Int(ib1:TList, ib2:TList)
  1217. If ib1.Count() <> ib2.Count() Then
  1218. Return True
  1219. End If
  1220. For Local ib:String = EachIn ib1
  1221. If Not ib2.Contains(ib) Then
  1222. Return True
  1223. End If
  1224. Next
  1225. For Local ib:String = EachIn ib2
  1226. If Not ib1.Contains(ib) Then
  1227. Return True
  1228. End If
  1229. Next
  1230. Return False
  1231. End Method
  1232. Method IncbinsHashDifference:Int(source:TSourceFile, ib:TSourceFile)
  1233. If source.hashes.IsEmpty() Then
  1234. Return True
  1235. End If
  1236. For Local file:String = EachIn source.hashes.Keys()
  1237. Local sourceHash:String = String(source.hashes.ValueForKey(file))
  1238. If sourceHash <> String(ib.hashes.ValueForKey(file)) Then
  1239. Return True
  1240. End If
  1241. Next
  1242. For Local file:String = EachIn ib.hashes.Keys()
  1243. Local ibHash:String = String(ib.hashes.ValueForKey(file))
  1244. If ibHash <> String(source.hashes.ValueForKey(file)) Then
  1245. Return True
  1246. End If
  1247. Next
  1248. End Method
  1249. Method CreateLinkStage:TSourceFile(source:TSourceFile, stage:Int = STAGE_LINK)
  1250. Local link:TSourceFile = New TSourceFile
  1251. source.CopyInfo(link)
  1252. link.deps.Insert(StripExt(link.obj_path) + ".c", source)
  1253. link.stage = stage
  1254. link.processed = True
  1255. link.depsList = New TList
  1256. link.depsList.AddLast(source)
  1257. If IOS_HAS_MERGE And processor.Platform() = "ios" Then
  1258. sources.Insert(link.obj_path, link)
  1259. Else
  1260. sources.Insert(link.arc_path, link)
  1261. End If
  1262. Return link
  1263. End Method
  1264. Method CreateMergeStage:TSourceFile(source:TSourceFile)
  1265. Local merge:TSourceFile = New TSourceFile
  1266. source.CopyInfo(merge)
  1267. merge.deps.Insert(merge.obj_path, source)
  1268. merge.stage = STAGE_MERGE
  1269. merge.processed = True
  1270. merge.depsList = New TList
  1271. merge.depsList.AddLast(source)
  1272. sources.Insert(merge.merge_path, merge)
  1273. Return merge
  1274. End Method
  1275. Method CalculateBatches:TList(files:TList)
  1276. Local batches:TList = New TList
  1277. Local count:Int
  1278. Local instances:TMap = New TMap
  1279. For Local m:TSourceFile = EachIn files
  1280. instances.Insert(m.GetSourcePath(), m)
  1281. count :+ 1
  1282. Next
  1283. Local dependencies:TMap = New TMap
  1284. For Local m:TSourceFile = EachIn files
  1285. dependencies.Insert(m.GetSourcePath(), m.deps)
  1286. Next
  1287. Local pct:Float = 100.0 / count
  1288. Local total:Float
  1289. Local num:Int
  1290. While Not dependencies.IsEmpty()
  1291. Local noDeps:TList = New TList
  1292. For Local depName:String = EachIn dependencies.Keys()
  1293. Local dep:TMap = TMap(dependencies.ValueForKey(depName))
  1294. If dep.IsEmpty() Then
  1295. noDeps.AddLast(depName)
  1296. End If
  1297. Next
  1298. If noDeps.IsEmpty() Then
  1299. ' circular dependency!
  1300. ' TODO : dump current list for user to work out?
  1301. Print "REMAINING :"
  1302. For Local depName:String = EachIn dependencies.Keys()
  1303. Print " " + depName
  1304. Next
  1305. Throw "circular dependency!"
  1306. End If
  1307. ' remove from dependencies
  1308. For Local name:String = EachIn noDeps
  1309. dependencies.Remove(name)
  1310. Next
  1311. For Local dep:TMap = EachIn dependencies.Values()
  1312. For Local name:String = EachIn noDeps
  1313. dep.Remove(name)
  1314. Next
  1315. Next
  1316. Local list:TList = New TList
  1317. For Local name:String = EachIn noDeps
  1318. Local m:TSourceFile = TSourceFile(instances.ValueForKey(name))
  1319. list.AddLast(m)
  1320. Next
  1321. batches.AddLast(list)
  1322. Wend
  1323. ' post process batches
  1324. Local suffix:String[]
  1325. Local stage:Int
  1326. For Local i:Int = 0 Until 3
  1327. Select i
  1328. Case 0
  1329. suffix = ["c", "cpp", "cc", "cxx", "m", "mm"]
  1330. Case 1
  1331. suffix = ["o"]
  1332. stage = STAGE_LINK
  1333. Case 2
  1334. suffix = ["o"]
  1335. stage = STAGE_APP_LINK
  1336. End Select
  1337. Local newList:TList = New TList
  1338. For Local list:TList = EachIn batches
  1339. For Local f:TSourceFile = EachIn list
  1340. Local p:String = f.GetSourcePath()
  1341. If Not p.EndsWith("bmx") Then
  1342. For Local s:String = EachIn suffix
  1343. If p.EndsWith(s) Then
  1344. If app_iface And stage Then
  1345. If (stage = STAGE_LINK And app_iface = f.iface_path) Or (stage = STAGE_APP_LINK And app_iface <> f.iface_path) Then
  1346. Continue
  1347. End If
  1348. End If
  1349. newList.AddLast(f)
  1350. list.Remove(f)
  1351. If list.IsEmpty() Then
  1352. batches.Remove(list)
  1353. End If
  1354. ' found, no need to loop further
  1355. Exit
  1356. End If
  1357. Next
  1358. End If
  1359. Next
  1360. Next
  1361. If Not newList.IsEmpty() Then
  1362. batches.AddLast(newList)
  1363. End If
  1364. Next
  1365. For Local list:TList = EachIn batches
  1366. For Local m:TSourceFile = EachIn list
  1367. total :+ pct
  1368. num :+ 1
  1369. If num = count Then
  1370. m.pct = 100
  1371. Else
  1372. m.pct = total
  1373. End If
  1374. Next
  1375. Next
  1376. Return batches
  1377. End Method
  1378. Method ShowPct:String(pct:Int)
  1379. Local s:String = "["
  1380. Local p:String = String.FromInt(pct)
  1381. Select p.length
  1382. Case 1
  1383. s :+ " "
  1384. Case 2
  1385. s :+ " "
  1386. End Select
  1387. Return s + p + "%] "
  1388. End Method
  1389. Method FixPct:String(pct:String)
  1390. If processor.Platform() = "win32" Then
  1391. Return pct.Replace("%", "%%")
  1392. Else
  1393. Return pct
  1394. End If
  1395. End Method
  1396. Method CheckPath:String(basePath:String, path:String)
  1397. Local p:String = RealPath(basePath + "/" + path)
  1398. If Not FileType(p) Then
  1399. ' maybe path is a full path already?
  1400. p = RealPath(path)
  1401. If Not FileType(p) Then
  1402. ' meh... fallback to original
  1403. p = RealPath(basePath + "/" + path)
  1404. End If
  1405. End If
  1406. Return p
  1407. End Method
  1408. Method DoCallback(src:String)
  1409. Local update:Int = True
  1410. Local m:TSourceFile = TSourceFile(sources.ValueForKey(src))
  1411. If m Then
  1412. If FileType(m.iface_path) = FILETYPE_FILE Then
  1413. ' has the interface/api changed since the last build?
  1414. If FileType(m.iface_path2) = FILETYPE_FILE And m.time = FileTime( m.path ) Then
  1415. If FileSize(m.iface_path) = FileSize(m.iface_path2) Then
  1416. Local i_bytes:Byte[] = LoadByteArray(m.iface_path)
  1417. Local i_bytes2:Byte[] = LoadByteArray(m.iface_path2)
  1418. ?bmxng
  1419. If i_bytes.length = i_bytes2.length And memcmp_( i_bytes, i_bytes2, Size_T(i_bytes.length) )=0 Then
  1420. ?Not bmxng
  1421. If i_bytes.length = i_bytes2.length And memcmp_( i_bytes, i_bytes2, i_bytes.length )=0 Then
  1422. ?
  1423. update = False
  1424. End If
  1425. End If
  1426. End If
  1427. If update Then
  1428. CopyFile m.iface_path, m.iface_path2
  1429. Else If m.iface_time < m.MaxIfaceTime() Then
  1430. SetFileTimeNow(m.iface_path2)
  1431. m.iface_time = time_(Null)
  1432. m.maxIfaceTimeCache = -1
  1433. End If
  1434. End If
  1435. If update Then
  1436. m.SetRequiresBuild(True)
  1437. m.iface_time = time_(Null)
  1438. m.maxIfaceTimeCache = -1
  1439. m.gen_time = time_(Null)
  1440. End If
  1441. End If
  1442. End Method
  1443. End Type
  1444. Type TArcTask
  1445. Field m:TSourceFile
  1446. Field path:String
  1447. Field oobjs:TList
  1448. Method Create:TArcTask(m:TSourceFile, path$ , oobjs:TList )
  1449. Self.m = m
  1450. Self.path = path
  1451. Self.oobjs = oobjs
  1452. Return Self
  1453. End Method
  1454. Function _CreateArc:Object(data:Object)
  1455. Return TArcTask(data).CreateArc()
  1456. End Function
  1457. Method CreateArc:Object()
  1458. DeleteFile path
  1459. Local cmd$,t$
  1460. If processor.Platform() = "win32"
  1461. For t$=EachIn oobjs
  1462. If Len(cmd)+Len(t)>1000
  1463. If opt_standalone And Not opt_nolog processor.PushLog(cmd)
  1464. If processor.Sys( cmd )
  1465. DeleteFile path
  1466. Throw "Build Error: Failed to create archive "+path
  1467. EndIf
  1468. cmd=""
  1469. EndIf
  1470. If Not cmd Then
  1471. Local prefix:String = processor.MinGWExePrefix()
  1472. Local ext:String = ""
  1473. If processor.OSPlatform() = "win32" Then
  1474. ext = ".exe"
  1475. End If
  1476. cmd= processor.Option("path_to_ar", processor.MinGWBinPath() + "/" + prefix + "ar" + ext) + " -rc "+CQuote(path)
  1477. End If
  1478. cmd:+" "+CQuote(t)
  1479. Next
  1480. End If
  1481. If processor.Platform() = "macos" Or processor.Platform() = "osx" Then
  1482. cmd=processor.Option(processor.BuildName("libtool"), "libtool") + " -o "+CQuote(path)
  1483. For Local t$=EachIn oobjs
  1484. cmd:+" "+CQuote(t)
  1485. Next
  1486. End If
  1487. If processor.Platform() = "ios" Then
  1488. Local proc:String = processor.CPU()
  1489. Select proc
  1490. Case "x86"
  1491. proc = "i386"
  1492. Case "x64"
  1493. proc = "x86_64"
  1494. End Select
  1495. cmd= processor.Option(processor.BuildName("libtool"), "libtool") + " -static -arch_only " + proc + " -o "+CQuote(path)
  1496. For Local t$=EachIn oobjs
  1497. cmd:+" "+CQuote(t)
  1498. Next
  1499. End If
  1500. If processor.Platform() = "linux" Or processor.Platform() = "raspberrypi" Or processor.Platform() = "android" Or processor.Platform() = "emscripten" Or processor.Platform() = "nx" Or processor.Platform() = "haiku"
  1501. For Local t$=EachIn oobjs
  1502. If Len(cmd)+Len(t)>1000
  1503. If opt_standalone And Not opt_nolog processor.PushLog(cmd)
  1504. If processor.Sys( cmd )
  1505. DeleteFile path
  1506. Throw "Build Error: Failed to create archive "+path
  1507. EndIf
  1508. cmd=""
  1509. EndIf
  1510. If processor.Platform() = "emscripten" Then
  1511. If Not cmd cmd=processor.Option(processor.BuildName("ar"), "emar") + " r "+CQuote(path)
  1512. Else
  1513. If Not cmd cmd=processor.Option(processor.BuildName("ar"), "ar") + " -r "+CQuote(path)
  1514. End If
  1515. cmd:+" "+CQuote(t)
  1516. Next
  1517. End If
  1518. If cmd
  1519. If opt_standalone And Not opt_nolog processor.PushLog(cmd)
  1520. If processor.Sys( cmd )
  1521. DeleteFile path
  1522. Throw "Build Error: Failed to create archive "+path
  1523. End If
  1524. EndIf
  1525. m.arc_time = time_(Null)
  1526. m.obj_time = time_(Null)
  1527. End Method
  1528. End Type