bmk_util.bmx 52 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051
  1. SuperStrict
  2. Import "bmk_config.bmx"
  3. Import "bmk_ng.bmx"
  4. Import "file_util.c"
  5. Import "hash.c"
  6. 'OS X Nasm doesn't work? Used to produce incorrect reloc offsets - haven't checked for a while
  7. Const USE_NASM:Int=False
  8. Const CC_WARNINGS:Int=False'True
  9. Const IOS_HAS_MERGE:Int = False
  10. Type TModOpt ' BaH
  11. Field cc_opts:String = ""
  12. Field ld_opts:TList = New TList
  13. Field cpp_opts:String = ""
  14. Field c_opts:String = ""
  15. Method addOption(qval:String, path:String)
  16. If qval.startswith("CC_OPTS") Then
  17. cc_opts:+ " " + setPath(ReQuote(qval[qval.find(":") + 1..].Trim()), path)
  18. ElseIf qval.startswith("CPP_OPTS") Then
  19. cpp_opts:+ " " + setPath(ReQuote(qval[qval.find(":") + 1..].Trim()), path)
  20. ElseIf qval.startswith("C_OPTS") Then
  21. c_opts:+ " " + setPath(ReQuote(qval[qval.find(":") + 1..].Trim()), path)
  22. ElseIf qval.startswith("LD_OPTS") Then
  23. Local opt:String = ReQuote(qval[qval.find(":") + 1..].Trim())
  24. If opt.startsWith("-L") Then
  25. opt = "-L" + CQuote(opt[2..])
  26. End If
  27. ld_opts.addLast opt
  28. ElseIf qval.startswith("CC_VOPT") Then
  29. setOption("cc_opts", qval)
  30. ElseIf qval.startswith("CPP_VOPT") Then
  31. setOption("cpp_opts", qval)
  32. ElseIf qval.startswith("C_VOPT") Then
  33. setOption("c_opts", qval)
  34. ElseIf qval.startswith("LD_VOPT") Then
  35. setOption("ld_opts", qval)
  36. End If
  37. End Method
  38. Function setOption(option:String, qval:String)
  39. Local opt:String = qval[qval.find(":") + 1..].Trim()
  40. Local parts:String[] = opt.Split("|")
  41. If parts.length = 2 Then
  42. globals.SetOption(option, parts[0].trim(), parts[1].Trim())
  43. End If
  44. End Function
  45. Method hasCCopt:Int(value:String)
  46. Return cc_opts.find(value) >= 0
  47. End Method
  48. Method hasCPPopt:Int(value:String)
  49. Return cpp_opts.find(value) >= 0
  50. End Method
  51. Method hasCopt:Int(value:String)
  52. Return c_opts.find(value) >= 0
  53. End Method
  54. Method hasLDopt:Int(value:String)
  55. For Local opt:String = EachIn ld_opts
  56. If opt.find(value) >= 0 Then
  57. Return True
  58. End If
  59. Next
  60. Return False
  61. End Method
  62. Function setPath:String(value:String, path:String)
  63. If value.Contains("%PWD%") Then
  64. Return value.Replace("%PWD%", path)
  65. End If
  66. ' var replace
  67. Local s:Int = value.Find("%")
  68. If s >= 0 Then
  69. Local e:Int = value.Find("%", s + 1)
  70. If e >= 0 Then
  71. Local v:String = value[s+1..e]
  72. value = value[..s] + processor.option(v, "NA") + value[e+1..]
  73. End If
  74. End If
  75. Return value
  76. End Function
  77. End Type
  78. Global mod_opts:TModOpt ' BaH
  79. Function Match:Int( ext$,pat$ )
  80. Return (";"+pat+";").Find( ";"+ext+";" )<>-1
  81. End Function
  82. Function HTTPEsc$( t$ )
  83. t=t.Replace( " ","%20" )
  84. Return t
  85. End Function
  86. Function Sys:Int( cmd$ )
  87. If opt_verbose
  88. Print cmd
  89. Else If opt_dumpbuild
  90. Local p$=cmd
  91. p=p.Replace( BlitzMaxPath()+"/","./" )
  92. WriteStdout p+"~n"
  93. Local t$="mkdir "
  94. If cmd.StartsWith( t ) And FileType( cmd[t.length..] ) Return 0
  95. EndIf
  96. Return system_( cmd )
  97. End Function
  98. Function Ranlib( dir$ )
  99. '
  100. ?MacOS
  101. If macos_version>=$1040 Return
  102. ?
  103. '
  104. For Local f$=EachIn LoadDir( dir )
  105. Local p$=dir+"/"+f
  106. Select FileType( p )
  107. Case FILETYPE_DIR
  108. Ranlib p
  109. Case FILETYPE_FILE
  110. If ExtractExt(f).ToLower()="a" Sys "ranlib "+p
  111. End Select
  112. Next
  113. End Function
  114. Function Assemble( src$,obj$ )
  115. processor.RunCommand("assemble", [src, obj])
  116. End Function
  117. Function AssembleNative( src$, obj$ )
  118. processor.RunCommand("assembleNative", [src, obj])
  119. End Function
  120. Function Fasm2As( src$,obj$ )
  121. processor.RunCommand("fasm2as", [src, obj])
  122. End Function
  123. Function CompileC( src$,obj$,opts$ )
  124. processor.RunCommand("CompileC", [src, obj, opts])
  125. End Function
  126. Function CompileBMX( src$,obj$,opts$ )
  127. If processor.BCCVersion() <> "BlitzMax" Then
  128. opts :+ " -p " + processor.Platform()
  129. End If
  130. If opt_standalone opt_nolog = True
  131. processor.RunCommand("CompileBMX", [src, obj, opts])
  132. If opt_standalone opt_nolog = False
  133. End Function
  134. Function CreateMergeArc( path$ , arc_path:String )
  135. Local cmd$
  136. If processor.Platform() = "ios" Then
  137. Local proc:String = processor.CPU()
  138. Local opp:String
  139. Select proc
  140. Case "x86"
  141. proc = "i386"
  142. opp = "x86_64"
  143. Case "x64"
  144. proc = "x86_64"
  145. opp = "i386"
  146. Case "armv7"
  147. opp = "arm64"
  148. Case "arm64"
  149. opp = "armv7"
  150. End Select
  151. cmd = "lipo "
  152. If Not FileType(path) Then
  153. cmd :+ "-create -arch_blank " + opp + " -arch "
  154. Else
  155. cmd :+ CQuote(path)
  156. cmd :+ " -replace "
  157. End If
  158. cmd :+ proc + " " + CQuote(arc_path)
  159. cmd :+ " -output " + CQuote(path)
  160. End If
  161. If cmd And processor.MultiSys( cmd, path, Null, Null )
  162. DeleteFile path
  163. Throw "Build Error: Failed to merge archive " + path
  164. EndIf
  165. End Function
  166. Function LinkApp( path$,lnk_files:TList,makelib:Int,opts$ )
  167. If processor.Platform() = "ios" Then
  168. PackageIOSApp(path, lnk_files, opts)
  169. Return
  170. End If
  171. DeleteFile path
  172. Local cmd$
  173. Local files$
  174. Local tmpfile$=BlitzMaxPath()+"/tmp/ld.tmp"
  175. Local sb:TStringBuffer = New TStringBuffer
  176. Local fb:TStringBuffer = New TStringBuffer
  177. If opt_standalone tmpfile = String(globals.GetRawVar("EXEPATH")) + "/ld." + processor.AppDet() + ".txt.tmp"
  178. If processor.Platform() = "macos" Or processor.Platform() = "osx" Then
  179. sb.Append(processor.Option(processor.BuildName("gpp"), "g++"))
  180. Select processor.CPU()
  181. Case "ppc"
  182. sb.Append(" -arch ppc" )
  183. Case "x86"
  184. sb.Append(" -arch i386 -read_only_relocs suppress")
  185. Case "x64"
  186. sb.Append(" -arch x86_64")
  187. Case "arm64"
  188. sb.Append(" -arch arm64")
  189. End Select
  190. If processor.Option(processor.BuildName("sysroot"), "") Then
  191. sb.Append(" -isysroot ").Append(processor.Option(processor.BuildName("sysroot"), ""))
  192. End If
  193. sb.Append(" -o ").Append(CQuote( path ))
  194. If opt_debug Or opt_gdbdebug Then
  195. sb.Append(" -g")
  196. End If
  197. If processor.BCCVersion() = "BlitzMax" Then
  198. sb.Append(" ").Append(CQuote("-L" +CQuote( BlitzMaxPath()+"/lib" ) ))
  199. End If
  200. If Not opt_dumpbuild Then
  201. sb.Append(" -filelist ").Append(CQuote( tmpfile ))
  202. End If
  203. For Local t$=EachIn lnk_files
  204. If opt_dumpbuild Or (t[..1]="-") Or (t[..1]="`")
  205. sb.Append(" ").Append(t)
  206. Else
  207. fb.Append(t).Append(Chr(10))
  208. EndIf
  209. Next
  210. sb.Append(" -lSystem -framework CoreServices -framework CoreFoundation")
  211. If opts Then
  212. sb.Append(" ").Append(opts)
  213. End If
  214. If processor.CPU() = "ppc"
  215. sb.Append(" -lc -lgcc_eh")
  216. End If
  217. End If
  218. If processor.Platform() = "win32"
  219. Local ext:String = ""
  220. ?win32
  221. ext = ".exe"
  222. ?
  223. Local version:Int = Int(processor.GCCVersion(True))
  224. Local usingLD:Int = False
  225. Local options:TStringBuffer = fb
  226. If processor.HasClang() Then
  227. options = sb
  228. End If
  229. ' always use g++ instead of LD...
  230. ' uncomment if we want to change to only use LD for GCC's < 4.x
  231. 'If version < 40000 Then
  232. ' usingLD = True
  233. 'End If
  234. ' or we can override in the config...
  235. If globals.Get("link_with_ld") Or (version >= 40600 And version < 60000) Then
  236. usingLD = True
  237. End If
  238. Local blitzMaxLibDir:String = "/lib"
  239. If processor.CPU()="x64" Then
  240. blitzMaxLibDir = "/lib64"
  241. End If
  242. If usingLD Then
  243. sb.Append(CQuote(processor.Option("path_to_ld", processor.MinGWBinPath()+ "/ld" + ext))).Append(" -stack 4194304")
  244. If Not opt_debug And Not opt_gdbdebug Then
  245. sb.Append(processor.option("strip.debug", " -s "))
  246. End If
  247. If opt_apptype="gui" Then
  248. sb.Append(" -subsystem windows")
  249. End If
  250. Else
  251. Local prefix:String = processor.MinGWExePrefix()
  252. sb.Append(CQuote(processor.Option("path_to_gpp", processor.MinGWBinPath() + "/" + prefix + "g++" + ext)))
  253. If Not processor.HasClang() Then
  254. If version < 60000 Then
  255. sb.Append(" --stack=4194304")
  256. Else
  257. sb.Append(" -Wl,--stack,4194304")
  258. End If
  259. End If
  260. If Not opt_debug And Not opt_gdbdebug Then
  261. sb.Append(processor.option("strip.debug", " -s "))
  262. End If
  263. If opt_apptype="gui"
  264. If version < 60000 Then
  265. sb.Append(" --subsystem,windows -mwindows")
  266. Else
  267. sb.Append(" -Wl,--subsystem,windows -mwindows")
  268. End If
  269. Else
  270. If Not makelib
  271. sb.Append(" -mconsole")
  272. End If
  273. End If
  274. If opt_threaded Then
  275. If version < 60000 Then
  276. sb.Append(" -mthread")
  277. Else
  278. sb.Append(" -mthreads")
  279. End If
  280. End If
  281. End If
  282. If makelib Then
  283. sb.Append(" -shared")
  284. If processor.Platform() = "win32" Then
  285. sb.Append(" -static-libgcc")
  286. End If
  287. Else
  288. sb.Append(" -static")
  289. If opt_gprof Then
  290. sb.Append(" -pg")
  291. End If
  292. End If
  293. sb.Append(" -o ").Append(CQuote( path ))
  294. If usingLD Then
  295. If processor.CPU()="x86"
  296. sb.Append(" ").Append(processor.MinGWLinkPaths()) ' the BlitzMax lib folder
  297. ' linking for x86 when using mingw64 binaries
  298. If processor.HasTarget("x86_64") Then
  299. sb.Append(" -mi386pe")
  300. End If
  301. Else
  302. sb.Append(" ").Append(processor.MinGWLinkPaths()) ' the BlitzMax lib folder
  303. End If
  304. If globals.Get("path_to_mingw_lib") Then
  305. sb.Append(" ").Append(CQuote( "-L"+CQuote( RealPath(processor.Option("path_to_mingw_lib", BlitzMaxPath()+"/lib") ) ) ))
  306. End If
  307. If globals.Get("path_to_mingw_lib2") Then
  308. sb.Append(" ").Append(CQuote( "-L"+CQuote( RealPath(processor.Option("path_to_mingw_lib2", BlitzMaxPath()+"/lib") ) ) ))
  309. End If
  310. If globals.Get("path_to_mingw_lib3") Then
  311. sb.Append(" ").Append(CQuote( "-L"+CQuote( RealPath(processor.Option("path_to_mingw_lib3", BlitzMaxPath()+"/lib") ) ) ))
  312. End If
  313. End If
  314. If makelib
  315. Local def$=StripExt(path)+".def"
  316. Local imp$=StripExt(path)+".a"
  317. If FileType( def )<>FILETYPE_FILE Then
  318. Print "Warning: Cannot locate .def file (" + def + "). Exporting ALL symbols."
  319. Else
  320. sb.Append(" ").Append(CQuote( def ))
  321. End If
  322. If version < 60000 Then
  323. sb.Append(" --out-implib ").Append(CQuote( imp ))
  324. If usingLD Then
  325. options.Append(" ").Append(CQuote( RealPath(processor.Option("path_to_mingw_lib", processor.MinGWDLLCrtPath()) + "/dllcrt2.o" ) ))
  326. End If
  327. Else
  328. sb.Append(" -Wl,--out-implib,").Append(CQuote( imp ))
  329. End If
  330. Else
  331. If usingLD
  332. fb.Append(" ").Append(CQuote( RealPath(processor.Option("path_to_mingw_lib2", processor.MinGWCrtPath()) + "/crtbegin.o" ) ))
  333. fb.Append(" ").Append(CQuote( RealPath(processor.Option("path_to_mingw_lib", processor.MinGWDLLCrtPath()) + "/crt2.o" ) ))
  334. End If
  335. EndIf
  336. Local xpmanifest$
  337. For Local f$=EachIn lnk_files
  338. Local t$=CQuote( f )
  339. If processor.HasClang() Then
  340. If f.StartsWith("-l") Then
  341. f = f.Replace(" ", "~n")
  342. End If
  343. t = f.Replace("\", "/").Replace(" ", "\ ").Replace("'", "\'")
  344. End If
  345. If opt_dumpbuild Or (t[..1]="-" And t[..2]<>"-l")
  346. sb.Append(" ").Append(t)
  347. Else
  348. If f.EndsWith( "/win32maxguiex.mod/xpmanifest.o" )
  349. xpmanifest=t
  350. Else
  351. If processor.HasClang() Then
  352. fb.Append("~n").Append(t)
  353. Else
  354. fb.Append(" ").Append(t)
  355. End If
  356. EndIf
  357. EndIf
  358. Next
  359. If xpmanifest Then
  360. If processor.HasClang() Then
  361. fb.Append("~n").Append(xpmanifest)
  362. Else
  363. fb.Append(" ").Append(xpmanifest)
  364. End If
  365. End If
  366. sb.Append(" ")
  367. If processor.HasClang() Then
  368. sb.Append("@")
  369. End If
  370. sb.Append(CQuote( tmpfile ))
  371. options.Append(" -lgdi32 -lwsock32 -lwinmm -ladvapi32")
  372. ' add any user-defined linker options
  373. options.Append(" ").Append(opts)
  374. If usingLD
  375. If opts.Find("stdc++") = -1 Then
  376. options.Append(" -lstdc++")
  377. End If
  378. options.Append(" -lmingwex")
  379. ' for a native Win32 runtiime of mingw 3.4.5, this needs to appear early.
  380. 'If Not processor.Option("path_to_mingw", "") Then
  381. options.Append(" -lmingw32")
  382. 'End If
  383. If opts.Find("gcc") = -1 Then
  384. options.Append(" -lgcc")
  385. End If
  386. ' if using 4.8+ or mingw64, we need to link to pthreads
  387. If version >= 40800 Or processor.HasTarget("x86_64") Or processor.HasClang() Then
  388. options.Append(" -lwinpthread ")
  389. If processor.CPU()="x86" Then
  390. options.Append(" -lgcc")
  391. End If
  392. End If
  393. options.Append(" -lmoldname -lmsvcrt ")
  394. End If
  395. options.Append(" -luser32 -lkernel32 ")
  396. 'If processor.Option("path_to_mingw", "") Then
  397. ' for a non-native Win32 runtime, this needs to appear last.
  398. ' (Actually, also for native gcc 4.x, but I dunno how we'll handle that yet!)
  399. If usingLD
  400. options.Append(" -lmingw32 ")
  401. End If
  402. ' add any user-defined linker options, again - just to cover whether we missed dependencies before.
  403. options.Append(" ").Append(opts)
  404. 'End If
  405. If Not makelib
  406. If usingLD
  407. options.Append(" ").Append(CQuote( processor.Option("path_to_mingw_lib2", processor.MinGWCrtPath()) + "/crtend.o" ))
  408. End If
  409. EndIf
  410. If Not processor.HasClang() Then
  411. fb.Insert(0,"INPUT(").Append(")")
  412. End If
  413. End If
  414. If processor.Platform() = "linux" Or processor.Platform() = "raspberrypi" Or processor.Platform() = "haiku"
  415. sb.Append(processor.Option(processor.BuildName("gpp"), "g++"))
  416. 'cmd:+" -m32 -s -Os -pthread"
  417. If processor.Platform() <> "raspberrypi" And processor.Platform() <> "haiku" Then
  418. If processor.CPU() = "x86" Or processor.CPU() = "arm" Then
  419. sb.Append(" -m32")
  420. End If
  421. If processor.CPU() = "x64" Then
  422. sb.Append(" -m64")
  423. End If
  424. End If
  425. If opt_static Then
  426. sb.Append(" -static")
  427. End If
  428. If processor.Platform() <> "haiku" And Not opt_nopie Then
  429. sb.Append(" -no-pie -fpie")
  430. End If
  431. If opt_gprof Then
  432. sb.Append(" -pg")
  433. End If
  434. If processor.Platform() <> "haiku" Then
  435. sb.Append(" -pthread")
  436. Else
  437. sb.Append(" -lpthread")
  438. End If
  439. sb.Append(" -o ").Append(CQuote( path ))
  440. sb.Append(" ").Append(CQuote( tmpfile ))
  441. If processor.Platform() <> "haiku" Then
  442. If processor.CPU() = "x86" Then
  443. sb.Append(" -L").Append(processor.Option(processor.BuildName("lib32"), "/usr/lib32"))
  444. End If
  445. sb.Append(" -L").Append(processor.Option(processor.BuildName("x11lib"), "/usr/X11R6/lib"))
  446. sb.Append(" -L").Append(processor.Option(processor.BuildName("lib"), "/usr/lib"))
  447. Else
  448. sb.Append(" -L").Append(CQuote( "/boot/system/develop/lib" ))
  449. sb.Append(" -L").Append(CQuote( BlitzMaxPath()+"/lib" ))
  450. End If
  451. For Local t$=EachIn lnk_files
  452. t=CQuote(t)
  453. If opt_dumpbuild Or (t[..1]="-" And t[..2]<>"-l") Or (t[..1]="`")
  454. sb.Append(" ").Append(t)
  455. Else
  456. fb.Append(" ").Append(t)
  457. EndIf
  458. Next
  459. fb.Insert(0,"INPUT(").Append(")")
  460. End If
  461. If processor.Platform() = "android" Then
  462. sb.Append(processor.Option(processor.BuildName("gpp"), "g++"))
  463. Local libso:String = StripDir(path)
  464. sb.Append(" -fPIC -shared ")
  465. ' for stlport shared lib
  466. sb.Append(" -L").Append(AndroidSTLPortDir())
  467. sb.Append(" -Wl,-soname,lib").Append(libso).Append(".so ")
  468. sb.Append(" -Wl,--export-dynamic -rdynamic ")
  469. sb.Append(" -o ").Append(CQuote( ExtractDir(path) + "/lib" + libso + ".so" ))
  470. sb.Append(" ").Append(CQuote( tmpfile ))
  471. sb.Append(" ").Append(processor.Option("android.platform.sysroot", ""))
  472. For Local t$=EachIn lnk_files
  473. t=CQuote(t)
  474. If opt_dumpbuild Or (t[..1]="-" And t[..2]<>"-l")
  475. sb.Append(" ").Append(t)
  476. Else
  477. fb.Append(" ").Append(t)
  478. EndIf
  479. Next
  480. sb.Append(" -Wl,-Bdynamic -lGLESv2 -lGLESv1_CM ")
  481. ' libstlport
  482. sb.Append(" -lstlport_shared")
  483. sb.Append(" -llog -ldl -landroid ")
  484. fb.Insert(0,"INPUT(").Append(")")
  485. End If
  486. If processor.Platform() = "emscripten"
  487. sb.Append(processor.Option(processor.BuildName("gpp"), "em++"))
  488. ' cmd:+" -pthread" ' No threading support yet...
  489. sb.Append(" -o ").Append(CQuote( path ))
  490. 'cmd:+" -filelist "+CQuote( tmpfile )
  491. sb.Append(" ").Append(opts)
  492. For Local t$=EachIn lnk_files
  493. t=CQuote(t)
  494. 'If opt_dumpbuild Or (t[..1]="-" And t[..2]<>"-l")
  495. sb.Append(" ").Append(t)
  496. 'Else
  497. ' files:+" "+t
  498. 'EndIf
  499. Next
  500. fb.Insert(0,"INPUT(").Append(")")
  501. End If
  502. If processor.Platform() = "nx" Then
  503. sb.Append(processor.Option(processor.BuildName("gpp"), "g++"))
  504. Local libso:String = StripDir(path)
  505. sb.Append(" -MMD -MP -MF ")
  506. sb.Append(" -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE ")
  507. sb.Append(" -specs=").Append(processor.Option("nx.devkitpro", "")).Append("/libnx/switch.specs")
  508. sb.Append(" -g")
  509. 'sb.Append(" -Wl,-Map,").Append(StripExt(path)).Append(".map")
  510. sb.Append(" -L").Append(NXLibDir())
  511. sb.Append(" -o ").Append(CQuote( path ))
  512. sb.Append(" ").Append(CQuote( tmpfile ))
  513. Local endLinks:TList = New TList
  514. For Local t$=EachIn lnk_files
  515. t=CQuote(t)
  516. If opt_dumpbuild Or (t[..1]="-" And t[..2]<>"-l") Or (t[..1]="`")
  517. sb.Append(" ").Append(t)
  518. Else
  519. If t.Contains("appstub") Or t.Contains("blitz.mod") Then
  520. endLinks.AddLast(t)
  521. Continue
  522. End If
  523. fb.Append(" ").Append(t)
  524. EndIf
  525. Next
  526. fb.Append(" -lnx -lm")
  527. For Local t:String = EachIn endLinks
  528. fb.Append(" ").Append(t)
  529. Next
  530. fb.Insert(0,"INPUT(").Append(")")
  531. End If
  532. Local t$=getenv_( "BMK_LD_OPTS" )
  533. If t
  534. sb.Append(" ").Append(t)
  535. EndIf
  536. cmd = sb.ToString()
  537. files = fb.ToString()
  538. If Not opt_standalone Then
  539. Local stream:TStream=WriteStream( tmpfile )
  540. stream.WriteBytes files.ToCString(),files.length
  541. stream.Close
  542. End If
  543. If processor.Sys( cmd ) Throw "Build Error: Failed to link "+path
  544. If opt_standalone
  545. Local stream:TStream=WriteStream( StripExt(tmpfile) )
  546. Local f:String = processor.FixPaths(files)
  547. stream.WriteBytes f.ToCString(),f.length
  548. stream.Close
  549. End If
  550. End Function
  551. Function MergeApp(file1:String, file2:String, outputFile:String)
  552. If Not opt_quiet Print "[100%] Merging:"+StripDir(file1) + " + " + StripDir(file2) + " > " + StripDir(outputFile)
  553. Local cmd:String = "lipo -create ~q" + file1 + "~q ~q" + file2 + "~q -output ~q" + outputFile + "~q"
  554. If processor.Sys( cmd ) Throw "Merge Error: Failed to merge " + file1 + " and " + file2 + " into " + outputFile
  555. DeleteFile file1
  556. DeleteFile file2
  557. End Function
  558. Function DeployAndroidProject()
  559. Local appId:String = StripDir(StripExt(opt_outfile))
  560. If opt_debug And opt_outfile.EndsWith(".debug") Then
  561. appId :+ ".debug"
  562. End If
  563. Local buildDir:String = ExtractDir(opt_outfile)
  564. ' eg. android-project-test_01
  565. Local projectDir:String = buildDir + "/android-project-" + appId '+ "-" + processor.CPU()
  566. ' check for dir
  567. If Not FileType(projectDir) Then
  568. ' doesn't exist. create it
  569. Local resourceProject:String = BlitzMaxPath() + "/resources/android/android-project"
  570. If Not FileType(resourceProject) Then
  571. Throw "Missing resources folder for Android build : " + resourceProject
  572. End If
  573. CopyDir(resourceProject, projectDir)
  574. End If
  575. ' check for valid dir
  576. If FileType(projectDir) <> FILETYPE_DIR Then
  577. Throw "Error creating project dir '" + projectDir + "'"
  578. End If
  579. ' create assets dir if missing
  580. Local assetsDir:String = projectDir + "/assets"
  581. If opt_all Then
  582. ' remove assets if we are doing a full build
  583. DeleteDir(assetsDir, True)
  584. End If
  585. If FileType(assetsDir) <> FILETYPE_DIR Then
  586. CreateDir(assetsDir)
  587. If FileType(assetsDir) <> FILETYPE_DIR Then
  588. Throw "Error creating assests dir '" + assetsDir + "'"
  589. End If
  590. End If
  591. ' create libs/abi dir if missing
  592. Local abiDir:String = projectDir + "/libs"
  593. If FileType(abiDir) <> FILETYPE_DIR Then
  594. CreateDir(abiDir)
  595. If FileType(abiDir) <> FILETYPE_DIR Then
  596. Throw "Error creating libs dir '" + abiDir + "'"
  597. End If
  598. End If
  599. abiDir :+ "/" + GetAndroidArch()
  600. If FileType(abiDir) <> FILETYPE_DIR Then
  601. CreateDir(abiDir)
  602. If FileType(abiDir) <> FILETYPE_DIR Then
  603. Throw "Error creating libs abi dir '" + abiDir + "'"
  604. End If
  605. End If
  606. ' copy stlport
  607. Local stlportDest:String = abiDir + "/libstlport_shared.so"
  608. If opt_all Or Not FileType(stlportDest) Then
  609. Local stlportSrc:String = AndroidSTLPortDir() + "/libstlport_shared.so"
  610. CopyFile(stlportSrc, stlportDest)
  611. If Not FileType(stlportDest) Then
  612. Throw "Error copying libstlport_shared.so from '" + stlportSrc + "'"
  613. End If
  614. End If
  615. Local projectSettings:TMap = ParseApplicationIniFile()
  616. Local appPackage:String = String(projectSettings.ValueForKey("app.package"))
  617. Local packagePath:String = projectDir + "/src/" + PathFromPackage(appPackage)
  618. ' create the package
  619. If Not FileType(packagePath) Then
  620. CreateDir(packagePath, True)
  621. If FileType(packagePath) <> FILETYPE_DIR Then
  622. Throw "Error creating package '" + packagePath + "'"
  623. End If
  624. End If
  625. ' copy/create java
  626. Local gameClassFile:String = packagePath+ "/BlitzMaxApp.java"
  627. If Not FileType(gameClassFile) Then
  628. CopyFile(projectDir + "/BlitzMaxApp.java", gameClassFile)
  629. If Not FileType(gameClassFile) Then
  630. Throw "Error creating class file '" + gameClassFile + "'"
  631. End If
  632. End If
  633. ' merge project data
  634. ' update AndroidManifest.xml
  635. MergeFile(projectDir, "AndroidManifest.xml", projectSettings)
  636. ' update BlitzMaxApp.java
  637. MergeFile(packagePath, "BlitzMaxApp.java", projectSettings)
  638. Local javaApp:String = LoadString( gameClassFile )
  639. ' set the package
  640. javaApp = ReplaceBlock( javaApp, "app.package","package " + appPackage + ";" )
  641. ' lib imports
  642. javaApp = ReplaceBlock( javaApp, "lib.imports", GetAndroidLibImports() )
  643. SaveString(javaApp, gameClassFile)
  644. ' update strings.xml
  645. MergeFile(projectDir + "/res/values", "strings.xml", projectSettings)
  646. ' update build.xml
  647. MergeFile(projectDir, "build.xml", projectSettings)
  648. ' set the sdk target
  649. Local projectPropertiesFile:String = projectDir + "/project.properties"
  650. Local projectProperties:String = LoadString( projectPropertiesFile )
  651. projectProperties = ReplaceBlock( projectProperties, "sdk.target","target=android-" + processor.option("android.sdk.target", ""), "~n#")
  652. SaveString(projectProperties, projectPropertiesFile)
  653. ' copy resources to assets
  654. CopyAndroidResources(buildDir, assetsDir)
  655. End Function
  656. Function GetAndroidLibImports:String()
  657. Local imports:String
  658. imports = "System.loadLibrary( ~qstlport_shared~q);~n"
  659. ' TODO : others imported via project...
  660. Return imports
  661. End Function
  662. Function GetAndroidArch:String()
  663. Local arch:String
  664. Select processor.CPU()
  665. Case "x86"
  666. arch = "x86"
  667. Case "x64"
  668. arch = "x86_64"
  669. Case "arm"
  670. arch = "armeabi-v7a"
  671. Case "armeabi"
  672. arch = "armeabi"
  673. Case "armeabiv7a"
  674. arch = "armeabi-v7a"
  675. Case "arm64v8a"
  676. arch = "arm64-v8a"
  677. Default
  678. Throw "Not a valid architecture '" + processor.CPU() + "'"
  679. End Select
  680. Return arch
  681. End Function
  682. Function AndroidSTLPortDir:String()
  683. Return processor.Option("android.ndk", "") + "/sources/cxx-stl/stlport/libs/" + GetAndroidArch()
  684. End Function
  685. Function CopyAndroidResources(buildDir:String, assetsDir:String)
  686. Local paths:String[] = SplitPaths(String(globals.GetRawVar("resource_path")))
  687. If paths Then
  688. For Local dir:String = EachIn paths
  689. Local resourceDir:String = buildDir + "/" + dir
  690. If Not FileType(resourceDir) Then
  691. Print "Warning : Defined resource_path '" + dir + "' not found"
  692. End If
  693. If FileType(resourceDir) = FILETYPE_DIR Then
  694. CopyDir assetsDir + "/" + dir, resourceDir
  695. End If
  696. Next
  697. End If
  698. End Function
  699. Function GetAndroidSDKTarget:String()
  700. Local sdkPath:String = processor.Option("android.sdk", "") + "/platforms"
  701. Local target:String = processor.Option("android.sdk.target", "")
  702. Local targetPath:String
  703. If target Then
  704. targetPath = sdkPath + "/android-" + target
  705. If FileType(targetPath) = FILETYPE_DIR Then
  706. Return target
  707. End If
  708. End If
  709. ' find highest numbered target platform dir
  710. Local dirs:String[] = LoadDir(sdkPath, True)
  711. Local high:Int
  712. For Local dir:String = EachIn dirs
  713. Local index:Int = dir.Find("android-")
  714. If index >= 0 Then
  715. Local value:Int = dir[index + 8..].ToInt()
  716. high = Max(value, high)
  717. End If
  718. Next
  719. If high > 0 Then
  720. Return high
  721. End If
  722. End Function
  723. Function NXLibDir:String()
  724. Return processor.Option("nx.devkitpro", "") + "/libnx/lib"
  725. End Function
  726. Function NxToolsDir:String()
  727. Return processor.Option("nx.devkitpro", "") + "/tools/bin"
  728. End Function
  729. Function BuildNxDependencies()
  730. BuildNxNso()
  731. BuildNxNacp()
  732. BuildNxNro()
  733. End Function
  734. Function BuildNxNso()
  735. If Not opt_quiet Print "Building:" + StripDir(StripExt(opt_outfile)) + ".nso"
  736. Local elf2nso:String = NxToolsDir() + "/elf2nso"
  737. ?win32
  738. elf2nso :+ ".exe"
  739. ?
  740. If Not FileType(elf2nso) Then
  741. Throw "elf2nso tool not present at " + elf2nso
  742. End If
  743. Local app:String = StripExt(opt_outfile)
  744. Local cmd:String = elf2nso + " " + CQuote(app + ".elf")
  745. cmd :+ " " + CQuote(app + ".nso")
  746. Sys(cmd)
  747. End Function
  748. Function BuildNxNacp()
  749. If Not opt_quiet Print "Building:" + StripDir(StripExt(opt_outfile)) + ".nacp"
  750. Local nacptool:String = NxToolsDir() + "/nacptool"
  751. ?win32
  752. nacptool :+ ".exe"
  753. ?
  754. If Not FileType(nacptool) Then
  755. Throw "nacptool tool not present at " + nacptool
  756. End If
  757. Local app:String = StripExt(opt_outfile)
  758. Local cmd:String = nacptool + " --create"
  759. Local name:String = processor.AppSetting("app.name")
  760. If Not name Then
  761. name = StripDir(StripExt(opt_outfile))
  762. End If
  763. cmd :+ " " + CQuote(name)
  764. Local auth:String = processor.AppSetting("app.company")
  765. If Not auth Then
  766. auth = "Unspecified Author"
  767. End If
  768. cmd :+ " " + CQuote(auth)
  769. Local ver:String = processor.AppSetting("app.version.name")
  770. If Not ver Then
  771. ver = "1.0.0"
  772. End If
  773. cmd :+ " " + CQuote(ver)
  774. cmd :+ " " + CQuote(app + ".nacp")
  775. Sys(cmd)
  776. End Function
  777. Function BuildNxNro()
  778. If Not opt_quiet Print "Building:" + StripDir(StripExt(opt_outfile)) + ".nro"
  779. Local elf2nro:String = NxToolsDir() + "/elf2nro"
  780. ?win32
  781. elf2nro :+ ".exe"
  782. ?
  783. If Not FileType(elf2nro) Then
  784. Throw "elf2nro tool not present at " + elf2nro
  785. End If
  786. ' get icon
  787. Local icon:String
  788. ' app.jpg
  789. ' TODO
  790. ' icon.jpg
  791. ' TODO
  792. ' default icon
  793. If Not icon Then
  794. icon = processor.Option("nx.devkitpro", "") + "/libnx/default_icon.jpg"
  795. If Not FileType(icon) Then
  796. Throw "Default icon not found at " + icon
  797. End If
  798. End If
  799. Local app:String = StripExt(opt_outfile)
  800. Local cmd:String = elf2nro + " " + CQuote(app + ".elf")
  801. cmd :+ " " + CQuote(app + ".nro")
  802. cmd :+ " --icon=" + CQuote(icon)
  803. cmd :+ " --nacp=" + CQuote(app + ".nacp")
  804. Local romfsDir:String = ExtractDir(opt_outfile) + "/romfs"
  805. If FileType(romfsDir) = FILETYPE_DIR Then
  806. cmd :+ " --romfsdir=" + CQuote(romfsDir)
  807. End If
  808. Sys(cmd)
  809. End Function
  810. Function PathFromPackage:String(package:String)
  811. Return package.Replace(".", "/")
  812. End Function
  813. Function MergeFile(dir:String, file:String, settings:TMap)
  814. Local s:String = LoadString(dir + "/" + file)
  815. s = ReplaceEnv(s, settings)
  816. SaveString(s, dir + "/" + file)
  817. End Function
  818. Function ReplaceEnv:String( str:String, settings:TMap )
  819. Local bits:TStringStack = New TStringStack
  820. Repeat
  821. Local i:Int = str.Find( "${" )
  822. If i=-1 Exit
  823. Local e:Int = str.Find( "}",i+2 )
  824. If e=-1 Exit
  825. If i>=2 And str[i-2..i] = "//" Then
  826. bits.AddLast str[..e+1]
  827. str = str[e+1..]
  828. Continue
  829. EndIf
  830. Local t:String = str[i+2..e]
  831. Local v:String = String(settings.ValueForKey(t))
  832. If Not v Then
  833. v = "${" + t + "}"
  834. End If
  835. bits.AddLast str[..i]
  836. bits.AddLast v
  837. str = str[e+1..]
  838. Forever
  839. If bits.IsEmpty() Then
  840. Return str
  841. End If
  842. bits.AddLast str
  843. Return bits.Join( "" )
  844. End Function
  845. Function ReplaceBlock:String( Text:String,tag:String,repText:String,mark:String="~n//" )
  846. 'find begin tag
  847. Local beginTag:String = mark+"${start."+tag+"}"
  848. Local i:Int = Text.Find( beginTag )
  849. If i=-1 Throw "Error updating target project - can't find block begin tag '"+tag+"'."
  850. i :+ beginTag.Length
  851. While i < Text.Length And Text[i-1]<>10
  852. i :+ 1
  853. Wend
  854. 'find end tag
  855. Local endTag:String = mark+"${end."+tag+"}"
  856. Local i2:Int = Text.Find( endTag,i-1 )
  857. If i2=-1 Throw "Error updating target project - can't find block end tag '"+tag+"'."
  858. If Not repText Or repText[repText.Length-1]=10 Then
  859. i2 :+ 1
  860. End If
  861. Return Text[..i]+repText+Text[i2..]
  862. End Function
  863. Function SplitPaths:String[](paths:String)
  864. Local split:String[] = New String[0]
  865. Local inQuote:Int
  866. Local token:String
  867. For Local i:Int = 0 Until paths.length
  868. Local char:Int = paths[i]
  869. If char = Asc("~q") Then
  870. inQuote = Not inQuote
  871. Else If char = Asc(" ") And Not inQuote Then
  872. token = token.Trim()
  873. If token Then
  874. split :+ [token]
  875. End If
  876. token = Null
  877. Else
  878. token :+ Chr(char)
  879. End If
  880. Next
  881. token = token.Trim()
  882. If token Then
  883. split :+ [token]
  884. End If
  885. Return split
  886. End Function
  887. Function PackageIOSApp( path$, lnk_files:TList, opts$ )
  888. Local templatePath:String = BlitzMaxPath() + "/resources/ios/template"
  889. If Not FileType(templatePath) Then
  890. Throw "iOS template dir is missing. Expecting it at '" + templatePath + "'"
  891. End If
  892. Local appId:String = StripDir(StripExt(opt_outfile))
  893. Local appPath:String = ExtractDir(opt_outfile)
  894. Local appProjectDir:String = appPath + "/" + appId + ".xcodeproj"
  895. If opt_all Then
  896. DeleteDir appProjectDir, True
  897. End If
  898. If Not FileType(appProjectDir) Then
  899. CopyDir templatePath + "/project.xcodeproj", appProjectDir
  900. End If
  901. Local projectPath:String = appProjectDir + "/project.pbxproj"
  902. Local uuid:String = "5CABB1EFACE"
  903. Local fileMap:TFileMap = New TFileMap
  904. For Local f:String = EachIn lnk_files
  905. Local kind:Int
  906. Select ExtractExt(f)
  907. Case "a"
  908. kind = TFileID.TYPE_ARC
  909. Case "o"
  910. kind = TFileID.TYPE_OBJ
  911. Case "dylib"
  912. kind = TFileID.TYPE_DYL
  913. Default
  914. If f.StartsWith("-l") Then
  915. kind = TFileID.TYPE_DYL
  916. End If
  917. If f.StartsWith("-framework") Then
  918. kind = TFileID.TYPE_FRM
  919. End If
  920. End Select
  921. fileMap.FileId(f, uuid, TFileMap.BUILD, kind)
  922. Next
  923. ' add project-specific resource paths?
  924. Local paths:String[] = SplitPaths(String(globals.GetRawVar("resource_path")))
  925. If paths Then
  926. For Local f:String = EachIn paths
  927. fileMap.FileId(f, uuid, TFileMap.BUILD, TFileID.TYPE_DIR)
  928. Next
  929. End If
  930. Local project:String = LoadString(projectPath)
  931. ' clean project
  932. project = iOSProjectClean(project, uuid)
  933. project = iOSProjectAppendFiles(project, uuid, fileMap)
  934. project = project.Replace("${PROJECT}", appId)
  935. project = project.Replace("${PROJECT_STRIPPED}", iOSFixAppId(appId))
  936. project = project.Replace("${COMPANY_IDENTIFIER}", processor.option("company_identifier", "com.mycompany"))
  937. project = project.Replace("${TEAM_ID}", processor.option("developer_team_id", "developer_team_id"))
  938. SaveString(project, projectPath)
  939. iOSCopyDefaultFiles(templatePath, appPath)
  940. End Function
  941. Function iOSFixAppId:String(id:String)
  942. id = id.Replace(" ", "") ' no spaces
  943. id = id.Replace("_", "") ' no underscores
  944. Return id
  945. End Function
  946. Function iOSCopyDefaultFiles(templatePath:String, appPath:String)
  947. Local iconSrc:String = templatePath + "/Icon.png"
  948. Local iconDest:String = appPath + "/Icon.png"
  949. Local defaultSrc:String = templatePath + "/Default.png"
  950. Local defaultDest:String = appPath + "/Default.png"
  951. Local default2Src:String = templatePath + "/[email protected]"
  952. Local default2Dest:String = appPath + "/[email protected]"
  953. Local plistSrc:String = templatePath + "/Info.plist"
  954. Local plistDest:String = appPath + "/Info.plist"
  955. If opt_all Or Not FileType(iconDest) Then
  956. CopyFile iconSrc, iconDest
  957. End If
  958. If opt_all Or Not FileType(defaultDest) Then
  959. CopyFile defaultSrc, defaultDest
  960. End If
  961. If opt_all Or Not FileType(default2Dest) Then
  962. CopyFile default2Src, default2Dest
  963. End If
  964. If opt_all Or Not FileType(plistDest) Then
  965. CopyFile plistSrc, plistDest
  966. End If
  967. End Function
  968. Function iOSProjectClean:String(Text:String, uuid:String)
  969. Local stack:TStringStack = New TStringStack
  970. For Local line:String = EachIn Text.Split("~n")
  971. If Not line.Trim().StartsWith(uuid) Then
  972. stack.AddLast(line)
  973. End If
  974. Next
  975. Return stack.Join("~n")
  976. End Function
  977. Function iOSProjectAppendFiles:String(Text:String, uuid:String, fileMap:TFileMap)
  978. Local offset:Int = -1
  979. offset = FindEol(Text, "/* Begin PBXBuildFile section */")
  980. If offset = -1 Then
  981. Return ""
  982. End If
  983. Text = Text[..offset] + iOSProjectBuildFiles(uuid, fileMap) + Text[offset..]
  984. offset = FindEol(Text,"/* Begin PBXFileReference section */")
  985. If offset = -1 Then
  986. Return ""
  987. End If
  988. Text = Text[..offset] + iOSProjectFileRefs(uuid, fileMap) + Text[offset..]
  989. offset = FindEol(Text,"/* Begin PBXFrameworksBuildPhase section */")
  990. If offset <> -1 Then
  991. offset = FindEol(Text,"/* Frameworks */ = {",offset)
  992. End If
  993. If offset <> -1 Then
  994. offset = FindEol(Text,"files = (",offset)
  995. End If
  996. If offset = -1 Then
  997. Return ""
  998. End If
  999. Text = Text[..offset] + iOSProjectFrameworksBuildPhase(uuid, fileMap) + Text[offset..]
  1000. offset = FindEol(Text,"/* Begin PBXResourcesBuildPhase section */")
  1001. If offset <> -1 Then
  1002. offset = FindEol(Text,"/* Resources */ = {",offset)
  1003. End If
  1004. If offset <> -1 Then
  1005. offset = FindEol(Text,"files = (",offset)
  1006. End If
  1007. If offset = -1 Then
  1008. Return ""
  1009. End If
  1010. Text = Text[..offset] + iOSProjectResourcesBuildPhase(uuid, fileMap) + Text[offset..]
  1011. offset = FindEol(Text,"/* Begin PBXGroup section */")
  1012. If offset <> -1 Then
  1013. offset = FindEol(Text,"/* Resources */ = {",offset)
  1014. End If
  1015. If offset <> -1 Then
  1016. offset = FindEol(Text,"children = (",offset)
  1017. End If
  1018. If offset = -1 Then
  1019. Return ""
  1020. End If
  1021. Text = Text[..offset] + iOSProjectResourcesGroup(uuid, fileMap) + Text[offset..]
  1022. offset = FindEol(Text,"/* Begin PBXGroup section */")
  1023. If offset <> -1 Then
  1024. offset = FindEol(Text,"/* Frameworks */ = {",offset)
  1025. End If
  1026. If offset <> -1 Then
  1027. offset = FindEol(Text,"children = (",offset)
  1028. End If
  1029. If offset = -1 Then
  1030. Return ""
  1031. End If
  1032. Text = Text[..offset] + iOSProjectFrameworksGroup(uuid, fileMap) + Text[offset..]
  1033. offset = FindEol(Text,"/* Begin PBXGroup section */")
  1034. If offset <> -1 Then
  1035. offset = FindEol(Text,"/* libs */ = {",offset)
  1036. End If
  1037. If offset <> -1 Then
  1038. offset = FindEol(Text,"children = (",offset)
  1039. End If
  1040. If offset = -1 Then
  1041. Return ""
  1042. End If
  1043. Text = Text[..offset] + iOSProjectLibsGroup(uuid, fileMap) + Text[offset..]
  1044. offset = FindEol(Text,"/* Begin PBXGroup section */")
  1045. If offset <> -1 Then
  1046. offset = FindEol(Text,"/* Objects */ = {",offset)
  1047. End If
  1048. If offset <> -1 Then
  1049. offset = FindEol(Text,"children = (",offset)
  1050. End If
  1051. If offset = -1 Then
  1052. Return ""
  1053. End If
  1054. Text = Text[..offset] + iOSProjectObjectsGroup(uuid, fileMap) + Text[offset..]
  1055. offset = FindEol(Text,"/* Begin XCBuildConfiguration section */")
  1056. If offset <> -1 Then
  1057. offset = FindEol(Text,"/* Debug */ = {",offset)
  1058. End If
  1059. If offset <> -1 Then
  1060. offset = FindEol(Text,"LIBRARY_SEARCH_PATHS = (",offset)
  1061. End If
  1062. If offset = -1 Then
  1063. Return ""
  1064. End If
  1065. Text = Text[..offset] + iOSProjectLibSearchPaths(uuid, fileMap) + Text[offset..]
  1066. offset = FindEol(Text,"/* Begin XCBuildConfiguration section */")
  1067. If offset <> -1 Then
  1068. offset = FindEol(Text,"/* Release */ = {",offset)
  1069. End If
  1070. If offset <> -1 Then
  1071. offset = FindEol(Text,"LIBRARY_SEARCH_PATHS = (",offset)
  1072. End If
  1073. If offset = -1 Then
  1074. Return ""
  1075. End If
  1076. Text = Text[..offset] + iOSProjectLibSearchPaths(uuid, fileMap) + Text[offset..]
  1077. Return Text
  1078. End Function
  1079. Function iOSProjectBuildFiles:String(uuid:String, fileMap:TFileMap)
  1080. Local stack:TStringStack = New TStringStack
  1081. For Local f:TFileId = EachIn fileMap.buildFiles
  1082. Local path:String = f.path
  1083. Local id:String = f.id
  1084. Local fileRef:String = fileMap.FileId(path, uuid, TFileMap.REF, f.kind)
  1085. Local dir:String = ExtractDir(path)
  1086. Local name:String = StripDir(path)
  1087. If path.StartsWith("-framework") Then
  1088. name = path[11..]
  1089. End If
  1090. Select f.kind
  1091. Case TFileId.TYPE_ARC, TFileId.TYPE_OBJ, TFileId.TYPE_DYL
  1092. stack.AddLast "~t~t" + id + " /* " + name + " */ = {isa = PBXBuildFile; fileRef = " + fileRef + "; };"
  1093. Case TFileId.TYPE_DIR
  1094. stack.AddLast "~t~t" + id + " /* " + name + " in Resources */ = {isa = PBXBuildFile; fileRef = " + fileRef + "; };"
  1095. Case TFileId.TYPE_LIB, TFileId.TYPE_FRM
  1096. stack.AddLast "~t~t" + id + " /* " + name + " in Frameworks */ = {isa = PBXBuildFile; fileRef = " + fileRef + "; };"
  1097. End Select
  1098. Next
  1099. If stack.Count() Then
  1100. stack.AddLast ""
  1101. End If
  1102. Return stack.Join("~n")
  1103. End Function
  1104. Function iOSProjectFileRefs:String(uuid:String, fileMap:TFileMap)
  1105. Local stack:TStringStack = New TStringStack
  1106. For Local path:String = EachIn fileMap.refFiles.Keys()
  1107. Local id:String = String(fileMap.refFiles.ValueForKey(path))
  1108. Local dir:String = ExtractDir(path)
  1109. Local name:String = StripDir(path)
  1110. Local fid:TFileId = fileMap.GetBuildFileIdForPath(path)
  1111. Select fid.kind
  1112. Case TFileId.TYPE_ARC
  1113. stack.AddLast "~t~t" + id + " /* " + name + " */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = " + name + "; path = ~q" + path + "~q; sourceTree = ~q<absolute>~q; };"
  1114. Case TFileId.TYPE_OBJ
  1115. stack.AddLast "~t~t" + id + " /* " + name + " */ = {isa = PBXFileReference; lastKnownFileType = ~qcompiled.mach-o.objfile~q; name = " + name + "; path = ~q" + path + "~q; sourceTree = ~q<absolute>~q; };"
  1116. Case TFileId.TYPE_DYL
  1117. stack.AddLast "~t~t" + id + " /* " + name + " */ = {isa = PBXFileReference; lastKnownFileType = ~qcompiled.mach-o.dylib~q; name = " + name + "; path = ~q" + path + "~q; sourceTree = ~q<absolute>~q; };"
  1118. Case TFileId.TYPE_DIR
  1119. stack.AddLast "~t~t" + id + " = {isa = PBXFileReference; lastKnownFileType = folder; path = ~q" + path + "~q; sourceTree = SOURCE_ROOT; };"
  1120. Case TFileId.TYPE_LIB
  1121. name = "lib" + path[2..] + ".a"
  1122. Local found:Int = False
  1123. ' path should be provided as a -L...
  1124. For Local p:String = EachIn fileMap.refFiles.Keys()
  1125. If p.StartsWith("-L") Then
  1126. Local libPath:String = p[2..].Replace("~q", "") + "/" + name
  1127. If FileType(libPath) Then
  1128. found = True
  1129. stack.AddLast "~t~t" + id + " /* " + name + " */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = " + name + "; path = ~q" + libPath + "~q; sourceTree = ~q<absolute>~q; };"
  1130. Exit
  1131. End If
  1132. End If
  1133. Next
  1134. If Not found Then
  1135. Print "WARNING : could not find file for library import '" + path + "'. Maybe LD_OPTS: -L... was not defined?"
  1136. End If
  1137. Case TFileId.TYPE_FRM
  1138. name = path[11..]
  1139. stack.AddLast "~t~t" + id + " /* " + name + " */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = " + name + ".framework; path = System/Library/Frameworks/" + name + ".framework; sourceTree = SDKROOT; };"
  1140. End Select
  1141. Next
  1142. If stack.Count() Then
  1143. stack.AddLast ""
  1144. End If
  1145. Return stack.Join("~n")
  1146. End Function
  1147. Function iOSProjectFrameworksBuildPhase:String(uuid:String, fileMap:TFileMap)
  1148. Local stack:TStringStack = New TStringStack
  1149. For Local f:TFileId = EachIn fileMap.buildFiles
  1150. Local path:String = f.path
  1151. Local id:String = f.id
  1152. Local dir:String = ExtractDir(path)
  1153. Local name:String = StripDir(path)
  1154. Select ExtractExt(name)
  1155. Case "a", "o"
  1156. stack.AddLast "~t~t~t~t" + id + " /* " + name + " */"
  1157. End Select
  1158. If path.StartsWith("-l") Then
  1159. name = "lib" + path[2..] + ".a"
  1160. stack.AddLast "~t~t~t~t" + id + " /* " + name + " */"
  1161. End If
  1162. If path.StartsWith("-framework") Then
  1163. name = path[11..]
  1164. stack.AddLast "~t~t~t~t" + id + " /* " + name + ".framework in Frameworks */"
  1165. End If
  1166. Next
  1167. If stack.Count() Then
  1168. stack.AddLast ""
  1169. End If
  1170. Return stack.Join(",~n")
  1171. End Function
  1172. Function iOSProjectResourcesBuildPhase:String(uuid:String, fileMap:TFileMap)
  1173. Local stack:TStringStack = New TStringStack
  1174. For Local f:TFileId = EachIn fileMap.buildFiles
  1175. Local path:String = f.path
  1176. Local id:String = f.id
  1177. If f.kind = TFileId.TYPE_DIR Then
  1178. stack.AddLast "~t~t~t~t" + id + " /* " + path + " in Resources */"
  1179. End If
  1180. Next
  1181. If stack.Count() Then
  1182. stack.AddLast ""
  1183. End If
  1184. Return stack.Join(",~n")
  1185. End Function
  1186. Function iOSProjectResourcesGroup:String(uuid:String, fileMap:TFileMap)
  1187. Local stack:TStringStack = New TStringStack
  1188. For Local path:String = EachIn fileMap.refFiles.Keys()
  1189. Local id:String = String(fileMap.refFiles.ValueForKey(path))
  1190. Local fid:TFileId = fileMap.GetBuildFileIdForPath(path)
  1191. If fid.kind = TFileId.TYPE_DIR Then
  1192. stack.AddLast "~t~t~t~t" + id + " /* " + path + " */"
  1193. End If
  1194. Next
  1195. If stack.Count() Then
  1196. stack.AddLast ""
  1197. End If
  1198. Return stack.Join(",~n")
  1199. End Function
  1200. Function iOSProjectFrameworksGroup:String(uuid:String, fileMap:TFileMap)
  1201. Local stack:TStringStack = New TStringStack
  1202. For Local path:String = EachIn fileMap.refFiles.Keys()
  1203. Local id:String = String(fileMap.refFiles.ValueForKey(path))
  1204. If path.StartsWith("-framework") Then
  1205. Local name:String = path[11..]
  1206. stack.AddLast "~t~t~t~t" + id + " /* " + name + ".framework in Frameworks */"
  1207. End If
  1208. Next
  1209. If stack.Count() Then
  1210. stack.AddLast ""
  1211. End If
  1212. Return stack.Join(",~n")
  1213. End Function
  1214. Function iOSProjectLibsGroup:String(uuid:String, fileMap:TFileMap)
  1215. Local stack:TStringStack = New TStringStack
  1216. For Local path:String = EachIn fileMap.refFiles.Keys()
  1217. Local id:String = String(fileMap.refFiles.ValueForKey(path))
  1218. Local dir:String = ExtractDir(path)
  1219. Local name:String = StripDir(path)
  1220. Select ExtractExt(name)
  1221. Case "a"
  1222. stack.AddLast "~t~t~t~t" + id + " /* " + name + " */"
  1223. End Select
  1224. If path.StartsWith("-l") Then
  1225. name = "lib" + path[2..] + ".a"
  1226. stack.AddLast "~t~t~t~t" + id + " /* " + name + " */"
  1227. End If
  1228. Next
  1229. If stack.Count() Then
  1230. stack.AddLast ""
  1231. End If
  1232. Return stack.Join(",~n")
  1233. End Function
  1234. Function iOSProjectObjectsGroup:String(uuid:String, fileMap:TFileMap)
  1235. Local stack:TStringStack = New TStringStack
  1236. For Local path:String = EachIn fileMap.refFiles.Keys()
  1237. Local id:String = String(fileMap.refFiles.ValueForKey(path))
  1238. Local dir:String = ExtractDir(path)
  1239. Local name:String = StripDir(path)
  1240. Select ExtractExt(name)
  1241. Case "o"
  1242. stack.AddLast "~t~t~t~t" + id + " /* " + name + " */"
  1243. End Select
  1244. Next
  1245. If stack.Count() Then
  1246. stack.AddLast ""
  1247. End If
  1248. Return stack.Join(",~n")
  1249. End Function
  1250. Function iOSProjectLibSearchPaths:String(uuid:String, fileMap:TFileMap)
  1251. Local stack:TStringStack = New TStringStack
  1252. For Local f:TFileId = EachIn fileMap.buildFiles
  1253. Local path:String = f.path
  1254. Local dir:String = ExtractDir(path)
  1255. Local name:String = StripDir(path)
  1256. Select ExtractExt(name)
  1257. Case "a"
  1258. stack.AddLast "~t~t~t~t~q" + EscapeSpaces(dir) + "~q"
  1259. End Select
  1260. If path.StartsWith("-L") Then
  1261. stack.AddLast("~t~t~t~t~q" + EscapeSpaces(path[2..]) + "~q")
  1262. End If
  1263. Next
  1264. If stack.Count() Then
  1265. stack.AddLast ""
  1266. End If
  1267. Return stack.Join(",~n")
  1268. End Function
  1269. Function MakeUpx()
  1270. If processor.Platform() = "emscripten" Or processor.Platform() = "nx" Or processor.Platform() = "ios" Then
  1271. Return
  1272. End If
  1273. Local upx:String = BlitzMaxPath() + "/bin/upx"
  1274. ?win32
  1275. upx :+ ".exe"
  1276. ?
  1277. If Not opt_quiet Then
  1278. Print "Packing:" + StripDir(opt_outfile)
  1279. End If
  1280. If FileType(upx) <> FILETYPE_FILE Then
  1281. If Not opt_quiet Then
  1282. Print "WARNING: Missing UPX : " + upx
  1283. End If
  1284. Return
  1285. End If
  1286. Local cmd:String = upx + " -9 "
  1287. If Not opt_verbose Then
  1288. cmd :+ "-qqq "
  1289. Else
  1290. cmd :+ "-qq "
  1291. End If
  1292. cmd :+ CQuote(opt_outfile)
  1293. Sys(cmd)
  1294. End Function
  1295. Function FindEOL:Int(Text:String, substr:String, start:Int = 0)
  1296. Local i:Int = Text.Find(substr, start)
  1297. If i = -1 Then
  1298. Return -1
  1299. End If
  1300. i :+ substr.Length
  1301. Local eol:Int = Text.Find("~n", i) + 1
  1302. If eol = 0 Then
  1303. Return Text.Length
  1304. End If
  1305. Return eol
  1306. End Function
  1307. Function ConcatString:String(a1:String, a2:String, a3:String, a4:String, a5:String = Null, a6:String = Null, a7:String = Null)
  1308. ?bmxng
  1309. Local s:TStringBuffer = New TStringBuffer(128)
  1310. ?Not bmxng
  1311. TStringBuffer.initialCapacity = 128
  1312. Local s:TStringBuffer = New TStringBuffer
  1313. ?
  1314. s.Append(a1).Append(a2).Append(a3).Append(a4)
  1315. If a5 s.Append(a5)
  1316. If a6 s.Append(a6)
  1317. If a7 s.Append(a7)
  1318. Return s.ToString()
  1319. End Function
  1320. Type TStringStack Extends TList
  1321. Method Join:String(s:String)
  1322. Local arr:String[] = New String[count()]
  1323. Local index:Int
  1324. For Local t:String = EachIn Self
  1325. arr[index] = t
  1326. index :+ 1
  1327. Next
  1328. Return s.Join(arr)
  1329. End Method
  1330. End Type
  1331. Type TFileId
  1332. Const TYPE_OBJ:Int = 1
  1333. Const TYPE_ARC:Int = 2
  1334. Const TYPE_DYL:Int = 3
  1335. Const TYPE_LIB:Int = 4
  1336. Const TYPE_FRM:Int = 5
  1337. Const TYPE_DIR:Int = 6
  1338. Field path:String
  1339. Field id:String
  1340. Field kind:Int
  1341. End Type
  1342. Type TFileMap
  1343. Const BUILD:Int = 0
  1344. Const REF:Int = 1
  1345. Field lastId:Int = 0
  1346. Field refFiles:TMap = New TMap
  1347. Field buildFiles:TList = New TList
  1348. Method FileId:String(path:String, uuid:String, kind:Int = BUILD, fileKind:Int = 0)
  1349. Local id:String
  1350. If kind = BUILD Then
  1351. Local f:TFileId = GetBuildFileIdForPath(path)
  1352. If f Then
  1353. id = f.id
  1354. End If
  1355. Else
  1356. id = String(refFiles.ValueForKey(path))
  1357. End If
  1358. If id Then
  1359. Return id
  1360. End If
  1361. Local file:String = "0000000000000" + lastId
  1362. id = uuid + file[file.length - 13..]
  1363. If kind = BUILD Then
  1364. Local f:TFileId = New TFileId
  1365. f.path = path
  1366. f.id = id
  1367. f.kind = fileKind
  1368. buildFiles.AddLast(f)
  1369. Else
  1370. refFiles.Insert(path, id)
  1371. End If
  1372. lastId :+ 1
  1373. Return id
  1374. End Method
  1375. Method GetBuildFileIdForPath:TFileId(path:String)
  1376. For Local f:TFileId = EachIn buildFiles
  1377. If f.path = path Then
  1378. Return f
  1379. End If
  1380. Next
  1381. End Method
  1382. End Type
  1383. Type TOrderedMap Extends TMap
  1384. Field _keys:TList = New TList
  1385. Method Insert( key:Object,value:Object )
  1386. If Not Contains(key) Then
  1387. _keys.AddLast(key)
  1388. End If
  1389. Super.Insert(key, value)
  1390. End Method
  1391. Method Remove:Int( key:Object )
  1392. _keys.Remove(key)
  1393. Return Super.Remove(key)
  1394. End Method
  1395. Method OrderedKeys:TList()
  1396. Return _keys
  1397. End Method
  1398. End Type
  1399. Type TBootstrapConfig
  1400. Field assets:TBootstrapAsset[]
  1401. Field targets:TBootstrapTarget[]
  1402. Method CopyAssets(dest:String)
  1403. For Local asset:TBootstrapAsset = EachIn assets
  1404. Print "processing " + asset.name
  1405. Local basePath:String
  1406. Select asset.assetType
  1407. Case "m"
  1408. basePath = "mod/" + asset.name.Replace(".",".mod/")+".mod"
  1409. Case "a"
  1410. basePath = "src/" + asset.name
  1411. Default
  1412. Continue
  1413. End Select
  1414. Local maxBase:String = BlitzMaxPath() + "/" + basePath
  1415. If Not FileType(maxBase) Throw "Expected dir missing : " + basePath
  1416. If FileType(maxBase) <> FILETYPE_DIR Throw "Not a dir : " + basePath
  1417. Local destBase:String = dest + "/" + basePath
  1418. If Not CreateDir(destBase, True) Throw "Error creating " + basePath
  1419. For Local part:String = EachIn asset.parts
  1420. If part.StartsWith("*") Then
  1421. ' copy files
  1422. FileCopy(maxBase, destBase, part[1..])
  1423. Else
  1424. ' copy dir
  1425. Local srcDir:String = maxBase + "/" + part
  1426. Local destDir:String = destBase + "/" + part
  1427. DirCopy(srcDir, destDir)
  1428. End If
  1429. Next
  1430. Next
  1431. End Method
  1432. Method DirCopy(src:String, dest:String)
  1433. If Not FileType(src) Throw "Source dir not found : " + src
  1434. If Not CreateDir(dest, True) Throw "Unable to create " + dest
  1435. If Not CreateDir(dest + "/.bmx") Throw "Unable to create " + dest + "/.bmx"
  1436. For Local file:String = EachIn LoadDir( src )
  1437. If file.EndsWith(".bmx") Then
  1438. Continue
  1439. End If
  1440. Local filePath:String = src + "/" + file
  1441. Select FileType( filePath )
  1442. Case FILETYPE_DIR
  1443. DirCopy( filePath, dest + "/" + file )
  1444. Case FILETYPE_FILE
  1445. CopyFile( filePath, dest + "/" + file )
  1446. End Select
  1447. Next
  1448. If LoadDir(dest + "/.bmx").Length = 0 Then
  1449. CreateFile(dest + "/.bmx/.gitkeep")
  1450. End If
  1451. End Method
  1452. Method FileCopy(src:String, dest:String, suffix:String)
  1453. If Not CreateDir(dest + "/.bmx") Throw "Unable to create " + dest + "/.bmx"
  1454. For Local file:String = EachIn LoadDir( src )
  1455. If Not file.EndsWith(suffix) Then
  1456. Continue
  1457. End If
  1458. Local filePath:String = src + "/" + file
  1459. If FileType(filePath) = FILETYPE_FILE Then
  1460. CopyFile(filePath, dest + "/" + file)
  1461. End If
  1462. Next
  1463. End Method
  1464. Method CopySources(dest:String, sources:TList)
  1465. Local bmxRoot:String = "$BMX_ROOT"
  1466. If processor.Platform() = "win32" Then
  1467. bmxRoot = "%BMX_ROOT%"
  1468. End If
  1469. For Local path:String = EachIn sources
  1470. Local srcPath:String = path.Replace(bmxRoot, BlitzMaxPath())
  1471. Local destPath:String = path.Replace(bmxRoot, dest)
  1472. CreateDir(ExtractDir(destPath), True)
  1473. If Not FileType(srcPath) Throw "Not found : " + srcPath
  1474. CopyFile(srcPath, destPath)
  1475. Next
  1476. End Method
  1477. Method CopyScripts(dest:String, app:TBootstrapAsset)
  1478. dest = dest + "/src/" + app.name
  1479. Local src:String = BlitzMaxPath() + "/src/" + app.name
  1480. Local ld:String = "/ld." + processor.AppDet() + ".txt"
  1481. Local build:String = "/" + processor.AppDet() + ".build"
  1482. Local ldSrcPath:String = src + ld
  1483. Local buildSrcPath:String = src + build
  1484. If Not FileType(ldSrcPath) Throw "ld script missing : " + ldSrcPath
  1485. If Not FileType(buildSrcPath) Throw "build script missing : " + buildSrcPath
  1486. CopyFile(ldSrcPath, dest + ld)
  1487. CopyFile(buildSrcPath, dest + build)
  1488. End Method
  1489. End Type
  1490. Type TBootstrapAsset
  1491. Field assetType:String
  1492. Field name:String
  1493. Field parts:String[]
  1494. End Type
  1495. Type TBootstrapTarget
  1496. Field platform:String
  1497. Field arch:String
  1498. End Type
  1499. Function LoadBootstrapConfig:TBootstrapConfig()
  1500. Const CONFIG:String = "bin/bootstrap.cfg"
  1501. Local file:String = BlitzMaxPath() + "/" + CONFIG
  1502. If Not FileType(file) Then
  1503. Throw CONFIG + " not found"
  1504. End If
  1505. Local cfg:String = LoadText(file).Trim()
  1506. If cfg Then
  1507. Local LINES:String[] = cfg.Split("~n")
  1508. Local assets:String[]
  1509. For Local line:String = EachIn LINES
  1510. line = line.Trim()
  1511. If line And Not line.StartsWith("#") Then
  1512. assets :+ [line]
  1513. End If
  1514. Next
  1515. Local boot:TBootstrapConfig = New TBootstrapConfig
  1516. 'boot.assets = New TBootstrapAsset[assets.length]
  1517. 'Local i:Int
  1518. For Local assetLine:String = EachIn assets
  1519. Local parts:String[] = assetLine.Split("~t")
  1520. If parts And parts.length > 1 Then
  1521. Select parts[0]
  1522. Case "t"
  1523. Local target:TBootstrapTarget = New TBootstrapTarget
  1524. target.platform = parts[1]
  1525. target.arch = parts[2]
  1526. boot.targets :+ [target]
  1527. Default
  1528. Local asset:TBootstrapAsset = New TBootstrapAsset
  1529. asset.assetType = parts[0]
  1530. asset.name = parts[1]
  1531. If parts.length > 2 Then
  1532. asset.parts = parts[2..]
  1533. End If
  1534. boot.assets :+ [asset]
  1535. 'i :+ 1
  1536. End Select
  1537. End If
  1538. Next
  1539. Return boot
  1540. Else
  1541. Throw "Could not load " + CONFIG
  1542. End If
  1543. End Function
  1544. Extern
  1545. Function bmx_setfiletimenow(path:String)
  1546. Function bmx_hash_createState:Byte Ptr()
  1547. Function bmx_hash_reset(state:Byte Ptr)
  1548. Function bmx_hash_update(state:Byte Ptr, data:Byte Ptr, length:Int)
  1549. Function bmx_hash_digest:String(state:Byte Ptr)
  1550. Function bmx_hash_free(state:Byte Ptr)
  1551. End Extern
  1552. Function SetFileTimeNow(path:String)
  1553. bmx_setfiletimenow(path)
  1554. End Function
  1555. Type TFileHash
  1556. Field statePtr:Byte Ptr
  1557. Method Create:TFileHash()
  1558. statePtr = bmx_hash_createState()
  1559. Return Self
  1560. End Method
  1561. Method CalculateHash:String(stream:TStream)
  1562. Const BUFFER_SIZE:Int = 8192
  1563. bmx_hash_reset(statePtr)
  1564. Local data:Byte[BUFFER_SIZE]
  1565. While True
  1566. Local read:Int = stream.Read(data, BUFFER_SIZE)
  1567. bmx_hash_update(statePtr, data, read)
  1568. If read < BUFFER_SIZE Then
  1569. Exit
  1570. End If
  1571. Wend
  1572. Return bmx_hash_digest(statePtr)
  1573. End Method
  1574. Method Free()
  1575. bmx_hash_free(statePtr)
  1576. End Method
  1577. End Type
  1578. Function CalculateFileHash:String(path:String)
  1579. If FileType(path) = FILETYPE_FILE Then
  1580. Local fileHasher:TFileHash = New TFileHash.Create()
  1581. Local stream:TStream = ReadStream(path)
  1582. Local fileHash:String = fileHasher.CalculateHash(stream)
  1583. stream.Close()
  1584. fileHasher.Free()
  1585. Return fileHash
  1586. End If
  1587. Return Null
  1588. End Function