bmk_util.bmx 53 KB

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