make.js 108 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378
  1. // Based on https://github.com/Kode/kmake by RobDangerous
  2. // ██╗ ██╗██████╗
  3. // ██║ ██║██╔══██╗
  4. // ██║ ██║██████╔╝
  5. // ██║ ██║██╔══██╗
  6. // ███████╗██║██████╔╝
  7. // ╚══════╝╚═╝╚═════╝
  8. import * as os from "os";
  9. import * as std from "std";
  10. let path_sep = "/";
  11. let other_path_sep = "\\";
  12. if (os_platform() === "win32") {
  13. path_sep = "\\";
  14. other_path_sep = "/";
  15. }
  16. let binpath = path_resolve(scriptArgs[0]);
  17. let toolsdir = binpath.substring(0, binpath.lastIndexOf(path_sep));
  18. let makedir = path_join(toolsdir, "..", "..");
  19. let __dirname = makedir;
  20. let irondir = path_join(makedir, "..");
  21. function get_binary_data(p) {
  22. return fs_readfile(irondir + "/sources/backends/data/" + p);
  23. }
  24. function get_text_data(p) {
  25. return fs_readfile(irondir + "/sources/backends/data/" + p);
  26. }
  27. function fs_exists(p) {
  28. return os.stat(p)[0] != null;
  29. }
  30. function fs_mkdir(p) {
  31. os.mkdir(p);
  32. }
  33. function array_remove(arr, e) {
  34. let i = arr.indexOf(e);
  35. if (i != -1) {
  36. arr.splice(i, 1);
  37. }
  38. }
  39. function fs_readdir(p) {
  40. let dirs = os.readdir(p)[0];
  41. array_remove(dirs, ".");
  42. array_remove(dirs, "..");
  43. return dirs;
  44. }
  45. function fs_copyfile(from, to) {
  46. let f = std.open(from, "rb");
  47. f.seek(0, std.SEEK_END);
  48. let size = f.tell();
  49. let u8 = new Uint8Array(size);
  50. f.seek(0, std.SEEK_SET);
  51. f.read(u8.buffer, 0, size);
  52. f.close();
  53. f = std.open(to, "wb");
  54. f.write(u8.buffer, 0, size);
  55. f.close();
  56. }
  57. function fs_isdir(p) {
  58. return (os.stat(p)[0].mode & os.S_IFMT) == os.S_IFDIR;
  59. }
  60. function fs_mtime(p) {
  61. return os.stat(p)[0].mtime;
  62. }
  63. function fs_readfile(p) {
  64. return std.loadFile(p);
  65. }
  66. function fs_writefile(p, data) {
  67. let f = std.open(p, "w");
  68. f.puts(data); // utf8
  69. f.close();
  70. }
  71. function parent_dir(dir) {
  72. return dir.substring(0, dir.lastIndexOf(path_sep));
  73. }
  74. function fs_ensuredir(dir) {
  75. if (dir != "" && !fs_exists(dir)) {
  76. fs_ensuredir(parent_dir(dir));
  77. fs_mkdir(dir);
  78. }
  79. }
  80. function fs_copydir(from, to) {
  81. fs_ensuredir(to);
  82. let files = fs_readdir(from);
  83. for (let file of files) {
  84. if (fs_isdir(path_join(from, file))) {
  85. fs_copydir(path_join(from, file), path_join(to, file));
  86. }
  87. else {
  88. fs_copyfile(path_join(from, file), path_join(to, file));
  89. }
  90. }
  91. }
  92. function os_popen(exe, params = [], ops = {}) {
  93. params.unshift(exe);
  94. let res = {stdout : ""};
  95. let cwd;
  96. if (ops.cwd) {
  97. cwd = os_cwd();
  98. os.chdir(ops.cwd);
  99. }
  100. let p = std.popen(params.join(" "), "r");
  101. res.stdout = p.readAsString();
  102. p.close();
  103. if (ops.cwd) {
  104. os.chdir(cwd);
  105. }
  106. return res;
  107. }
  108. function os_exec(exe, params = [], ops = {}) {
  109. params.unshift(exe);
  110. let res = {status : 0};
  111. if (os_platform() === "win32") {
  112. res = amake.os_exec_win(params, ops); // { status, stdout }
  113. }
  114. else {
  115. res.status = os.exec(params, ops);
  116. }
  117. return res;
  118. }
  119. function os_platform() {
  120. return os.platform;
  121. }
  122. function os_cwd() {
  123. return os.getcwd()[0];
  124. }
  125. function os_env(s) {
  126. return std.getenv(s);
  127. }
  128. function os_argv() {
  129. return scriptArgs;
  130. }
  131. function os_cpus_length() {
  132. // return os.cpus().length;
  133. return 8;
  134. }
  135. function os_chmod(p, m) {
  136. if (os_platform() === "win32") {
  137. return;
  138. }
  139. os_exec("chmod", [ m, p ]);
  140. }
  141. function os_exit(c) {
  142. std.exit(c);
  143. }
  144. function crypto_random_uuid() {
  145. let u = Date.now().toString(16) + Math.random().toString(16) + "0".repeat(16);
  146. let guid = [ u.substring(0, 8), u.substring(8, 12), "4000-8" + u.substring(13, 16), u.substring(16, 28) ].join("-");
  147. return guid;
  148. }
  149. // https://github.com/kawanet/sha1-uint8array
  150. var SHA1 = "undefined" != typeof exports ? exports : {};
  151. !function(t) {
  152. var r = [ 1518500249, 1859775393, -1894007588, -899497514 ], i = {sha1 : 1};
  153. SHA1.createHash = function(t) {
  154. if (t && !i[t] && !i[t.toLowerCase()])
  155. throw new Error("Digest method not supported");
  156. return new s
  157. };
  158. var n, s = function() {
  159. function t() {
  160. this.A = 1732584193, this.B = -271733879, this.C = -1732584194, this.D = 271733878, this.E = -1009589776, this.t = 0, this.i = 0,
  161. (!n || e >= 8e3) && (n = new ArrayBuffer(8e3), e = 0), this.h = new Uint8Array(n, e, 80), this.o = new Int32Array(n, e, 20), e += 80
  162. }
  163. return t.prototype.update = function(t) {
  164. if ("string" == typeof t)
  165. return this.u(t);
  166. if (null == t)
  167. throw new TypeError("Invalid type: " + typeof t);
  168. var r = t.byteOffset, i = t.byteLength, n = i / 64 | 0, s = 0;
  169. if (n && !(3 & r) && !(this.t % 64)) {
  170. for (var h = new Int32Array(t.buffer, r, 16 * n); n--;)
  171. this.v(h, s >> 2), s += 64;
  172. this.t += s
  173. }
  174. if (1 !== t.BYTES_PER_ELEMENT && t.buffer) {
  175. var e = new Uint8Array(t.buffer, r + s, i - s);
  176. return this.p(e)
  177. }
  178. return s === i ? this : this.p(t, s)
  179. }, t.prototype.p = function(t, r) {
  180. var i = this.h, n = this.o, s = t.length;
  181. for (r |= 0; r < s;) {
  182. for (var h = this.t % 64, e = h; r < s && e < 64;)
  183. i[e++] = t[r++];
  184. e >= 64 && this.v(n), this.t += e - h
  185. }
  186. return this
  187. }, t.prototype.u = function(t) {
  188. for (var r = this.h, i = this.o, n = t.length, s = this.i, h = 0; h < n;) {
  189. for (var e = this.t % 64, f = e; h < n && f < 64;) {
  190. var o = 0 | t.charCodeAt(h++);
  191. o < 128 ? r[f++] = o
  192. : o < 2048 ? (r[f++] = 192 | o >>> 6, r[f++] = 128 | 63 & o)
  193. : o < 55296 || o > 57343 ? (r[f++] = 224 | o >>> 12, r[f++] = 128 | o >>> 6 & 63, r[f++] = 128 | 63 & o)
  194. : s ? (o = ((1023 & s) << 10) + (1023 & o) + 65536, r[f++] = 240 | o >>> 18, r[f++] = 128 | o >>> 12 & 63, r[f++] = 128 | o >>> 6 & 63,
  195. r[f++] = 128 | 63 & o, s = 0)
  196. : s = o
  197. }
  198. f >= 64 && (this.v(i), i[0] = i[16]), this.t += f - e
  199. }
  200. return this.i = s, this
  201. }, t.prototype.v = function(t, i) {
  202. var n = this, s = n.A, e = n.B, f = n.C, w = n.D, y = n.E, A = 0;
  203. for (i |= 0; A < 16;)
  204. h[A++] = o(t[i++]);
  205. for (A = 16; A < 80; A++)
  206. h[A] = u(h[A - 3] ^ h[A - 8] ^ h[A - 14] ^ h[A - 16]);
  207. for (A = 0; A < 80; A++) {
  208. var p = A / 20 | 0, d = a(s) + v(p, e, f, w) + y + h[A] + r[p] | 0;
  209. y = w, w = f, f = c(e), e = s, s = d
  210. }
  211. this.A = s + this.A | 0, this.B = e + this.B | 0, this.C = f + this.C | 0, this.D = w + this.D | 0, this.E = y + this.E | 0
  212. }, t.prototype.digest = function(t) {
  213. var r = this.h, i = this.o, n = this.t % 64 | 0;
  214. for (r[n++] = 128; 3 & n;)
  215. r[n++] = 0;
  216. if ((n >>= 2) > 14) {
  217. for (; n < 16;)
  218. i[n++] = 0;
  219. n = 0, this.v(i)
  220. }
  221. for (; n < 16;)
  222. i[n++] = 0;
  223. var s = 8 * this.t, h = (4294967295 & s) >>> 0, e = (s - h) / 4294967296;
  224. return e && (i[14] = o(e)), h && (i[15] = o(h)), this.v(i), "hex" === t ? this.I() : this.U()
  225. }, t.prototype.I = function() {
  226. var t = this, r = t.A, i = t.B, n = t.C, s = t.D, h = t.E;
  227. return f(r) + f(i) + f(n) + f(s) + f(h)
  228. }, t.prototype.U = function() {
  229. var t = this, r = t.A, i = t.B, n = t.C, s = t.D, h = t.E, e = t.h, f = t.o;
  230. return f[0] = o(r), f[1] = o(i), f[2] = o(n), f[3] = o(s), f[4] = o(h), e.slice(0, 20)
  231. }, t
  232. }(), h = new Int32Array(80), e = 0, f = function(t) {
  233. return (t + 4294967296).toString(16).substr(-8)
  234. }, o = 254 === new Uint8Array(new Uint16Array([ 65279 ]).buffer)[0] ? function(t) {
  235. return t
  236. } : function(t) {
  237. return t << 24 & 4278190080 | t << 8 & 16711680 | t >> 8 & 65280 | t >> 24 & 255
  238. }, u = function(t) {
  239. return t << 1 | t >>> 31
  240. }, a = function(t) {
  241. return t << 5 | t >>> 27
  242. }, c = function(t) {
  243. return t << 30 | t >>> 2
  244. };
  245. function v(t, r, i, n) {
  246. return 0 === t ? r & i | ~r & n : 2 === t ? r & i | r & n | i & n : r ^ i ^ n
  247. }
  248. }();
  249. function uuidv5(path, namespace) {
  250. let hash = SHA1.createHash("sha1");
  251. hash.update(namespace);
  252. hash.update(path);
  253. let value = hash.digest("hex");
  254. return value.substring(0, 8) + "-" + value.substring(8, 12) + "-" + value.substring(12, 16) + "-" + value.substring(16, 20) + "-" + value.substring(20, 32);
  255. }
  256. function path_join() {
  257. let args = Array.from(arguments);
  258. return path_normalize(args.join(path_sep));
  259. }
  260. function path_isabs(p) {
  261. return p[0] == "/" || p[1] == ":" || (p[0] == "\\" && p[1] == "\\");
  262. }
  263. function _path_resolve(base, relative) {
  264. let stack = base.split("/");
  265. let parts = relative.split("/");
  266. for (let i = 0; i < parts.length; i++) {
  267. if (parts[i] == ".") {
  268. continue;
  269. }
  270. if (parts[i] == "..") {
  271. stack.pop();
  272. }
  273. else {
  274. stack.push(parts[i]);
  275. }
  276. }
  277. return stack.join("/");
  278. }
  279. function path_resolve() {
  280. let args = Array.from(arguments);
  281. if (!path_isabs(args[0])) {
  282. args.unshift(os_cwd());
  283. }
  284. let i = args.length - 1;
  285. let p = args[i];
  286. p = path_normalize(p);
  287. while (!path_isabs(p)) {
  288. i--;
  289. p = _path_resolve(args[i], p);
  290. p = path_normalize(p);
  291. }
  292. return p;
  293. }
  294. function path_relative(from, to) {
  295. let a = from.split(path_sep);
  296. let b = to.split(path_sep);
  297. while (a[0] == b[0]) {
  298. a.shift();
  299. b.shift();
  300. if (a.length == 0 || b.length == 0) {
  301. break;
  302. }
  303. }
  304. let base = "";
  305. for (let i = 0; i < a.length; ++i) {
  306. base += ".." + path_sep;
  307. }
  308. base += b.join(path_sep);
  309. return base;
  310. }
  311. function path_normalize(p) {
  312. p = p.replaceAll(other_path_sep, path_sep);
  313. while (p.indexOf(path_sep + path_sep) != -1) {
  314. p = p.replaceAll(path_sep + path_sep, path_sep);
  315. }
  316. if (p.endsWith(path_sep)) {
  317. p = p.substring(0, p.length - 1);
  318. }
  319. let ar = p.split(path_sep);
  320. let i = 0;
  321. while (i < ar.length) {
  322. if (i > 0 && ar[i] == ".." && ar[i - 1] != "..") {
  323. ar.splice(i - 1, 2);
  324. i--;
  325. }
  326. else {
  327. i++;
  328. }
  329. }
  330. return ar.join(path_sep);
  331. }
  332. function exe_ext() {
  333. return os_platform() == "win32" ? ".exe" : "";
  334. }
  335. function path_extname(p) {
  336. return p.substring(p.lastIndexOf("."), p.length);
  337. }
  338. function path_basename(p) {
  339. return p.substring(p.lastIndexOf(path_sep) + 1, p.length);
  340. }
  341. function path_basename_noext(p) {
  342. return p.substring(p.lastIndexOf(path_sep) + 1, p.lastIndexOf("."));
  343. }
  344. function path_dirname(p) {
  345. return p.substring(0, p.lastIndexOf(path_sep));
  346. }
  347. function sys_dir() {
  348. if (os_platform() === "linux") {
  349. // if (os_arch() === "arm64") return "linux_arm64";
  350. return "linux_x64";
  351. }
  352. else if (os_platform() === "win32") {
  353. return "windows_x64";
  354. }
  355. else {
  356. return "macos";
  357. }
  358. }
  359. function matches(text, pattern) {
  360. let regexstring = pattern.replace(/\./g, "\\.").replace(/\*\*/g, ".?").replace(/\*/g, "[^/]*").replace(/\?/g, "*");
  361. let regex = new RegExp("^" + regexstring + "$", "g");
  362. return regex.test(text);
  363. }
  364. function stringify(p) {
  365. return p.replaceAll("\\", "/");
  366. }
  367. // ███████╗██╗ ██╗██████╗ ██████╗ ██████╗ ████████╗███████╗██████╗ ███████╗
  368. // ██╔════╝╚██╗██╔╝██╔══██╗██╔═══██╗██╔══██╗╚══██╔══╝██╔════╝██╔══██╗██╔════╝
  369. // █████╗ ╚███╔╝ ██████╔╝██║ ██║██████╔╝ ██║ █████╗ ██████╔╝███████╗
  370. // ██╔══╝ ██╔██╗ ██╔═══╝ ██║ ██║██╔══██╗ ██║ ██╔══╝ ██╔══██╗╚════██║
  371. // ███████╗██╔╝ ██╗██║ ╚██████╔╝██║ ██║ ██║ ███████╗██║ ██║███████║
  372. // ╚══════╝╚═╝ ╚═╝╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═╝╚══════╝
  373. class Exporter {
  374. constructor() {
  375. this.path = null;
  376. this.outFile = null;
  377. }
  378. write_file(file) {
  379. this.path = file;
  380. this.outFile = "";
  381. }
  382. close_file() {
  383. fs_writefile(this.path, this.outFile);
  384. this.outFile = "";
  385. }
  386. p(line = "", indent = 0) {
  387. let tabs = "";
  388. for (let i = 0; i < indent; ++i) {
  389. tabs += "\t";
  390. }
  391. this.outFile += tabs + line + "\n";
  392. }
  393. nice_path(from, to, filepath) {
  394. return filepath;
  395. // let absolute = path_normalize(filepath);
  396. // if (!path_isabs(absolute)) {
  397. // absolute = path_resolve(from, filepath);
  398. // }
  399. // return path_relative(to, absolute);
  400. }
  401. }
  402. function get_dir_from_string(file, base) {
  403. file = file.replace(/\\/g, '/');
  404. if (file.indexOf("/") >= 0) {
  405. let dir = file.substr(0, file.lastIndexOf("/"));
  406. return path_join(base, path_relative(base, dir)).replace(/\\/g, "/");
  407. }
  408. else {
  409. return base;
  410. }
  411. }
  412. function get_dir(file) {
  413. return get_dir_from_string(file.file, file.projectName);
  414. }
  415. class VisualStudioExporter extends Exporter {
  416. constructor() {
  417. super();
  418. }
  419. get_debug_dir(from, project) {
  420. let debugdir = project.get_debug_dir();
  421. if (path_isabs(debugdir)) {
  422. debugdir = debugdir.replace(/\//g, "\\");
  423. }
  424. else {
  425. debugdir = path_resolve(from, debugdir).replace(/\//g, "\\");
  426. }
  427. return debugdir;
  428. }
  429. export_user_file(from, to, project, platform) {
  430. if (project.get_debug_dir() === "")
  431. return;
  432. this.write_file(path_resolve(to, project.get_safe_name() + ".vcxproj.user"));
  433. this.p('<?xml version="1.0" encoding="utf-8"?>');
  434. this.p('<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">');
  435. this.p('<PropertyGroup>', 1);
  436. if (platform === "windows") {
  437. this.p('<LocalDebuggerWorkingDirectory>' + this.get_debug_dir(from, project) + '</LocalDebuggerWorkingDirectory>', 2);
  438. this.p('<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>', 2);
  439. project.cmdArgs.push(this.get_debug_dir(from, project));
  440. if (project.cmdArgs.length > 0) {
  441. this.p('<LocalDebuggerCommandArguments>' + project.cmdArgs.join(' ') + '</LocalDebuggerCommandArguments>', 2);
  442. }
  443. }
  444. this.p('</PropertyGroup>', 1);
  445. this.p('</Project>');
  446. this.close_file();
  447. }
  448. write_project_declarations(project, solutionUuid) {
  449. this.p('Project("{' + solutionUuid.toUpperCase() + '}") = "' + project.get_safe_name() + '", "' + project.get_safe_name() + '.vcxproj", "{' +
  450. project.get_uuid().toString().toUpperCase() + '}"');
  451. if (project.getSubProjects().length > 0) {
  452. this.p('ProjectSection(ProjectDependencies) = postProject', 1);
  453. for (let proj of project.getSubProjects()) {
  454. this.p('{' + proj.get_uuid().toString().toUpperCase() + '} = {' + proj.get_uuid().toString().toUpperCase() + '}', 2);
  455. }
  456. this.p('EndProjectSection', 1);
  457. }
  458. this.p('EndProject');
  459. for (let proj of project.getSubProjects())
  460. this.write_project_declarations(proj, solutionUuid);
  461. }
  462. get_configs() {
  463. return [ "Debug", "Develop", "Release" ];
  464. }
  465. get_systems() {
  466. return [ "x64" ];
  467. }
  468. export_solution(project) {
  469. let from = path_resolve(".");
  470. let to = path_resolve("build");
  471. let platform = goptions.target;
  472. this.write_file(path_resolve(to, project.get_safe_name() + '.slnx'));
  473. this.p('<Solution>');
  474. this.p('<Configurations>', 1);
  475. this.p('<Platform Name="x64" />', 2);
  476. this.p('</Configurations>', 1);
  477. this.p('<Project Path="' + project.get_safe_name() + '.vcxproj" Id="' + project.get_uuid().toString().toLowerCase() + '" />', 1);
  478. this.p('</Solution>');
  479. this.close_file();
  480. this.export_project(from, to, project, platform, false, goptions);
  481. this.export_filters(from, to, project, platform);
  482. this.export_user_file(from, to, project, platform);
  483. this.export_resource_script(to);
  484. export_ico(project.icon, path_resolve(to, 'icon.ico'), from);
  485. }
  486. export_resource_script(to) {
  487. this.write_file(path_resolve(to, "resources.rc"));
  488. this.p('107 ICON "icon.ico"');
  489. this.close_file();
  490. }
  491. pretty_dir(dir) {
  492. let pretty_dir = dir;
  493. while (pretty_dir.startsWith("../")) {
  494. pretty_dir = pretty_dir.substring(3);
  495. }
  496. return pretty_dir.replace(/\//g, "\\");
  497. }
  498. item_group(from, to, project, type, filter) {
  499. let lastdir = "";
  500. this.p('<ItemGroup>', 1);
  501. for (let file of project.getFiles()) {
  502. let dir = get_dir(file);
  503. if (dir !== lastdir)
  504. lastdir = dir;
  505. if (filter(file)) {
  506. let filepath = "";
  507. if (project.noFlatten && !path_isabs(file.file)) {
  508. filepath = path_resolve(path_join(project.basedir, file.file));
  509. }
  510. else {
  511. filepath = this.nice_path(from, to, file.file);
  512. }
  513. this.p('<' + type + ' Include="' + filepath + '">', 2);
  514. this.p('<Filter>' + this.pretty_dir(dir) + '</Filter>', 3);
  515. this.p('</' + type + '>', 2);
  516. }
  517. }
  518. this.p('</ItemGroup>', 1);
  519. }
  520. export_filters(from, to, project, platform) {
  521. for (let proj of project.getSubProjects())
  522. this.export_filters(from, to, proj, platform);
  523. this.write_file(path_resolve(to, project.get_safe_name() + '.vcxproj.filters'));
  524. this.p('<?xml version="1.0" encoding="utf-8"?>');
  525. this.p('<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">');
  526. let lastdir = '';
  527. let dirs = [];
  528. for (let file of project.getFiles()) {
  529. let dir = get_dir(file);
  530. if (dir !== lastdir) {
  531. let subdir = dir;
  532. while (subdir.indexOf('/') >= 0) {
  533. subdir = subdir.substr(0, subdir.lastIndexOf('/'));
  534. if (!dirs.includes(subdir))
  535. dirs.push(subdir);
  536. }
  537. dirs.push(dir);
  538. lastdir = dir;
  539. }
  540. }
  541. let assets = [];
  542. this.p('<ItemGroup>', 1);
  543. for (let dir of dirs) {
  544. let pretty = this.pretty_dir(dir);
  545. if (pretty !== '..') {
  546. this.p('<Filter Include="' + pretty + '">', 2);
  547. this.p('<UniqueIdentifier>{' + crypto_random_uuid().toString().toUpperCase() + '}</UniqueIdentifier>', 3);
  548. this.p('</Filter>', 2);
  549. }
  550. }
  551. this.p('</ItemGroup>', 1);
  552. this.item_group(from, to, project, 'ClInclude', (file) => { return file.file.endsWith(".h"); });
  553. this.item_group(from, to, project, 'ClCompile',
  554. (file) => { return file.file.endsWith(".cpp") || file.file.endsWith(".c") || file.file.endsWith(".cc"); });
  555. this.item_group(from, to, project, 'CustomBuild', (file) => { return file.file.endsWith(".hlsl"); });
  556. if (platform === "windows") {
  557. this.item_group(from, to, project, "ResourceCompile", (file) => { return file.file.endsWith(".rc"); });
  558. }
  559. this.p('</Project>');
  560. this.close_file();
  561. }
  562. get_platform_toolset() {
  563. // return 'v145';
  564. return 'ClangCL';
  565. }
  566. configuration(config, indent, project) {
  567. this.p('<PropertyGroup Condition="\'$(Configuration)\'==\'' + config + '\'" Label="Configuration">', indent);
  568. this.p('<ConfigurationType>Application</ConfigurationType>', indent + 1);
  569. this.p('<UseDebugLibraries>' + (config === "Release" ? "false" : "true") + '</UseDebugLibraries>', indent + 1);
  570. this.p('<PlatformToolset>' + this.get_platform_toolset() + '</PlatformToolset>', indent + 1);
  571. this.p('<PreferredToolArchitecture>x64</PreferredToolArchitecture>', indent + 1);
  572. if (config === "Release" && project.lto) {
  573. this.p('<WholeProgramOptimization>true</WholeProgramOptimization>', indent + 1);
  574. }
  575. this.p('<CharacterSet>Unicode</CharacterSet>', indent + 1);
  576. this.p('</PropertyGroup>', indent);
  577. }
  578. get_optimization(config) {
  579. switch (config) {
  580. case "Debug":
  581. default:
  582. return "Disabled";
  583. case "Develop":
  584. return "Full";
  585. case "Release":
  586. return "MaxSpeed";
  587. }
  588. }
  589. cStd(project) {
  590. switch (project.cStd.toLowerCase()) {
  591. case "c99":
  592. return "";
  593. case "c11":
  594. return "stdc11";
  595. case "c17":
  596. return "stdc17";
  597. case "c2x":
  598. return "stdc17";
  599. }
  600. }
  601. cppStd(project) {
  602. switch (project.cppStd.toLowerCase()) {
  603. case "c++17":
  604. return "stdcpp17";
  605. case "c++23":
  606. return "stdcpplatest";
  607. }
  608. }
  609. item_definition(config, system, includes, debugDefines, releaseDefines, indent, debuglibs, releaselibs, project) {
  610. this.p('<ItemDefinitionGroup Condition="\'$(Configuration)|$(Platform)\'==\'' + config + '|' + system + '\'">', indent);
  611. this.p('<ClCompile>', indent + 1);
  612. this.p('<AdditionalIncludeDirectories>' + includes + '</AdditionalIncludeDirectories>', indent + 2);
  613. this.p('<AdditionalOptions>-Wno-deprecated-declarations -Wno-c23-extensions -Wno-incompatible-pointer-types -Wno-incompatible-function-pointer-types -Wno-microsoft-enum-forward-reference /bigobj %(AdditionalOptions)</AdditionalOptions>', indent + 2);
  614. this.p('<WarningLevel>Level3</WarningLevel>', indent + 2);
  615. this.p('<Optimization>' + this.get_optimization(config) + '</Optimization>', indent + 2);
  616. if (config === 'Release') {
  617. this.p('<FunctionLevelLinking>true</FunctionLevelLinking>', indent + 2);
  618. this.p('<IntrinsicFunctions>true</IntrinsicFunctions>', indent + 2);
  619. }
  620. this.p('<PreprocessorDefinitions>' + (config === 'Release' ? releaseDefines : debugDefines) + ((system === 'x64') ? 'SYS_64;' : '') +
  621. 'WIN32;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>',
  622. indent + 2);
  623. this.p('<RuntimeLibrary>' + (config === 'Release' ? 'MultiThreaded' : 'MultiThreadedDebug') + '</RuntimeLibrary>', indent + 2);
  624. this.p('<MultiProcessorCompilation>true</MultiProcessorCompilation>', indent + 2);
  625. this.p('<MinimalRebuild>false</MinimalRebuild>', indent + 2);
  626. if (config === 'Develop') {
  627. this.p('<BasicRuntimeChecks>Default</BasicRuntimeChecks>', indent + 2);
  628. }
  629. let cStd = this.cStd(project);
  630. this.p('<LanguageStandard_C>' + cStd + '</LanguageStandard_C>', indent + 2);
  631. let cppStd = this.cppStd(project);
  632. this.p('<LanguageStandard>' + cppStd + '</LanguageStandard>', indent + 2);
  633. this.p('</ClCompile>', indent + 1);
  634. this.p('<Link>', indent + 1);
  635. if (project.name == "amake") { // TODO
  636. this.p('<SubSystem>Console</SubSystem>', indent + 2);
  637. }
  638. else {
  639. this.p('<SubSystem>Windows</SubSystem>', indent + 2);
  640. }
  641. this.p('<GenerateDebugInformation>true</GenerateDebugInformation>', indent + 2);
  642. if (config === 'Release') {
  643. this.p('<EnableCOMDATFolding>true</EnableCOMDATFolding>', indent + 2);
  644. this.p('<OptimizeReferences>true</OptimizeReferences>', indent + 2);
  645. }
  646. let libs = config === 'Release' ? releaselibs : debuglibs;
  647. this.p(
  648. '<AdditionalDependencies>' + libs +
  649. 'kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>',
  650. indent + 2);
  651. this.p('</Link>', indent + 1);
  652. this.p('<Manifest>', indent + 1);
  653. this.p('<EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>', indent + 2);
  654. this.p('</Manifest>', indent + 1);
  655. this.p('</ItemDefinitionGroup>', indent);
  656. }
  657. globals(indent) {
  658. this.p('<VCProjectVersion>18.0</VCProjectVersion>', indent);
  659. this.p('<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>', indent);
  660. }
  661. extension_settings(indent) {
  662. this.p('<Import Project="$(VCTargetsPath)\\BuildCustomizations\\masm.props" />', indent);
  663. }
  664. extension_targets(indent) {
  665. this.p('<Import Project="$(VCTargetsPath)\\BuildCustomizations\\masm.targets"/>', indent);
  666. }
  667. export_project(from, to, project, platform, cmd, options) {
  668. for (let proj of project.getSubProjects()) {
  669. this.export_project(from, to, proj, platform, cmd, options);
  670. }
  671. this.write_file(path_resolve(to, project.get_safe_name() + '.vcxproj'));
  672. this.p('<?xml version="1.0" encoding="utf-8"?>');
  673. this.p('<Project DefaultTargets="Build" ' +
  674. 'xmlns="http://schemas.microsoft.com/developer/msbuild/2003">');
  675. this.p('<ItemGroup Label="ProjectConfigurations">', 1);
  676. for (let system of this.get_systems()) {
  677. for (let config of this.get_configs()) {
  678. this.p('<ProjectConfiguration Include="' + config + '|' + system + '">', 2);
  679. this.p('<Configuration>' + config + '</Configuration>', 3);
  680. this.p('<Platform>' + system + '</Platform>', 3);
  681. this.p('</ProjectConfiguration>', 2);
  682. }
  683. }
  684. this.p('</ItemGroup>', 1);
  685. this.p('<PropertyGroup Label="Globals">', 1);
  686. this.p('<ProjectGuid>{' + project.get_uuid().toString().toLowerCase() + '}</ProjectGuid>', 2);
  687. this.globals(2);
  688. this.p('</PropertyGroup>', 1);
  689. this.p('<Import Project="$(VCTargetsPath)\\Microsoft.Cpp.Default.props" />', 1);
  690. for (let config of this.get_configs()) {
  691. for (let system of this.get_systems()) {
  692. this.configuration(config, 1, project);
  693. }
  694. }
  695. this.p('<Import Project="$(VCTargetsPath)\\Microsoft.Cpp.props" />', 1);
  696. this.p('<ImportGroup Label="ExtensionSettings">', 1);
  697. this.extension_settings(2);
  698. this.p('</ImportGroup>', 1);
  699. this.p('<PropertyGroup Label="UserMacros" />', 1);
  700. if (project.get_executable_name()) {
  701. this.p('<PropertyGroup>', 1);
  702. this.p('<TargetName>' + project.get_executable_name() + '</TargetName>', 2);
  703. this.p('</PropertyGroup>', 1);
  704. }
  705. if (platform === 'windows') {
  706. for (let system of this.get_systems()) {
  707. this.p('<ImportGroup Label="PropertySheets" Condition="\'$(Platform)\'==\'' + system + '\'">', 1);
  708. this.p(
  709. '<Import Project="$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props" Condition="exists(\'$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\')" Label="LocalAppDataPlatform" />',
  710. 2);
  711. this.p('</ImportGroup>', 1);
  712. }
  713. }
  714. let debugDefines = "_DEBUG;";
  715. let releaseDefines = "NDEBUG;";
  716. for (let define of project.getDefines()) {
  717. debugDefines += define + ";";
  718. releaseDefines += define + ";";
  719. }
  720. let incstring = "";
  721. let includedirs = project.getIncludeDirs();
  722. for (let include of includedirs) {
  723. let relativized = path_relative(to, path_resolve(from, include));
  724. if (relativized === "") {
  725. relativized = ".";
  726. }
  727. incstring += relativized + ";";
  728. }
  729. if (incstring.length > 0)
  730. incstring = incstring.substr(0, incstring.length - 1);
  731. let debuglibs = "";
  732. for (let proj of project.getSubProjects()) {
  733. if (proj.noFlatten) {
  734. debuglibs += project.basedir + "\\build\\x64\\Debug\\" + proj.get_safe_name() + ".lib;";
  735. }
  736. else {
  737. debuglibs += "Debug\\" + proj.get_safe_name() + ".lib;";
  738. }
  739. }
  740. for (let lib of project.getLibs()) {
  741. if (fs_exists(path_resolve(from, lib + ".lib"))) {
  742. debuglibs += path_relative(to, path_resolve(from, lib)) + ".lib;";
  743. }
  744. else {
  745. debuglibs += lib + ".lib;";
  746. }
  747. }
  748. let releaselibs = "";
  749. for (let proj of project.getSubProjects()) {
  750. if (proj.noFlatten) {
  751. releaselibs += project.basedir + "\\build\\x64\\Release\\" + proj.get_safe_name() + ".lib;";
  752. }
  753. else {
  754. releaselibs += "Release\\" + proj.get_safe_name() + ".lib;";
  755. }
  756. }
  757. for (let proj of project.getSubProjects())
  758. releaselibs += "Release\\" + proj.get_safe_name() + ".lib;";
  759. for (let lib of project.getLibs()) {
  760. if (fs_exists(path_resolve(from, lib + ".lib"))) {
  761. releaselibs += path_relative(to, path_resolve(from, lib)) + ".lib;";
  762. }
  763. else {
  764. releaselibs += lib + ".lib;";
  765. }
  766. }
  767. for (let config of this.get_configs()) {
  768. for (let system of this.get_systems()) {
  769. this.item_definition(config, system, incstring, debugDefines, releaseDefines, 2, debuglibs, releaselibs, project);
  770. }
  771. }
  772. this.p('<ItemGroup>', 1);
  773. for (let file of project.getFiles()) {
  774. let filepath = "";
  775. if (project.noFlatten && !path_isabs(file.file)) {
  776. filepath = path_resolve(project.basedir + "/" + file.file);
  777. }
  778. else {
  779. filepath = this.nice_path(from, to, file.file);
  780. }
  781. if (file.file.endsWith(".h"))
  782. this.p('<ClInclude Include="' + filepath + '" />', 2);
  783. }
  784. this.p('</ItemGroup>', 1);
  785. this.p('<ItemGroup>', 1);
  786. let objects = {};
  787. for (let fileobject of project.getFiles()) {
  788. let file = fileobject.file;
  789. if (file.endsWith(".cpp") || file.endsWith(".c") || file.endsWith("cc")) {
  790. let name = file.toLowerCase();
  791. if (name.indexOf("/") >= 0)
  792. name = name.substr(name.lastIndexOf("/") + 1);
  793. name = name.substr(0, name.lastIndexOf("."));
  794. let filepath = "";
  795. if (project.noFlatten && !path_isabs(file)) {
  796. filepath = path_resolve(project.basedir + "/" + file);
  797. }
  798. else {
  799. filepath = this.nice_path(from, to, file);
  800. }
  801. if (!objects[name]) {
  802. this.p('<ClCompile Include="' + filepath + '" />', 2);
  803. objects[name] = true;
  804. }
  805. else {
  806. while (objects[name]) {
  807. name = name + '_';
  808. }
  809. this.p('<ClCompile Include="' + filepath + '">', 2);
  810. this.p('<ObjectFileName>$(IntDir)\\' + name + '.obj</ObjectFileName>', 3);
  811. this.p('</ClCompile>', 2);
  812. objects[name] = true;
  813. }
  814. }
  815. }
  816. this.p('</ItemGroup>', 1);
  817. this.p('<ItemGroup>', 1);
  818. for (let file of project.getFiles()) {
  819. if (file.file.endsWith('.natvis')) {
  820. this.p('<Natvis Include="' + this.nice_path(from, to, file.file) + '"/>', 2);
  821. }
  822. }
  823. this.p('</ItemGroup>', 1);
  824. if (platform === "windows") {
  825. this.p('<ItemGroup>', 1);
  826. for (let file of project.customs) {
  827. this.p('<CustomBuild Include="' + this.nice_path(from, to, file.file) + '">', 2);
  828. this.p('<FileType>Document</FileType>', 2);
  829. this.p('<Command>' + file.command + '</Command>', 2);
  830. this.p('<Outputs>' + file.output + '</Outputs>', 2);
  831. this.p('<Message>%(Filename)%(Extension)</Message>', 2);
  832. this.p('</CustomBuild>', 2);
  833. }
  834. this.p('</ItemGroup>');
  835. this.p('<ItemGroup>', 1);
  836. this.p('<None Include="icon.ico" />', 2);
  837. this.p('</ItemGroup>', 1);
  838. this.p('<ItemGroup>', 1);
  839. this.p('<ResourceCompile Include="resources.rc" />', 2);
  840. for (let file of project.getFiles()) {
  841. if (file.file.endsWith('.rc')) {
  842. this.p('<ResourceCompile Include="' + this.nice_path(from, to, file.file) + '" />', 2);
  843. }
  844. }
  845. this.p('</ItemGroup>', 1);
  846. }
  847. this.p('<Import Project="$(VCTargetsPath)\\Microsoft.Cpp.targets" />', 1);
  848. this.p('<ImportGroup Label="ExtensionTargets">', 1);
  849. this.extension_targets(2);
  850. this.p('</ImportGroup>', 1);
  851. this.p('</Project>');
  852. this.close_file();
  853. }
  854. }
  855. class WasmExporter extends Exporter {
  856. constructor() {
  857. super();
  858. this.compile_commands = new CompilerCommandsExporter();
  859. let compiler = "clang --target=wasm32 -nostdlib -matomics -mbulk-memory";
  860. let compilerFlags = "";
  861. this.make =
  862. new MakeExporter(compiler, compiler, compilerFlags, compilerFlags,
  863. // '--target=wasm32 -nostdlib -matomics -mbulk-memory "-Wl,--import-memory,--shared-memory,--allow-undefined,--no-entry"', '.wasm');
  864. '--target=wasm32 -nostdlib -matomics -mbulk-memory "-Wl,--import-memory,--shared-memory,--allow-undefined,--no-entry,--stack-first,--initial-memory=543621120,--max-memory=543621120,-z,stack-size=6553600"', '.wasm');
  865. }
  866. export_solution(project) {
  867. this.make.export_solution(project);
  868. this.compile_commands.export_solution(project);
  869. }
  870. }
  871. function new_path_id(path) {
  872. return uuidv5(path, "7448ebd8-cfc8-4f45-8b3d-5df577ceea6d").toUpperCase();
  873. }
  874. function get_dir2(file) {
  875. if (file.file.indexOf("/") >= 0) {
  876. let dir = file.file.substr(0, file.file.lastIndexOf("/"));
  877. return path_join(file.projectName, path_relative(file.projectDir, dir)).replace(/\\/g, "/");
  878. }
  879. else {
  880. return file.projectName;
  881. }
  882. }
  883. class Directory {
  884. constructor(dirname) {
  885. this.dirname = dirname;
  886. this.id = new_path_id(dirname);
  887. }
  888. getName() {
  889. return this.dirname;
  890. }
  891. getLastName() {
  892. if (this.dirname.indexOf("/") < 0)
  893. return this.dirname;
  894. return this.dirname.substr(this.dirname.lastIndexOf("/") + 1);
  895. }
  896. getId() {
  897. return this.id;
  898. }
  899. }
  900. class File {
  901. constructor(filename, dir) {
  902. this.filename = filename;
  903. this.dir = dir;
  904. this.buildid = new_path_id(dir + filename + "_buildid");
  905. this.fileid = new_path_id(dir + filename + "_fileid");
  906. }
  907. getBuildId() {
  908. return this.buildid;
  909. }
  910. getFileId() {
  911. return this.fileid;
  912. }
  913. isBuildFile() {
  914. return this.filename.endsWith(".c") || this.filename.endsWith(".cpp") || this.filename.endsWith(".m") || this.filename.endsWith(".mm") ||
  915. this.filename.endsWith(".cc") || this.filename.endsWith(".metal");
  916. }
  917. getName() {
  918. return this.filename;
  919. }
  920. getLastName() {
  921. if (this.filename.indexOf("/") < 0)
  922. return this.filename;
  923. return this.filename.substr(this.filename.lastIndexOf("/") + 1);
  924. }
  925. get_dir() {
  926. return this.dir;
  927. }
  928. toString() {
  929. return this.getName();
  930. }
  931. }
  932. class Framework {
  933. constructor(name) {
  934. this.name = name;
  935. this.buildid = new_path_id(name + "_buildid");
  936. this.fileid = new_path_id(name + "_fileid");
  937. this.localPath = null;
  938. }
  939. toString() {
  940. if (this.name.indexOf(".") < 0)
  941. return this.name + ".framework";
  942. else
  943. return this.name;
  944. }
  945. getBuildId() {
  946. return this.buildid.toString().toUpperCase();
  947. }
  948. getFileId() {
  949. return this.fileid.toString().toUpperCase();
  950. }
  951. }
  952. function findDirectory(dirname, directories) {
  953. for (let dir of directories) {
  954. if (dir.getName() === dirname) {
  955. return dir;
  956. }
  957. }
  958. return null;
  959. }
  960. function addDirectory(dirname, directories) {
  961. let dir = findDirectory(dirname, directories);
  962. if (dir === null) {
  963. dir = new Directory(dirname);
  964. directories.push(dir);
  965. while (dirname.indexOf("/") >= 0) {
  966. dirname = dirname.substr(0, dirname.lastIndexOf("/"));
  967. addDirectory(dirname, directories);
  968. }
  969. }
  970. return dir;
  971. }
  972. class IconImage {
  973. constructor(idiom, size, scale) {
  974. this.idiom = idiom;
  975. this.size = size;
  976. this.scale = scale;
  977. }
  978. }
  979. class XCodeExporter extends Exporter {
  980. constructor() {
  981. super();
  982. }
  983. exportWorkspace(to, project) {
  984. let dir = path_resolve(to, project.get_safe_name() + ".xcodeproj", "project.xcworkspace");
  985. fs_ensuredir(dir);
  986. this.write_file(path_resolve(to, project.get_safe_name() + ".xcodeproj", "project.xcworkspace", "contents.xcworkspacedata"));
  987. this.p('<?xml version="1.0" encoding="UTF-8"?>');
  988. this.p('<Workspace');
  989. this.p('version = "1.0">');
  990. this.p('<FileRef');
  991. this.p('location = "self:' + project.get_safe_name() + '.xcodeproj">');
  992. this.p('</FileRef>');
  993. this.p('</Workspace>');
  994. this.close_file();
  995. }
  996. export_solution(project) {
  997. let from = path_resolve(".");
  998. let to = path_resolve("build");
  999. let platform = goptions.target;
  1000. let xdir = path_resolve(to, project.get_safe_name() + ".xcodeproj");
  1001. fs_ensuredir(xdir);
  1002. this.exportWorkspace(to, project);
  1003. function add_icons(icons, idiom, sizes, scales) {
  1004. for (let i = 0; i < sizes.length; ++i) {
  1005. icons.push(new IconImage(idiom, sizes[i], scales[i]));
  1006. }
  1007. }
  1008. let icons = [];
  1009. if (platform === "ios") {
  1010. add_icons(icons, "iphone", [ 20, 20, 29, 29, 40, 40, 60, 60 ], [ 2, 3, 2, 3, 2, 3, 2, 3 ]);
  1011. add_icons(icons, "ipad", [ 20, 20, 29, 29, 40, 40, 76, 76, 83.5 ], [ 1, 2, 1, 2, 1, 2, 1, 2, 2 ]);
  1012. icons.push(new IconImage("ios-marketing", 1024, 1));
  1013. }
  1014. else {
  1015. add_icons(icons, "mac", [ 16, 16, 32, 32, 128, 128, 256, 256, 512, 512 ], [ 1, 2, 1, 2, 1, 2, 1, 2, 1, 2 ]);
  1016. }
  1017. let iconsdir = path_resolve(to, "Images.xcassets", "AppIcon.appiconset");
  1018. fs_ensuredir(iconsdir);
  1019. this.write_file(path_resolve(to, "Images.xcassets", "AppIcon.appiconset", "Contents.json"));
  1020. this.p('{');
  1021. this.p('"images" : [', 1);
  1022. for (let i = 0; i < icons.length; ++i) {
  1023. let icon = icons[i];
  1024. this.p('{', 2);
  1025. this.p('"idiom" : "' + icon.idiom + '",', 3);
  1026. this.p('"size" : "' + icon.size + 'x' + icon.size + '",', 3);
  1027. this.p('"filename" : "' + icon.idiom + icon.scale + 'x' + icon.size + '.png",', 3);
  1028. this.p('"scale" : "' + icon.scale + 'x"', 3);
  1029. if (i === icons.length - 1)
  1030. this.p('}', 2);
  1031. else
  1032. this.p('},', 2);
  1033. }
  1034. this.p('],', 1);
  1035. this.p('"info" : {', 1);
  1036. this.p('"version" : 1,', 2);
  1037. this.p('"author" : "xcode"', 2);
  1038. this.p('}', 1);
  1039. this.p('}');
  1040. this.close_file();
  1041. for (let i = 0; i < icons.length; ++i) {
  1042. let icon = icons[i];
  1043. export_png_icon(project.icon, path_resolve(to, 'Images.xcassets', 'AppIcon.appiconset', icon.idiom + icon.scale + 'x' + icon.size + '.png'),
  1044. icon.size * icon.scale, icon.size * icon.scale, from);
  1045. }
  1046. let plistname = "";
  1047. let files = [];
  1048. let directories = [];
  1049. for (let fileobject of project.getFiles()) {
  1050. let filename = fileobject.file;
  1051. if (filename.endsWith(".plist")) {
  1052. plistname = filename;
  1053. }
  1054. let dir = addDirectory(get_dir2(fileobject), directories);
  1055. let file = new File(filename, dir);
  1056. files.push(file);
  1057. }
  1058. if (plistname.length === 0) {
  1059. console.log("Error: no plist found");
  1060. }
  1061. let frameworks = [];
  1062. for (let lib of project.getLibs()) {
  1063. frameworks.push(new Framework(lib));
  1064. }
  1065. let target_options =
  1066. {bundle : 'org.armory3d.' + project.getName().toLowerCase(), version : "1.0", build : "1", organizationName : "Armory3D", developmentTeam : ""};
  1067. if (project.target_options && project.target_options.ios) {
  1068. let userOptions = project.target_options.ios;
  1069. if (userOptions.version)
  1070. target_options.version = userOptions.version;
  1071. if (userOptions.build)
  1072. target_options.build = userOptions.build;
  1073. }
  1074. let projectId = new_path_id("_projectId");
  1075. let appFileId = new_path_id("_appFileId");
  1076. let frameworkBuildId = new_path_id("_frameworkBuildId");
  1077. let sourceBuildId = new_path_id("_sourceBuildId");
  1078. let frameworksGroupId = new_path_id("_frameworksGroupId");
  1079. let productsGroupId = new_path_id("_productsGroupId");
  1080. let mainGroupId = new_path_id("_mainGroupId");
  1081. let targetId = new_path_id("_targetId");
  1082. let nativeBuildConfigListId = new_path_id("_nativeBuildConfigListId");
  1083. let projectBuildConfigListId = new_path_id("_projectBuildConfigListId");
  1084. let debugId = new_path_id("_debugId");
  1085. let releaseId = new_path_id("_releaseId");
  1086. let nativeDebugId = new_path_id("_nativeDebugId");
  1087. let nativeReleaseId = new_path_id("_nativeReleaseId");
  1088. let debugDirFileId = new_path_id("_debugDirFileId");
  1089. let debugDirBuildId = new_path_id("_debugDirBuildId");
  1090. let resourcesBuildId = new_path_id("_resourcesBuildId");
  1091. let iconFileId = new_path_id("_iconFileId");
  1092. let iconBuildId = new_path_id("_iconBuildId");
  1093. this.write_file(path_resolve(to, project.get_safe_name() + ".xcodeproj", "project.pbxproj"));
  1094. this.p('// !$*UTF8*$!');
  1095. this.p('{');
  1096. this.p('archiveVersion = 1;', 1);
  1097. this.p('classes = {', 1);
  1098. this.p('};', 1);
  1099. this.p('objectVersion = 46;', 1);
  1100. this.p('objects = {', 1);
  1101. this.p();
  1102. this.p('/* Begin PBXBuildFile section */');
  1103. for (let framework of frameworks) {
  1104. this.p(framework.getBuildId() + ' /* ' + framework.toString() + ' in Frameworks */ = {isa = PBXBuildFile; fileRef = ' + framework.getFileId() +
  1105. ' /* ' + framework.toString() + ' */; };',
  1106. 2);
  1107. }
  1108. this.p(debugDirBuildId + ' /* Deployment in Resources */ = {isa = PBXBuildFile; fileRef = ' + debugDirFileId + ' /* Deployment */; };', 2);
  1109. for (let file of files) {
  1110. if (file.isBuildFile()) {
  1111. this.p(file.getBuildId() + ' /* ' + file.toString() + ' in Sources */ = {isa = PBXBuildFile; fileRef = ' + file.getFileId() + ' /* ' +
  1112. file.toString() + ' */; };',
  1113. 2);
  1114. }
  1115. }
  1116. this.p(iconBuildId + ' /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = ' + iconFileId + ' /* Images.xcassets */; };', 2);
  1117. this.p('/* End PBXBuildFile section */');
  1118. this.p();
  1119. this.p('/* Begin PBXFileReference section */');
  1120. let executable_name = project.get_safe_name();
  1121. if (project.get_executable_name()) {
  1122. executable_name = project.get_executable_name();
  1123. }
  1124. this.p(appFileId + ' /* ' + project.get_safe_name() +
  1125. '.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "' + executable_name +
  1126. '.app"; sourceTree = BUILT_PRODUCTS_DIR; };',
  1127. 2);
  1128. for (let framework of frameworks) {
  1129. if (framework.toString().endsWith('.framework')) {
  1130. // Local framework - a directory is specified
  1131. if (framework.toString().indexOf('/') >= 0) {
  1132. framework.localPath = path_resolve(from, framework.toString());
  1133. this.p(framework.getFileId() + ' /* ' + framework.toString() +
  1134. ' */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ' + framework.toString() +
  1135. '; path = ' + framework.localPath + '; sourceTree = "<absolute>"; };',
  1136. 2);
  1137. }
  1138. // XCode framework
  1139. else {
  1140. this.p(framework.getFileId() + ' /* ' + framework.toString() +
  1141. ' */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ' + framework.toString() +
  1142. '; path = System/Library/Frameworks/' + framework.toString() + '; sourceTree = SDKROOT; };',
  1143. 2);
  1144. }
  1145. }
  1146. else if (framework.toString().endsWith('.dylib')) {
  1147. if (framework.toString().indexOf('/') >= 0) {
  1148. framework.localPath = path_resolve(from, framework.toString());
  1149. this.p(framework.getFileId() + ' /* ' + framework.toString() +
  1150. ' */ = {isa = PBXFileReference; lastKnownFileType = compiled.mach-o.dylib; name = ' + framework.toString() +
  1151. '; path = ' + framework.localPath + '; sourceTree = "<absolute>"; };',
  1152. 2);
  1153. }
  1154. else {
  1155. this.p(framework.getFileId() + ' /* ' + framework.toString() +
  1156. ' */ = {isa = PBXFileReference; lastKnownFileType = compiled.mach-o.dylib; name = ' + framework.toString() +
  1157. '; path = usr/lib/' + framework.toString() + '; sourceTree = SDKROOT; };',
  1158. 2);
  1159. }
  1160. }
  1161. else {
  1162. framework.localPath = path_resolve(from, framework.toString());
  1163. this.p(framework.getFileId() + ' /* ' + framework.toString() + ' */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = ' +
  1164. framework.toString() + '; path = ' + framework.localPath + '; sourceTree = "<group>"; };',
  1165. 2);
  1166. }
  1167. }
  1168. this.p(debugDirFileId + ' /* Deployment */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Deployment; path = "' +
  1169. path_resolve(from, project.get_debug_dir()) + '"; sourceTree = "<group>"; };',
  1170. 2);
  1171. for (let file of files) {
  1172. let filetype = "unknown";
  1173. let fileencoding = "";
  1174. if (file.getName().endsWith(".plist"))
  1175. filetype = "text.plist.xml";
  1176. if (file.getName().endsWith(".h"))
  1177. filetype = "sourcecode.c.h";
  1178. if (file.getName().endsWith(".m"))
  1179. filetype = "sourcecode.c.objc";
  1180. if (file.getName().endsWith(".c"))
  1181. filetype = "sourcecode.c.c";
  1182. if (file.getName().endsWith(".cpp"))
  1183. filetype = "sourcecode.c.cpp";
  1184. if (file.getName().endsWith(".cc"))
  1185. filetype = "sourcecode.c.cpp";
  1186. if (file.getName().endsWith(".mm"))
  1187. filetype = "sourcecode.c.objcpp";
  1188. if (file.getName().endsWith(".metal")) {
  1189. filetype = "sourcecode.metal";
  1190. fileencoding = "fileEncoding = 4; ";
  1191. }
  1192. if (!file.getName().endsWith(".DS_Store")) {
  1193. this.p(file.getFileId() + ' /* ' + file.toString() + ' */ = {isa = PBXFileReference; ' + fileencoding + 'lastKnownFileType = ' + filetype +
  1194. '; name = "' + file.getLastName() + '"; path = "' + path_resolve(from, file.toString()) + '"; sourceTree = "<group>"; };',
  1195. 2);
  1196. }
  1197. }
  1198. this.p(
  1199. iconFileId +
  1200. ' /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };',
  1201. 2);
  1202. this.p('/* End PBXFileReference section */');
  1203. this.p();
  1204. this.p('/* Begin PBXFrameworksBuildPhase section */');
  1205. this.p(frameworkBuildId + ' /* Frameworks */ = {', 2);
  1206. this.p('isa = PBXFrameworksBuildPhase;', 3);
  1207. this.p('buildActionMask = 2147483647;', 3);
  1208. this.p('files = (', 3);
  1209. for (let framework of frameworks) {
  1210. this.p(framework.getBuildId() + ' /* ' + framework.toString() + ' in Frameworks */,', 4);
  1211. }
  1212. this.p(');', 3);
  1213. this.p('runOnlyForDeploymentPostprocessing = 0;', 3);
  1214. this.p('};', 2);
  1215. this.p('/* End PBXFrameworksBuildPhase section */');
  1216. this.p();
  1217. this.p('/* Begin PBXGroup section */');
  1218. this.p(mainGroupId + ' = {', 2);
  1219. this.p('isa = PBXGroup;', 3);
  1220. this.p('children = (', 3);
  1221. this.p(iconFileId + ' /* Images.xcassets */,', 4);
  1222. this.p(debugDirFileId + ' /* Deployment */,', 4);
  1223. for (let dir of directories) {
  1224. if (dir.getName().indexOf('/') < 0)
  1225. this.p(dir.getId() + ' /* ' + dir.getName() + ' */,', 4);
  1226. }
  1227. this.p(frameworksGroupId + ' /* Frameworks */,', 4);
  1228. this.p(productsGroupId + ' /* Products */,', 4);
  1229. this.p(');', 3);
  1230. this.p('sourceTree = "<group>";', 3);
  1231. this.p('};', 2);
  1232. this.p(productsGroupId + ' /* Products */ = {', 2);
  1233. this.p('isa = PBXGroup;', 3);
  1234. this.p('children = (', 3);
  1235. this.p(appFileId + ' /* ' + project.get_safe_name() + '.app */,', 4);
  1236. this.p(');', 3);
  1237. this.p('name = Products;', 3);
  1238. this.p('sourceTree = "<group>";', 3);
  1239. this.p('};', 2);
  1240. this.p(frameworksGroupId + ' /* Frameworks */ = {', 2);
  1241. this.p('isa = PBXGroup;', 3);
  1242. this.p('children = (', 3);
  1243. for (let framework of frameworks) {
  1244. this.p(framework.getFileId() + ' /* ' + framework.toString() + ' */,', 4);
  1245. }
  1246. this.p(');', 3);
  1247. this.p('name = Frameworks;', 3);
  1248. this.p('sourceTree = "<group>";', 3);
  1249. this.p('};', 2);
  1250. for (let dir of directories) {
  1251. this.p(dir.getId() + ' /* ' + dir.getName() + ' */ = {', 2);
  1252. this.p('isa = PBXGroup;', 3);
  1253. this.p('children = (', 3);
  1254. for (let dir2 of directories) {
  1255. if (dir2 === dir)
  1256. continue;
  1257. if (dir2.getName().startsWith(dir.getName())) {
  1258. if (dir2.getName().substr(dir.getName().length + 1).indexOf('/') < 0)
  1259. this.p(dir2.getId() + ' /* ' + dir2.getName() + ' */,', 4);
  1260. }
  1261. }
  1262. for (let file of files) {
  1263. if (file.get_dir() === dir && !file.getName().endsWith('.DS_Store'))
  1264. this.p(file.getFileId() + ' /* ' + file.toString() + ' */,', 4);
  1265. }
  1266. this.p(');', 3);
  1267. if (dir.getName().indexOf('/') < 0) {
  1268. this.p('path = ../;', 3);
  1269. this.p('name = "' + dir.getLastName() + '";', 3);
  1270. }
  1271. else
  1272. this.p('name = "' + dir.getLastName() + '";', 3);
  1273. this.p('sourceTree = "<group>";', 3);
  1274. this.p('};', 2);
  1275. }
  1276. this.p('/* End PBXGroup section */');
  1277. this.p();
  1278. this.p('/* Begin PBXNativeTarget section */');
  1279. this.p(targetId + ' /* ' + project.get_safe_name() + ' */ = {', 2);
  1280. this.p('isa = PBXNativeTarget;', 3);
  1281. this.p('buildConfigurationList = ' + nativeBuildConfigListId + ' /* Build configuration list for PBXNativeTarget "' + project.get_safe_name() + '" */;',
  1282. 3);
  1283. this.p('buildPhases = (', 3);
  1284. this.p(sourceBuildId + ' /* Sources */,', 4);
  1285. this.p(frameworkBuildId + ' /* Frameworks */,', 4);
  1286. this.p(resourcesBuildId + ' /* Resources */,', 4);
  1287. this.p(');', 3);
  1288. this.p('buildRules = (', 3);
  1289. this.p(');', 3);
  1290. this.p('dependencies = (', 3);
  1291. this.p(');', 3);
  1292. this.p('name = "' + project.getName() + '";', 3);
  1293. this.p('productName = "' + project.getName() + '";', 3);
  1294. this.p('productReference = ' + appFileId + ' /* ' + project.get_safe_name() + '.app */;', 3);
  1295. if (project.name == "amake") { // TODO
  1296. this.p('productType = "com.apple.product-type.tool";', 3);
  1297. }
  1298. else {
  1299. this.p('productType = "com.apple.product-type.application";', 3);
  1300. }
  1301. this.p('};', 2);
  1302. this.p('/* End PBXNativeTarget section */');
  1303. this.p();
  1304. this.p('/* Begin PBXProject section */');
  1305. this.p(projectId + ' /* Project object */ = {', 2);
  1306. this.p('isa = PBXProject;', 3);
  1307. this.p('attributes = {', 3);
  1308. this.p('LastUpgradeCheck = 1230;', 4);
  1309. this.p('ORGANIZATIONNAME = "' + target_options.organizationName + '";', 4);
  1310. this.p('TargetAttributes = {', 4);
  1311. this.p(targetId + ' = {', 5);
  1312. this.p('CreatedOnToolsVersion = 6.1.1;', 6);
  1313. if (target_options.developmentTeam) {
  1314. this.p('DevelopmentTeam = ' + target_options.developmentTeam + ';', 6);
  1315. }
  1316. this.p('};', 5);
  1317. this.p('};', 4);
  1318. this.p('};', 3);
  1319. this.p('buildConfigurationList = ' + projectBuildConfigListId + ' /* Build configuration list for PBXProject "' + project.get_safe_name() + '" */;', 3);
  1320. this.p('compatibilityVersion = "Xcode 3.2";', 3);
  1321. this.p('developmentRegion = en;', 3);
  1322. this.p('hasScannedForEncodings = 0;', 3);
  1323. this.p('knownRegions = (', 3);
  1324. this.p('en,', 4);
  1325. this.p('Base,', 4);
  1326. this.p(');', 3);
  1327. this.p('mainGroup = ' + mainGroupId + ';', 3);
  1328. this.p('productRefGroup = ' + productsGroupId + ' /* Products */;', 3);
  1329. this.p('projectDirPath = "";', 3);
  1330. this.p('projectRoot = "";', 3);
  1331. this.p('targets = (', 3);
  1332. this.p(targetId + ' /* ' + project.get_safe_name() + ' */,', 4);
  1333. this.p(');', 3);
  1334. this.p('};', 2);
  1335. this.p('/* End PBXProject section */');
  1336. this.p();
  1337. this.p('/* Begin PBXResourcesBuildPhase section */');
  1338. this.p(resourcesBuildId + ' /* Resources */ = {', 2);
  1339. this.p('isa = PBXResourcesBuildPhase;', 3);
  1340. this.p('buildActionMask = 2147483647;', 3);
  1341. this.p('files = (', 3);
  1342. this.p(debugDirBuildId + ' /* Deployment in Resources */,', 4);
  1343. this.p(iconBuildId + ' /* Images.xcassets in Resources */,', 4);
  1344. this.p(');', 3);
  1345. this.p('runOnlyForDeploymentPostprocessing = 0;', 3);
  1346. this.p('};', 2);
  1347. this.p('/* End PBXResourcesBuildPhase section */');
  1348. this.p();
  1349. this.p('/* Begin PBXSourcesBuildPhase section */');
  1350. this.p(sourceBuildId + ' /* Sources */ = {', 2);
  1351. this.p('isa = PBXSourcesBuildPhase;', 3);
  1352. this.p('buildActionMask = 2147483647;', 3);
  1353. this.p('files = (', 3);
  1354. for (let file of files) {
  1355. if (file.isBuildFile())
  1356. this.p(file.getBuildId() + ' /* ' + file.toString() + ' in Sources */,', 4);
  1357. }
  1358. this.p(');', 3);
  1359. this.p('runOnlyForDeploymentPostprocessing = 0;');
  1360. this.p('};');
  1361. this.p('/* End PBXSourcesBuildPhase section */');
  1362. this.p();
  1363. this.p('/* Begin XCBuildConfiguration section */');
  1364. this.p(debugId + ' /* Debug */ = {', 2);
  1365. this.p('isa = XCBuildConfiguration;', 3);
  1366. this.p('buildSettings = {', 3);
  1367. this.p('ALWAYS_SEARCH_USER_PATHS = NO;', 4);
  1368. this.p('CLANG_CXX_LANGUAGE_STANDARD = "' + project.cppStd + '";', 4);
  1369. this.p('CLANG_CXX_LIBRARY = "compiler-default";', 4);
  1370. this.p('CLANG_ENABLE_MODULES = YES;', 4);
  1371. this.p('CLANG_ENABLE_OBJC_ARC = YES;', 4);
  1372. this.p('CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;', 4);
  1373. this.p('CLANG_WARN_BOOL_CONVERSION = YES;', 4);
  1374. this.p('CLANG_WARN_COMMA = YES;', 4);
  1375. this.p('CLANG_WARN_CONSTANT_CONVERSION = YES;', 4);
  1376. this.p('CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;', 4);
  1377. this.p('CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;', 4);
  1378. this.p('CLANG_WARN_EMPTY_BODY = YES;', 4);
  1379. this.p('CLANG_WARN_ENUM_CONVERSION = YES;', 4);
  1380. this.p('CLANG_WARN_INFINITE_RECURSION = YES;', 4);
  1381. this.p('CLANG_WARN_INT_CONVERSION = YES;', 4);
  1382. this.p('CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;', 4);
  1383. this.p('CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;', 4);
  1384. this.p('CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;', 4);
  1385. this.p('CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;', 4);
  1386. this.p('CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;', 4);
  1387. this.p('CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;', 4);
  1388. this.p('CLANG_WARN_STRICT_PROTOTYPES = YES;', 4);
  1389. this.p('CLANG_WARN_SUSPICIOUS_MOVE = YES;', 4);
  1390. this.p('CLANG_WARN_UNREACHABLE_CODE = YES;', 4);
  1391. this.p('CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;', 4);
  1392. if (platform === 'ios') {
  1393. this.p('"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";', 4);
  1394. }
  1395. else {
  1396. this.p('CODE_SIGN_IDENTITY = "-";', 4);
  1397. // this.p('"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";', 4);
  1398. }
  1399. this.p('COPY_PHASE_STRIP = NO;', 4);
  1400. this.p('ENABLE_STRICT_OBJC_MSGSEND = YES;', 4);
  1401. this.p('ENABLE_TESTABILITY = YES;', 4);
  1402. this.p('GCC_C_LANGUAGE_STANDARD = "' + project.cStd + '";', 4);
  1403. this.p('GCC_DYNAMIC_NO_PIC = NO;', 4);
  1404. this.p('GCC_NO_COMMON_BLOCKS = YES;', 4);
  1405. this.p('GCC_OPTIMIZATION_LEVEL = 0;', 4);
  1406. this.p('GCC_PREPROCESSOR_DEFINITIONS = (', 4);
  1407. this.p('"DEBUG=1",', 5);
  1408. for (let define of project.getDefines()) {
  1409. if (define.indexOf('=') >= 0)
  1410. this.p('"' + define.replace(/\"/g, '\\\\\\"') + '",', 5);
  1411. else
  1412. this.p(define + ',', 5);
  1413. }
  1414. this.p('"$(inherited)",', 5);
  1415. this.p(');', 4);
  1416. this.p('GCC_SYMBOLS_PRIVATE_EXTERN = NO;', 4);
  1417. this.p('GCC_WARN_64_TO_32_BIT_CONVERSION = YES;', 4);
  1418. this.p('GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;', 4);
  1419. this.p('GCC_WARN_UNDECLARED_SELECTOR = YES;', 4);
  1420. this.p('GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;', 4);
  1421. this.p('GCC_WARN_UNUSED_FUNCTION = YES;', 4);
  1422. this.p('GCC_WARN_UNUSED_VARIABLE = YES;', 4);
  1423. if (platform === 'ios') {
  1424. this.p('IPHONEOS_DEPLOYMENT_TARGET = 16.0;', 4);
  1425. }
  1426. else {
  1427. this.p('MACOSX_DEPLOYMENT_TARGET = 13.0;', 4);
  1428. }
  1429. this.p('MTL_ENABLE_DEBUG_INFO = YES;', 4);
  1430. this.p('ONLY_ACTIVE_ARCH = YES;', 4);
  1431. if (platform === 'ios') {
  1432. this.p('SDKROOT = iphoneos;', 4);
  1433. this.p('TARGETED_DEVICE_FAMILY = "1,2";', 4);
  1434. }
  1435. else {
  1436. this.p('SDKROOT = macosx;', 4);
  1437. }
  1438. this.p('};', 3);
  1439. this.p('name = Debug;', 3);
  1440. this.p('};', 2);
  1441. this.p(releaseId + ' /* Release */ = {', 2);
  1442. this.p('isa = XCBuildConfiguration;', 3);
  1443. this.p('buildSettings = {', 3);
  1444. this.p('ALWAYS_SEARCH_USER_PATHS = NO;', 4);
  1445. this.p('CLANG_CXX_LANGUAGE_STANDARD = "' + project.cppStd + '";', 4);
  1446. this.p('CLANG_CXX_LIBRARY = "compiler-default";', 4);
  1447. this.p('CLANG_ENABLE_MODULES = YES;', 4);
  1448. this.p('CLANG_ENABLE_OBJC_ARC = YES;', 4);
  1449. this.p('CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;', 4);
  1450. this.p('CLANG_WARN_BOOL_CONVERSION = YES;', 4);
  1451. this.p('CLANG_WARN_COMMA = YES;', 4);
  1452. this.p('CLANG_WARN_CONSTANT_CONVERSION = YES;', 4);
  1453. this.p('CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;', 4);
  1454. this.p('CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;', 4);
  1455. this.p('CLANG_WARN_EMPTY_BODY = YES;', 4);
  1456. this.p('CLANG_WARN_ENUM_CONVERSION = YES;', 4);
  1457. this.p('CLANG_WARN_INFINITE_RECURSION = YES;', 4);
  1458. this.p('CLANG_WARN_INT_CONVERSION = YES;', 4);
  1459. this.p('CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;', 4);
  1460. this.p('CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;', 4);
  1461. this.p('CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;', 4);
  1462. this.p('CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;', 4);
  1463. this.p('CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;', 4);
  1464. this.p('CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;', 4);
  1465. this.p('CLANG_WARN_STRICT_PROTOTYPES = YES;', 4);
  1466. this.p('CLANG_WARN_SUSPICIOUS_MOVE = YES;', 4);
  1467. this.p('CLANG_WARN_UNREACHABLE_CODE = YES;', 4);
  1468. this.p('CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;', 4);
  1469. if (platform === 'ios') {
  1470. this.p('"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";', 4);
  1471. }
  1472. else {
  1473. this.p('CODE_SIGN_IDENTITY = "-";', 4);
  1474. // this.p('"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";', 4);
  1475. }
  1476. this.p('COPY_PHASE_STRIP = YES;', 4);
  1477. if (platform === 'macos') {
  1478. this.p('DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";', 4);
  1479. }
  1480. this.p('ENABLE_NS_ASSERTIONS = NO;', 4);
  1481. this.p('ENABLE_STRICT_OBJC_MSGSEND = YES;', 4);
  1482. this.p('GCC_C_LANGUAGE_STANDARD = "' + project.cStd + '";', 4);
  1483. this.p('GCC_NO_COMMON_BLOCKS = YES;', 4);
  1484. this.p('GCC_PREPROCESSOR_DEFINITIONS = (', 4);
  1485. this.p('NDEBUG,', 5);
  1486. for (let define of project.getDefines()) {
  1487. if (define.indexOf('=') >= 0)
  1488. this.p('"' + define.replace(/\"/g, '\\\\\\"') + '",', 5);
  1489. else
  1490. this.p(define + ',', 5);
  1491. }
  1492. this.p('"$(inherited)",', 5);
  1493. this.p(');', 4);
  1494. this.p('GCC_WARN_64_TO_32_BIT_CONVERSION = YES;', 4);
  1495. this.p('GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;', 4);
  1496. this.p('GCC_WARN_UNDECLARED_SELECTOR = YES;', 4);
  1497. this.p('GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;', 4);
  1498. this.p('GCC_WARN_UNUSED_FUNCTION = YES;', 4);
  1499. this.p('GCC_WARN_UNUSED_VARIABLE = YES;', 4);
  1500. if (platform === 'ios') {
  1501. this.p('IPHONEOS_DEPLOYMENT_TARGET = 16.0;', 4);
  1502. }
  1503. else {
  1504. this.p('MACOSX_DEPLOYMENT_TARGET = 13.0;', 4);
  1505. }
  1506. this.p('MTL_ENABLE_DEBUG_INFO = NO;', 4);
  1507. this.p('ONLY_ACTIVE_ARCH = YES;', 4);
  1508. if (platform === 'ios') {
  1509. this.p('SDKROOT = iphoneos;', 4);
  1510. this.p('TARGETED_DEVICE_FAMILY = "1,2";', 4);
  1511. this.p('VALIDATE_PRODUCT = YES;', 4);
  1512. }
  1513. else {
  1514. this.p('SDKROOT = macosx;', 4);
  1515. }
  1516. this.p('};', 3);
  1517. this.p('name = Release;', 3);
  1518. this.p('};', 2);
  1519. this.p(nativeDebugId + ' /* Debug */ = {', 2);
  1520. this.p('isa = XCBuildConfiguration;', 3);
  1521. this.p('buildSettings = {', 3);
  1522. this.p('ARCHS = arm64;', 4);
  1523. this.p('ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;', 4);
  1524. this.p('CODE_SIGN_STYLE = Automatic;', 4);
  1525. if (platform === 'macos') {
  1526. this.p('COMBINE_HIDPI_IMAGES = YES;', 4);
  1527. }
  1528. this.p('ENABLE_HARDENED_RUNTIME = YES;', 4);
  1529. this.p('FRAMEWORK_SEARCH_PATHS = (', 4);
  1530. this.p('"$(inherited)",', 5);
  1531. // Search paths to local frameworks
  1532. for (let framework of frameworks) {
  1533. if (framework.localPath != null)
  1534. this.p(framework.localPath.substr(0, framework.localPath.lastIndexOf('/')) + ',', 5);
  1535. }
  1536. this.p(');', 4);
  1537. this.p('HEADER_SEARCH_PATHS = (', 4);
  1538. this.p('"$(inherited)",', 5);
  1539. this.p('"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include",', 5);
  1540. for (let projectpath of project.getIncludeDirs())
  1541. this.p('"' + path_resolve(from, projectpath).replace(/ /g, '\\\\ ') + '",', 5);
  1542. this.p(');', 4);
  1543. this.p('LIBRARY_SEARCH_PATHS = (', 4);
  1544. for (let framework of frameworks) {
  1545. if ((framework.toString().endsWith('.dylib') || framework.toString().endsWith('.a')) && framework.localPath != null) {
  1546. this.p(framework.localPath.substr(0, framework.localPath.lastIndexOf('/')) + ',', 5);
  1547. }
  1548. }
  1549. this.p(');', 4);
  1550. this.p('INFOPLIST_EXPAND_BUILD_SETTINGS = "YES";', 4);
  1551. this.p('INFOPLIST_FILE = "' + path_resolve(from, plistname) + '";', 4);
  1552. this.p('LD_RUNPATH_SEARCH_PATHS = (', 4);
  1553. this.p('"$(inherited)",', 5);
  1554. if (platform === 'ios') {
  1555. this.p('"@executable_path/Frameworks",', 5);
  1556. }
  1557. for (let framework of frameworks) {
  1558. if (framework.toString().endsWith('.dylib') && framework.localPath != null) {
  1559. this.p(framework.localPath.substr(0, framework.localPath.lastIndexOf('/')) + ',', 5);
  1560. }
  1561. }
  1562. this.p(');', 4);
  1563. if (project.cFlags.length > 0) {
  1564. this.p('OTHER_CFLAGS = (', 4);
  1565. for (let cFlag of project.cFlags) {
  1566. this.p('"' + cFlag + '",', 5);
  1567. }
  1568. this.p(');', 4);
  1569. }
  1570. if (project.cppFlags.length > 0) {
  1571. this.p('OTHER_CPLUSPLUSFLAGS = (', 4);
  1572. for (let cppFlag of project.cppFlags) {
  1573. this.p('"' + cppFlag + '",', 5);
  1574. }
  1575. this.p(');', 4);
  1576. }
  1577. this.p('PRODUCT_BUNDLE_IDENTIFIER = "' + target_options.bundle + '";', 4);
  1578. this.p('BUNDLE_VERSION = "' + target_options.version + '";', 4);
  1579. this.p('BUILD_VERSION = "' + target_options.build + '";', 4);
  1580. this.p('CODE_SIGN_IDENTITY = "-";', 4);
  1581. this.p('PRODUCT_NAME = "$(TARGET_NAME)";', 4);
  1582. this.p('};', 3);
  1583. this.p('name = Debug;', 3);
  1584. this.p('};', 2);
  1585. this.p(nativeReleaseId + ' /* Release */ = {', 2);
  1586. this.p('isa = XCBuildConfiguration;', 3);
  1587. this.p('buildSettings = {', 3);
  1588. this.p('ARCHS = arm64;', 4);
  1589. this.p('ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;', 4);
  1590. this.p('CODE_SIGN_STYLE = Automatic;', 4);
  1591. if (platform === 'macos') {
  1592. this.p('COMBINE_HIDPI_IMAGES = YES;', 4);
  1593. }
  1594. this.p('ENABLE_HARDENED_RUNTIME = YES;', 4);
  1595. this.p('FRAMEWORK_SEARCH_PATHS = (', 4);
  1596. this.p('"$(inherited)",', 5);
  1597. // Search paths to local frameworks
  1598. for (let framework of frameworks) {
  1599. if (framework.localPath != null)
  1600. this.p(framework.localPath.substr(0, framework.localPath.lastIndexOf('/')) + ',', 5);
  1601. }
  1602. this.p(');', 4);
  1603. this.p('HEADER_SEARCH_PATHS = (', 4);
  1604. this.p('"$(inherited)",', 5);
  1605. this.p('"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include",', 5);
  1606. for (let p of project.getIncludeDirs())
  1607. this.p('"' + path_resolve(from, p).replace(/ /g, '\\\\ ') + '",', 5);
  1608. this.p(');', 4);
  1609. this.p('LIBRARY_SEARCH_PATHS = (', 4);
  1610. for (let framework of frameworks) {
  1611. if ((framework.toString().endsWith('.dylib') || framework.toString().endsWith('.a')) && framework.localPath != null) {
  1612. this.p(framework.localPath.substr(0, framework.localPath.lastIndexOf('/')) + ',', 5);
  1613. }
  1614. }
  1615. this.p(');', 4);
  1616. this.p('INFOPLIST_EXPAND_BUILD_SETTINGS = "YES";', 4);
  1617. this.p('INFOPLIST_FILE = "' + path_resolve(from, plistname) + '";', 4);
  1618. this.p('LD_RUNPATH_SEARCH_PATHS = (', 4);
  1619. this.p('"$(inherited)",', 5);
  1620. if (platform === 'ios') {
  1621. this.p('"@executable_path/Frameworks",', 5);
  1622. }
  1623. for (let framework of frameworks) {
  1624. if (framework.toString().endsWith('.dylib') && framework.localPath != null) {
  1625. this.p(framework.localPath.substr(0, framework.localPath.lastIndexOf('/')) + ',', 5);
  1626. }
  1627. }
  1628. this.p(');', 4);
  1629. if (project.cFlags.length > 0) {
  1630. this.p('OTHER_CFLAGS = (', 4);
  1631. for (let cFlag of project.cFlags) {
  1632. this.p('"' + cFlag + '",', 5);
  1633. }
  1634. this.p(');', 4);
  1635. }
  1636. if (project.cppFlags.length > 0) {
  1637. this.p('OTHER_CPLUSPLUSFLAGS = (', 4);
  1638. for (let cppFlag of project.cppFlags) {
  1639. this.p('"' + cppFlag + '",', 5);
  1640. }
  1641. this.p(');', 4);
  1642. }
  1643. this.p('PRODUCT_BUNDLE_IDENTIFIER = "' + target_options.bundle + '";', 4);
  1644. this.p('BUNDLE_VERSION = "' + target_options.version + '";', 4);
  1645. this.p('BUILD_VERSION = "' + target_options.build + '";', 4);
  1646. this.p('CODE_SIGN_IDENTITY = "-";', 4);
  1647. this.p('PRODUCT_NAME = "$(TARGET_NAME)";', 4);
  1648. this.p('};', 3);
  1649. this.p('name = Release;', 3);
  1650. this.p('};', 2);
  1651. this.p('/* End XCBuildConfiguration section */');
  1652. this.p();
  1653. this.p('/* Begin XCConfigurationList section */');
  1654. this.p(projectBuildConfigListId + ' /* Build configuration list for PBXProject "' + project.get_safe_name() + '" */ = {', 2);
  1655. this.p('isa = XCConfigurationList;', 3);
  1656. this.p('buildConfigurations = (', 3);
  1657. this.p(debugId + ' /* Debug */,', 4);
  1658. this.p(releaseId + ' /* Release */,', 4);
  1659. this.p(');', 3);
  1660. this.p('defaultConfigurationIsVisible = 0;', 3);
  1661. this.p('defaultConfigurationName = Release;', 3);
  1662. this.p('};', 2);
  1663. this.p(nativeBuildConfigListId + ' /* Build configuration list for PBXNativeTarget "' + project.get_safe_name() + '" */ = {', 2);
  1664. this.p('isa = XCConfigurationList;', 3);
  1665. this.p('buildConfigurations = (', 3);
  1666. this.p(nativeDebugId + ' /* Debug */,', 4);
  1667. this.p(nativeReleaseId + ' /* Release */,', 4);
  1668. this.p(');', 3);
  1669. this.p('defaultConfigurationIsVisible = 0;', 3);
  1670. this.p('defaultConfigurationName = Release;', 3);
  1671. this.p('};', 2);
  1672. this.p('/* End XCConfigurationList section */');
  1673. this.p('};', 1);
  1674. this.p('rootObject = ' + projectId + ' /* Project object */;', 1);
  1675. this.p('}');
  1676. this.close_file();
  1677. }
  1678. }
  1679. class MakeExporter extends Exporter {
  1680. constructor(ccompiler, cppcompiler, cFlags, cppFlags, linkerFlags, outputExtension, libsLine = null) {
  1681. super();
  1682. if (ccompiler == "tcc") {
  1683. let tccdir = makedir + "/tcc"
  1684. linkerFlags = "-lc -lm -pthread";
  1685. ccompiler = tccdir + "/bin/" + sys_dir() + "/tcc";
  1686. ccompiler += " -DSTBI_NO_SIMD -DSINFL_NO_SIMD -DIRON_NOSIMD -w";
  1687. ccompiler += " -I" + tccdir + "/include -B" + tccdir + "/bin/" + sys_dir();
  1688. cppcompiler = ccompiler;
  1689. }
  1690. this.ccompiler = ccompiler;
  1691. this.cppcompiler = cppcompiler;
  1692. this.cFlags = cFlags;
  1693. this.cppFlags = cppFlags;
  1694. this.linkerFlags = linkerFlags;
  1695. this.outputExtension = outputExtension;
  1696. this.cFlags += " -Wno-incompatible-pointer-types";
  1697. if (libsLine != null) {
  1698. this.libsLine = libsLine;
  1699. }
  1700. }
  1701. libsLine(project) {
  1702. let libs = "";
  1703. for (let lib of project.getLibs()) {
  1704. libs += " -l" + lib;
  1705. }
  1706. return libs;
  1707. }
  1708. export_solution(project) {
  1709. let from = path_resolve(".");
  1710. let to = path_resolve("build");
  1711. let objects = {};
  1712. let ofiles = {};
  1713. let output_path = path_resolve(to, goptions.build_path);
  1714. fs_ensuredir(output_path);
  1715. for (let fileobject of project.getFiles()) {
  1716. let file = fileobject.file;
  1717. if (file.endsWith(".cpp") || file.endsWith(".c") || file.endsWith(".cc")) {
  1718. let name = file.toLowerCase();
  1719. if (name.indexOf("/") >= 0) {
  1720. name = name.substr(name.lastIndexOf("/") + 1);
  1721. }
  1722. name = name.substr(0, name.lastIndexOf("."));
  1723. if (!objects[name]) {
  1724. objects[name] = true;
  1725. ofiles[file] = name;
  1726. }
  1727. else {
  1728. while (objects[name]) {
  1729. name = name + "_";
  1730. }
  1731. objects[name] = true;
  1732. ofiles[file] = name;
  1733. }
  1734. }
  1735. }
  1736. let ofilelist = "";
  1737. for (let o in objects) {
  1738. ofilelist += o + ".o ";
  1739. }
  1740. this.write_file(path_resolve(output_path, "makefile"));
  1741. let incline = "-I./ "; // local directory to pick up the precompiled headers
  1742. for (let inc of project.getIncludeDirs()) {
  1743. inc = path_relative(output_path, path_resolve(from, inc));
  1744. incline += "-I" + inc + " ";
  1745. }
  1746. this.p("INC=" + incline);
  1747. this.p("LIB=" + this.linkerFlags + this.libsLine(project));
  1748. let defline = "";
  1749. for (let def of project.getDefines()) {
  1750. defline += "-D" + def.replace(/\"/g, '\\"') + " ";
  1751. }
  1752. if (!goptions.debug) {
  1753. defline += "-DNDEBUG ";
  1754. }
  1755. this.p("DEF=" + defline);
  1756. this.p();
  1757. let cline = this.cFlags;
  1758. cline += " -std=" + project.cStd + " ";
  1759. for (let flag of project.cFlags) {
  1760. cline += flag + ' ';
  1761. }
  1762. this.p("CFLAGS=" + cline);
  1763. let cppline = this.cppFlags;
  1764. cppline += " -std=" + project.cppStd + " ";
  1765. for (let flag of project.cppFlags) {
  1766. cppline += flag + " ";
  1767. }
  1768. this.p("CPPFLAGS=" + cppline);
  1769. let optimization = "";
  1770. if (!goptions.debug) {
  1771. optimization = "-O2";
  1772. }
  1773. else
  1774. optimization = "-g";
  1775. let executable_name = project.get_safe_name();
  1776. if (project.get_executable_name()) {
  1777. executable_name = project.get_executable_name();
  1778. }
  1779. this.p(executable_name + this.outputExtension + ": " + ofilelist);
  1780. let output = '-o "' + executable_name + this.outputExtension + '"';
  1781. this.p('\t' + this.cppcompiler + ' ' + output + ' ' + optimization + ' ' + ofilelist + ' $(LIB)');
  1782. for (let fileobject of project.getFiles()) {
  1783. let file = fileobject.file;
  1784. if (file.endsWith(".c") || file.endsWith(".cpp") || file.endsWith(".cc")) {
  1785. this.p();
  1786. let name = ofiles[file];
  1787. let realfile = path_relative(output_path, path_resolve(from, file));
  1788. this.p("-include " + name + ".d");
  1789. this.p(name + ".o: " + realfile);
  1790. let compiler = this.cppcompiler;
  1791. let flags = '$(CPPFLAGS)';
  1792. if (file.endsWith(".c")) {
  1793. compiler = this.ccompiler;
  1794. flags = '$(CFLAGS)';
  1795. }
  1796. this.p('\t' + compiler + ' ' + optimization + ' $(INC) $(DEF) -MD ' + flags + ' -c ' + realfile + ' -o ' + name + '.o');
  1797. }
  1798. }
  1799. this.close_file();
  1800. }
  1801. }
  1802. class LinuxExporter extends Exporter {
  1803. constructor() {
  1804. super();
  1805. let compilerFlags = "";
  1806. let linkerFlags = "-static-libgcc -static-libstdc++ -pthread";
  1807. if (goptions.ccompiler == "gcc") {
  1808. compilerFlags += "-flto";
  1809. linkerFlags += " -flto";
  1810. }
  1811. this.make = new MakeExporter(goptions.ccompiler, goptions.cppcompiler, compilerFlags, compilerFlags, linkerFlags, '');
  1812. this.compile_commands = new CompilerCommandsExporter();
  1813. }
  1814. export_solution(project) {
  1815. this.make.export_solution(project);
  1816. this.compile_commands.export_solution(project);
  1817. }
  1818. }
  1819. class AndroidExporter extends Exporter {
  1820. constructor() {
  1821. super();
  1822. this.compile_commands = new CompilerCommandsExporter();
  1823. }
  1824. export_solution(project) {
  1825. let from = path_resolve(".");
  1826. let to = path_resolve("build");
  1827. this.safe_name = project.get_safe_name();
  1828. let outdir = path_join(to.toString(), this.safe_name);
  1829. fs_ensuredir(outdir);
  1830. let target_options = {
  1831. package : "org.armory3d",
  1832. installLocation : "internalOnly",
  1833. versionCode : 1,
  1834. versionName : "1.0",
  1835. compileSdkVersion : 33,
  1836. minSdkVersion : 24,
  1837. targetSdkVersion : 33,
  1838. screenOrientation : "sensor",
  1839. permissions : [],
  1840. disableStickyImmersiveMode : false,
  1841. metadata : [],
  1842. abiFilters : []
  1843. };
  1844. if (project.target_options != null && project.target_options.android != null) {
  1845. let userOptions = project.target_options.android;
  1846. for (let key in userOptions) {
  1847. if (userOptions[key] == null)
  1848. continue;
  1849. switch (key) {
  1850. default:
  1851. target_options[key] = userOptions[key];
  1852. }
  1853. }
  1854. }
  1855. fs_writefile(path_join(outdir, 'build.gradle.kts'), get_text_data('android/build.gradle.kts'));
  1856. fs_writefile(path_join(outdir, 'gradle.properties'), get_text_data('android/gradle.properties'));
  1857. fs_writefile(path_join(outdir, 'gradlew'), get_text_data('android/gradlew'));
  1858. if (os_platform() !== 'win32') {
  1859. os_chmod(path_join(outdir, 'gradlew'), "+x");
  1860. }
  1861. fs_writefile(path_join(outdir, 'gradlew.bat'), get_text_data('android/gradlew.bat'));
  1862. let settings = get_text_data('android/settings.gradle.kts');
  1863. settings = settings.replace(/{name}/g, project.getName());
  1864. fs_writefile(path_join(outdir, 'settings.gradle.kts'), settings);
  1865. fs_ensuredir(path_join(outdir, 'app'));
  1866. fs_writefile(path_join(outdir, 'app', 'proguard-rules.pro'), get_text_data('android/app/proguard-rules.pro'));
  1867. this.write_app_gradle(project, outdir, from, target_options);
  1868. this.write_cmake_lists(project, outdir, from);
  1869. fs_ensuredir(path_join(outdir, 'app', 'src'));
  1870. fs_ensuredir(path_join(outdir, 'app', 'src', 'main'));
  1871. this.write_manifest(outdir, target_options);
  1872. let strings = get_text_data('android/main/res/values/strings.xml');
  1873. strings = strings.replace(/{name}/g, project.getName());
  1874. fs_ensuredir(path_join(outdir, 'app', 'src', 'main', 'res', 'values'));
  1875. fs_writefile(path_join(outdir, 'app', 'src', 'main', 'res', 'values', 'strings.xml'), strings);
  1876. this.export_icons(project.icon, outdir, from, to);
  1877. fs_ensuredir(path_join(outdir, 'gradle', 'wrapper'));
  1878. fs_writefile(path_join(outdir, 'gradle', 'wrapper', 'gradle-wrapper.jar'), get_binary_data('android/gradle/wrapper/gradle-wrapper.jar'));
  1879. fs_writefile(path_join(outdir, 'gradle', 'wrapper', 'gradle-wrapper.properties'), get_text_data('android/gradle/wrapper/gradle-wrapper.properties'));
  1880. fs_copydir(path_resolve(from, project.get_debug_dir()), path_resolve(to, this.safe_name, 'app', 'src', 'main', 'assets'));
  1881. this.compile_commands.export_solution(project);
  1882. }
  1883. write_app_gradle(project, outdir, from, target_options) {
  1884. let cflags = '';
  1885. for (let flag of project.cFlags)
  1886. cflags += flag + ' ';
  1887. let cppflags = '';
  1888. for (let flag of project.cppFlags)
  1889. cppflags += flag + ' ';
  1890. let gradle = get_text_data('android/app/build.gradle.kts');
  1891. gradle = gradle.replace(/{package}/g, target_options.package);
  1892. gradle = gradle.replace(/{versionCode}/g, target_options.versionCode.toString());
  1893. gradle = gradle.replace(/{versionName}/g, target_options.versionName);
  1894. gradle = gradle.replace(/{compileSdkVersion}/g, target_options.compileSdkVersion.toString());
  1895. gradle = gradle.replace(/{minSdkVersion}/g, target_options.minSdkVersion.toString());
  1896. gradle = gradle.replace(/{targetSdkVersion}/g, target_options.targetSdkVersion.toString());
  1897. let arch = '';
  1898. if (target_options.abiFilters.length > 0) {
  1899. for (let item of target_options.abiFilters) {
  1900. if (arch.length === 0) {
  1901. arch = '"' + item + '"';
  1902. }
  1903. else {
  1904. arch = arch + ', "' + item + '"';
  1905. }
  1906. }
  1907. arch = `ndk { abiFilters += listOf(${arch}) }`;
  1908. }
  1909. else {
  1910. switch (goptions.arch) {
  1911. case 'default':
  1912. arch = '';
  1913. break;
  1914. case 'arm8':
  1915. arch = 'arm64-v8a';
  1916. break;
  1917. }
  1918. if (goptions.arch !== 'default') {
  1919. arch = `ndk {abiFilters += listOf("${arch}")}`;
  1920. }
  1921. }
  1922. gradle = gradle.replace(/{architecture}/g, arch);
  1923. // Looks like these should go into CMakeLists.txt now..
  1924. // gradle = gradle.replace(/{cflags}/g, cflags);
  1925. // cppflags = '-frtti -fexceptions ' + cppflags;
  1926. // cppflags = '-std=' + project.cppStd + ' ' + cppflags;
  1927. // gradle = gradle.replace(/{cppflags}/g, cppflags);
  1928. let javasources = '';
  1929. for (let dir of project.getJavaDirs()) {
  1930. javasources += '"' + path_relative(path_join(outdir, 'app'), path_resolve(from, dir)).replace(/\\/g, '/') + '", ';
  1931. }
  1932. javasources += '"' + path_join(irondir, 'sources', 'backends', 'data', 'android_java').replace(/\\/g, '/') + '"';
  1933. gradle = gradle.replace(/{javasources}/g, javasources);
  1934. fs_writefile(path_join(outdir, 'app', 'build.gradle.kts'), gradle);
  1935. }
  1936. write_cmake_lists(project, outdir, from) {
  1937. let cmake = get_text_data('android/app/CMakeLists.txt');
  1938. let debugDefines = '';
  1939. for (let def of project.getDefines()) {
  1940. debugDefines += ' -D' + def.replace(/\"/g, '\\\\\\\"');
  1941. }
  1942. cmake = cmake.replace(/{debug_defines}/g, debugDefines);
  1943. let releaseDefines = '';
  1944. for (let def of project.getDefines()) {
  1945. releaseDefines += ' -D' + def.replace(/\"/g, '\\\\\\\"');
  1946. }
  1947. cmake = cmake.replace(/{release_defines}/g, releaseDefines);
  1948. let includes = '';
  1949. for (let inc of project.getIncludeDirs()) {
  1950. includes += ' "' + path_resolve(inc).replace(/\\/g, '/') + '"\n';
  1951. }
  1952. cmake = cmake.replace(/{includes}/g, includes);
  1953. let files = '';
  1954. for (let file of project.getFiles()) {
  1955. if (file.file.endsWith('.c') || file.file.endsWith('.cc') || file.file.endsWith('.cpp') || file.file.endsWith('.h')) {
  1956. if (path_isabs(file.file)) {
  1957. files += ' "' + path_resolve(file.file).replace(/\\/g, '/') + '"\n';
  1958. }
  1959. else {
  1960. files += ' "' + path_resolve(path_join(from, file.file)).replace(/\\/g, '/') + '"\n';
  1961. }
  1962. }
  1963. }
  1964. cmake = cmake.replace(/{files}/g, files);
  1965. let libraries1 = '';
  1966. let libraries2 = '';
  1967. for (let lib of project.getLibs()) {
  1968. libraries1 += 'find_library(' + lib + '-lib ' + lib + ')\n';
  1969. libraries2 += ' ${' + lib + '-lib}\n';
  1970. }
  1971. cmake = cmake.replace(/{libraries1}/g, libraries1).replace(/{libraries2}/g, libraries2);
  1972. let cmakePath = path_join(outdir, 'app', 'CMakeLists.txt');
  1973. fs_writefile(cmakePath, cmake);
  1974. }
  1975. write_manifest(outdir, target_options) {
  1976. let manifest = get_text_data('android/main/AndroidManifest.xml');
  1977. manifest = manifest.replace(/{package}/g, target_options.package);
  1978. manifest = manifest.replace(/{installLocation}/g, target_options.installLocation);
  1979. manifest = manifest.replace(/{versionCode}/g, target_options.versionCode.toString());
  1980. manifest = manifest.replace(/{versionName}/g, target_options.versionName);
  1981. manifest = manifest.replace(/{screenOrientation}/g, target_options.screenOrientation);
  1982. manifest = manifest.replace(/{targetSdkVersion}/g, target_options.targetSdkVersion);
  1983. manifest =
  1984. manifest.replace(/{permissions}/g, target_options.permissions.map((p) => { return '\n\t<uses-permission android:name="' + p + '"/>'; }).join(''));
  1985. let metadata = target_options.disableStickyImmersiveMode ? '\n\t\t<meta-data android:name="disableStickyImmersiveMode" android:value="true"/>' : '';
  1986. for (let meta of target_options.metadata) {
  1987. metadata += '\n\t\t' + meta;
  1988. }
  1989. manifest = manifest.replace(/{metadata}/g, metadata);
  1990. fs_ensuredir(path_join(outdir, 'app', 'src', 'main'));
  1991. fs_writefile(path_join(outdir, 'app', 'src', 'main', 'AndroidManifest.xml'), manifest);
  1992. }
  1993. export_icons(icon, outdir, from, to) {
  1994. let folders = [ 'mipmap-mdpi', 'mipmap-hdpi', 'mipmap-xhdpi', 'mipmap-xxhdpi', 'mipmap-xxxhdpi' ];
  1995. let dpis = [ 48, 72, 96, 144, 192 ];
  1996. for (let i = 0; i < dpis.length; ++i) {
  1997. let folder = folders[i];
  1998. let dpi = dpis[i];
  1999. fs_ensuredir(path_join(outdir, 'app', 'src', 'main', 'res', folder));
  2000. export_png_icon(icon, path_resolve(to, this.safe_name, 'app', 'src', 'main', 'res', folder, 'ic_launcher.png'), dpi, dpi, from);
  2001. export_png_icon(icon, path_resolve(to, this.safe_name, 'app', 'src', 'main', 'res', folder, 'ic_launcher_round.png'), dpi, dpi, from);
  2002. }
  2003. }
  2004. }
  2005. class CompilerCommandsExporter extends Exporter {
  2006. constructor() {
  2007. super();
  2008. }
  2009. export_solution(project) {
  2010. let from = path_resolve(".");
  2011. let to = path_resolve("build");
  2012. let platform = goptions.target;
  2013. from = path_resolve(os_cwd(), from);
  2014. this.write_file(path_resolve(to, 'compile_commands.json'));
  2015. let includes = [];
  2016. for (let inc of project.getIncludeDirs()) {
  2017. includes.push('-I');
  2018. includes.push(path_resolve(from, inc));
  2019. }
  2020. let defines = [];
  2021. for (let def of project.getDefines()) {
  2022. defines.push('-D');
  2023. defines.push(def.replace(/\"/g, '\\"'));
  2024. }
  2025. let objects = {};
  2026. let ofiles = {};
  2027. for (let fileobject of project.getFiles()) {
  2028. let file = fileobject.file;
  2029. if (file.endsWith('.cpp') || file.endsWith('.c') || file.endsWith('.cc')) {
  2030. let name = file.toLowerCase();
  2031. if (name.indexOf('/') >= 0)
  2032. name = name.substr(name.lastIndexOf('/') + 1);
  2033. name = name.substr(0, name.lastIndexOf('.'));
  2034. if (!objects[name]) {
  2035. objects[name] = true;
  2036. ofiles[file] = name;
  2037. }
  2038. else {
  2039. while (objects[name]) {
  2040. name = name + '_';
  2041. }
  2042. objects[name] = true;
  2043. ofiles[file] = name;
  2044. }
  2045. }
  2046. }
  2047. let default_args = [];
  2048. if (platform === 'android') {
  2049. default_args.push('--target=aarch64-none-linux-android21');
  2050. default_args.push('-DANDROID');
  2051. function ndkFromSdkRoot() {
  2052. let _a = os_env('ANDROID_HOME');
  2053. let sdkEnv = _a !== null ? _a : os_env('ANDROID_SDK_ROOT');
  2054. if (!sdkEnv)
  2055. return null;
  2056. let ndk_dir = path_join(sdkEnv, 'ndk');
  2057. if (!fs_exists(ndk_dir)) {
  2058. return null;
  2059. }
  2060. let ndks = fs_readdir(ndk_dir);
  2061. ndks = ndks.filter(item => !item.startsWith("."));
  2062. if (ndks.length < 1) {
  2063. return null;
  2064. }
  2065. return path_join(ndk_dir, ndks[0]);
  2066. }
  2067. let _a = os_env('ANDROID_NDK');
  2068. let android_ndk = _a !== null ? _a : ndkFromSdkRoot();
  2069. if (android_ndk) {
  2070. let host_tag = '';
  2071. switch (os_platform()) {
  2072. case 'linux':
  2073. host_tag = 'linux-x86_64';
  2074. break;
  2075. case 'darwin':
  2076. host_tag = 'darwin-x86_64';
  2077. break;
  2078. case 'win32':
  2079. host_tag = 'windows-x86_64';
  2080. break;
  2081. }
  2082. let ndk_toolchain = path_join(android_ndk, `toolchains/llvm/prebuilt/${host_tag}`);
  2083. if (host_tag !== '' && fs_exists(ndk_toolchain)) {
  2084. default_args.push(`--gcc-toolchain=${ndk_toolchain}`);
  2085. default_args.push(`--sysroot=${ndk_toolchain}/sysroot`);
  2086. }
  2087. else {
  2088. // fallback to the first found toolchain
  2089. let toolchains = fs_readdir(path_join(android_ndk, `toolchains/llvm/prebuilt/`));
  2090. if (toolchains.length > 0) {
  2091. let host_tag = toolchains[0];
  2092. let ndk_toolchain = path_join(android_ndk, `toolchains/llvm/prebuilt/${host_tag}`);
  2093. default_args.push(`--gcc-toolchain=${ndk_toolchain}`);
  2094. default_args.push(`--sysroot=${ndk_toolchain}/sysroot`);
  2095. console.log(`Found android ndk toolchain in ${ndk_toolchain}.`);
  2096. }
  2097. }
  2098. }
  2099. }
  2100. let commands = [];
  2101. for (let fileobject of project.getFiles()) {
  2102. let file = fileobject.file;
  2103. if (file.endsWith('.c') || file.endsWith('.cpp') || file.endsWith('.cc')) {
  2104. let args = [ '/usr/bin/clang', '-c', '-o', (goptions.debug ? 'Debug' : 'Release') + ofiles[file] + '.o' ];
  2105. if (file.endsWith('.c')) {
  2106. args.push('-std=c99');
  2107. }
  2108. args.push(...default_args);
  2109. args.push(path_resolve(from, file));
  2110. let command = {
  2111. directory : from,
  2112. file : path_resolve(from, file),
  2113. output : path_resolve(to, ofiles[file] + '.o'),
  2114. arguments : args.concat(includes).concat(defines)
  2115. };
  2116. commands.push(command);
  2117. }
  2118. }
  2119. this.p(JSON.stringify(commands));
  2120. this.close_file();
  2121. }
  2122. }
  2123. // ███╗ ███╗ █████╗ ██╗ ██╗███████╗
  2124. // ████╗ ████║██╔══██╗██║ ██╔╝██╔════╝
  2125. // ██╔████╔██║███████║█████╔╝ █████╗
  2126. // ██║╚██╔╝██║██╔══██║██╔═██╗ ██╔══╝
  2127. // ██║ ╚═╝ ██║██║ ██║██║ ██╗███████╗
  2128. // ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝
  2129. function export_ico(icon, to, from) {
  2130. if (!fs_exists(path_join(from, icon))) {
  2131. from = irondir;
  2132. icon = "icon.png";
  2133. }
  2134. if (fs_exists(to) && fs_mtime(to) > fs_mtime(from)) {
  2135. return;
  2136. }
  2137. amake.export_ico(path_join(from, icon), to);
  2138. }
  2139. function export_png_icon(icon, to, width, height, from) {
  2140. if (!fs_exists(path_join(from, icon))) {
  2141. from = irondir;
  2142. icon = "icon.png";
  2143. }
  2144. if (fs_exists(to) && fs_mtime(to) > fs_mtime(from)) {
  2145. return;
  2146. }
  2147. amake.export_png(path_join(from, icon), to, width, height);
  2148. }
  2149. function contains_define(array, value) {
  2150. return array.indexOf(value) > -1;
  2151. }
  2152. function contains_fancy_define(array, value) {
  2153. let name = value.substring(0, value.indexOf("="));
  2154. for (let element of array) {
  2155. let index = element.indexOf("=");
  2156. if (index >= 0) {
  2157. let otherName = element.substring(0, index);
  2158. if (name === otherName) {
  2159. return true;
  2160. }
  2161. }
  2162. }
  2163. return false;
  2164. }
  2165. function load_project(directory, is_root_project) {
  2166. __dirname = path_resolve(directory);
  2167. if (is_root_project) {
  2168. globalThis.platform = goptions.target;
  2169. globalThis.graphics = goptions.graphics;
  2170. globalThis.flags = {
  2171. name : "Armory",
  2172. package : "org.armory3d",
  2173. dirname : __dirname,
  2174. release : os_argv().indexOf("--debug") == -1,
  2175. embed : false,
  2176. with_physics : false,
  2177. with_d3dcompiler : false,
  2178. with_nfd : false,
  2179. with_compress : false,
  2180. with_image_write : false,
  2181. with_video_write : false,
  2182. with_eval : false,
  2183. with_plugins : false,
  2184. with_kong : false,
  2185. with_raytrace : false,
  2186. idle_sleep : false,
  2187. export_version_info : false,
  2188. export_data_list : false
  2189. };
  2190. }
  2191. let project = eval("function _(){" + fs_readfile(path_resolve(directory, "project.js")) + "} _();");
  2192. if (is_root_project) {
  2193. try {
  2194. export_iron_project(project, goptions);
  2195. } catch (error) {
  2196. console.log(error);
  2197. os_exit(1);
  2198. }
  2199. }
  2200. return project;
  2201. }
  2202. function search_files2(current_dir, pattern) {
  2203. let result = [];
  2204. if (!fs_exists(current_dir)) {
  2205. return result;
  2206. }
  2207. current_dir = path_join(current_dir); ////
  2208. let files = fs_readdir(current_dir);
  2209. for (let f in files) {
  2210. let file = path_join(current_dir, files[f]);
  2211. if (fs_isdir(file))
  2212. continue;
  2213. file = path_relative(current_dir, file);
  2214. if (matches(stringify(file), stringify(pattern))) {
  2215. result.push(path_join(current_dir, stringify(file)));
  2216. }
  2217. }
  2218. if (pattern.endsWith("**")) {
  2219. let dirs = fs_readdir(current_dir);
  2220. for (let d of dirs) {
  2221. let dir = path_join(current_dir, d);
  2222. if (d.startsWith('.'))
  2223. continue;
  2224. if (!fs_isdir(dir))
  2225. continue;
  2226. result = result.concat(search_files2(dir, pattern));
  2227. }
  2228. }
  2229. return result;
  2230. }
  2231. class AssetConverter {
  2232. constructor(exporter, options, asset_matchers) {
  2233. this.exporter = exporter;
  2234. this.options = options;
  2235. this.asset_matchers = asset_matchers;
  2236. }
  2237. static replace_pattern(pattern, value, filepath, from) {
  2238. let base_path = from;
  2239. let dir_value = path_relative(base_path, path_dirname(filepath));
  2240. if (base_path.length > 0 && base_path[base_path.length - 1] === path_sep && dir_value.length > 0 && dir_value[dir_value.length - 1] !== path_sep) {
  2241. dir_value += path_sep;
  2242. }
  2243. let dir_regex = dir_value === '' ? /{dir}\//g : /{dir}/g;
  2244. return pattern.replace(/{name}/g, value).replace(dir_regex, dir_value);
  2245. }
  2246. static create_export_info(filepath, keep_ext, options, from) {
  2247. let name_value = path_basename_noext(filepath);
  2248. let destination = path_basename_noext(filepath);
  2249. if (keep_ext || options.noprocessing) {
  2250. destination += path_extname(filepath);
  2251. }
  2252. if (options.destination) {
  2253. destination = AssetConverter.replace_pattern(options.destination, destination, filepath, from);
  2254. }
  2255. if (keep_ext) {
  2256. name_value += path_extname(filepath);
  2257. }
  2258. if (options.name) {
  2259. name_value = AssetConverter.replace_pattern(options.name, name_value, filepath, from);
  2260. }
  2261. return {name : name_value, destination : path_normalize(destination)};
  2262. }
  2263. watch(match, options) {
  2264. match = path_normalize(match);
  2265. let basedir = match.substring(0, match.lastIndexOf(path_sep));
  2266. let pattern = match;
  2267. if (path_isabs(pattern)) {
  2268. pattern = path_relative(basedir, pattern);
  2269. }
  2270. let files = search_files2(basedir, pattern);
  2271. let self = this;
  2272. let parsed_files = [];
  2273. let index = 0;
  2274. for (let file of files) {
  2275. console.log('Exporting asset ' + (index + 1) + ' of ' + files.length + ' (' + path_basename(file) + ').');
  2276. let ext = path_extname(file).toLowerCase();
  2277. switch (ext) {
  2278. case '.png':
  2279. case '.jpg':
  2280. case '.hdr': {
  2281. let export_info = AssetConverter.create_export_info(file, false, options, ".");
  2282. let images;
  2283. if (options.noprocessing) {
  2284. images = self.exporter.copy_blob(file, export_info.destination, globalThis.flags.embed && !options.noembed);
  2285. }
  2286. else {
  2287. images = self.exporter.copy_image(file, export_info.destination, globalThis.flags.embed && !options.noembed);
  2288. }
  2289. parsed_files.push({
  2290. name : export_info.name,
  2291. from : file,
  2292. type : 'image',
  2293. files : images,
  2294. original_width : options.original_width,
  2295. original_height : options.original_height,
  2296. noembed : options.noembed
  2297. });
  2298. break;
  2299. }
  2300. default: {
  2301. let export_info = AssetConverter.create_export_info(file, true, options, ".");
  2302. let blobs = self.exporter.copy_blob(file, export_info.destination, globalThis.flags.embed && !options.noembed);
  2303. parsed_files.push({
  2304. name : export_info.name,
  2305. from : file,
  2306. type : 'blob',
  2307. files : blobs,
  2308. original_width : undefined,
  2309. original_height : undefined,
  2310. noembed : options.noembed
  2311. });
  2312. break;
  2313. }
  2314. }
  2315. index += 1;
  2316. }
  2317. return parsed_files;
  2318. }
  2319. run() {
  2320. let files = [];
  2321. for (let matcher of this.asset_matchers) {
  2322. files = files.concat(this.watch(matcher.match, matcher.options));
  2323. }
  2324. return files;
  2325. }
  2326. }
  2327. class CompiledShader {
  2328. constructor() {
  2329. this.files = [];
  2330. }
  2331. }
  2332. function shader_find_type(options) {
  2333. if (options.graphics === 'vulkan') {
  2334. return 'spirv';
  2335. }
  2336. else if (options.graphics === 'metal') {
  2337. return 'metal';
  2338. }
  2339. else if (options.graphics === 'direct3d12') {
  2340. return 'hlsl';
  2341. }
  2342. else if (options.graphics === 'webgpu') {
  2343. return 'wgsl';
  2344. }
  2345. }
  2346. class ShaderCompiler {
  2347. constructor(exporter, to, temp, options, shader_matchers) {
  2348. this.exporter = exporter;
  2349. this.type = shader_find_type(options);
  2350. this.options = options;
  2351. this.to = to;
  2352. this.temp = temp;
  2353. this.shader_matchers = shader_matchers;
  2354. }
  2355. watch(match, options) {
  2356. match = path_normalize(match);
  2357. let basedir = match.substring(0, match.lastIndexOf(path_sep));
  2358. let pattern = match;
  2359. if (path_isabs(pattern)) {
  2360. pattern = path_relative(basedir, pattern);
  2361. }
  2362. let shaders = search_files2(basedir, pattern);
  2363. let self = this;
  2364. let compiled_shaders = [];
  2365. let index = 0;
  2366. for (let shader of shaders) {
  2367. console.log('Compiling shader ' + (index + 1) + ' of ' + shaders.length + ' (' + path_basename(shader) + ').');
  2368. let compiled_shader = null;
  2369. try {
  2370. compiled_shader = self.compile_shader(shader, options);
  2371. } catch (error) {
  2372. console.log('Compiling shader ' + (index + 1) + ' of ' + shaders.length + ' (' + path_basename(shader) + ') failed:');
  2373. console.log(error);
  2374. }
  2375. if (compiled_shader === null) {
  2376. compiled_shader = new CompiledShader();
  2377. }
  2378. let type = self.type;
  2379. if (type == "hlsl") {
  2380. type = "d3d11";
  2381. }
  2382. let base = path_resolve('build', 'temp', path_basename_noext(shader));
  2383. compiled_shader.files = [ base + '.vert.' + type, base + '.frag.' + type ];
  2384. compiled_shader.name = AssetConverter.create_export_info(shader, false, options, ".").name;
  2385. compiled_shaders.push(compiled_shader);
  2386. ++index;
  2387. }
  2388. return compiled_shaders;
  2389. }
  2390. run() {
  2391. let shaders = [];
  2392. for (let matcher of this.shader_matchers) {
  2393. shaders = shaders.concat(this.watch(matcher.match, matcher.options));
  2394. }
  2395. return shaders;
  2396. }
  2397. compile_shader(file, options) {
  2398. let from = file;
  2399. let to = path_join(this.to, path_basename_noext(file) + '.' + this.type);
  2400. let from_time = 0;
  2401. let to_time;
  2402. if (fs_exists(from))
  2403. from_time = fs_mtime(from);
  2404. if (fs_exists(to))
  2405. to_time = fs_mtime(to);
  2406. if (options.noprocessing) {
  2407. if (!to_time || to_time < from_time) {
  2408. fs_copyfile(from, to);
  2409. }
  2410. let compiled_shader = new CompiledShader();
  2411. return compiled_shader;
  2412. }
  2413. if (!from_time || (to_time && to_time > from_time)) {
  2414. return null;
  2415. }
  2416. else {
  2417. fs_ensuredir(this.temp);
  2418. // from = path_resolve(from);
  2419. // to = path_resolve(to);
  2420. // this.temp = path_resolve(this.temp);
  2421. amake.ashader(this.type, from, to);
  2422. let compiled_shader = new CompiledShader();
  2423. return compiled_shader;
  2424. }
  2425. }
  2426. }
  2427. function export_k(from, to) {
  2428. to += ".k";
  2429. if (fs_exists(to) && fs_mtime(to) > fs_mtime(from)) {
  2430. return "k";
  2431. }
  2432. fs_ensuredir(path_dirname(to));
  2433. amake.export_k(from, to);
  2434. }
  2435. class IronExporter {
  2436. constructor(project, options) {
  2437. this.options = options;
  2438. this.sources = [];
  2439. }
  2440. ts_options(defines) {
  2441. defines.push("arm_" + this.options.graphics);
  2442. defines.push("arm_" + goptions.target);
  2443. return {from : ".", sources : this.sources, defines : defines};
  2444. }
  2445. export() {
  2446. fs_ensuredir(path_join("build", "out"));
  2447. }
  2448. copy_image(from, to, embed) {
  2449. let to_full = path_join("build", "out", to);
  2450. if (embed) {
  2451. to_full = path_join("build", "temp", to);
  2452. }
  2453. export_k(from, to_full);
  2454. return [ to + ".k" ];
  2455. }
  2456. copy_blob(from, to, embed) {
  2457. fs_ensuredir(path_join("build", "out", path_dirname(to)));
  2458. let to_full = path_join("build", "out", to);
  2459. if (embed && !to.endsWith(".txt") && !to.endsWith(".md") && !to.endsWith(".json") && !to.endsWith(".js")) {
  2460. fs_ensuredir(path_join("build", "temp", path_dirname(to)));
  2461. to_full = path_join("build", "temp", to);
  2462. }
  2463. fs_copyfile(from, to_full);
  2464. return [ to ];
  2465. }
  2466. add_source_directory(path) {
  2467. this.sources.push(path);
  2468. }
  2469. }
  2470. function ts_contains_define(define) {
  2471. let b = false;
  2472. for (let s of globalThis.options.defines) {
  2473. if (define.includes(s)) {
  2474. b = true;
  2475. break;
  2476. };
  2477. }
  2478. if (define.includes("!")) {
  2479. b = !b;
  2480. }
  2481. return b;
  2482. }
  2483. function ts_preprocessor(file, file_path) {
  2484. let stack = [];
  2485. let found = [];
  2486. let lines = file.split("\n");
  2487. for (let i = 0; i < lines.length; ++i) {
  2488. let line = lines[i].trimStart();
  2489. if (line.startsWith("/// if")) {
  2490. let define = line.substr(6);
  2491. stack.push(ts_contains_define(define));
  2492. found.push(stack[stack.length - 1]);
  2493. }
  2494. else if (line.startsWith("/// elseif")) {
  2495. let define = line.substr(10);
  2496. if (!found[found.length - 1] && ts_contains_define(define)) {
  2497. stack[stack.length - 1] = true;
  2498. found[found.length - 1] = true;
  2499. }
  2500. else {
  2501. stack[stack.length - 1] = false;
  2502. }
  2503. }
  2504. else if (line.startsWith("/// else")) {
  2505. stack[stack.length - 1] = !found[found.length - 1];
  2506. }
  2507. else if (line.startsWith("/// end")) {
  2508. stack.pop();
  2509. found.pop();
  2510. }
  2511. else if (stack.length > 0) {
  2512. let comment = false;
  2513. for (let b of stack) {
  2514. if (!b) {
  2515. comment = true;
  2516. break;
  2517. }
  2518. }
  2519. if (comment) {
  2520. lines[i] = "///" + lines[i];
  2521. }
  2522. }
  2523. if (lines[i].indexOf("__ID__") > -1 && !lines[i].startsWith("declare")) {
  2524. // #define ID__(x, y) x ":" #y
  2525. // #define ID_(x, y) ID__(x, y)
  2526. // #define ID ID_(__FILE__, __LINE__)
  2527. lines[i] = lines[i].replace("__ID__", "\"" + path_basename(file_path) + ":" + i + "\"");
  2528. }
  2529. }
  2530. return lines.join("\n");
  2531. }
  2532. function write_ts_project(projectdir, options) {
  2533. let tsdata = {include : []};
  2534. let main_ts = null;
  2535. for (let i = 0; i < options.sources.length; ++i) {
  2536. let src = options.sources[i];
  2537. let files = fs_readdir(src);
  2538. if (src.endsWith(".ts")) {
  2539. // Add file instead of dir
  2540. files = [ src.substring(src.lastIndexOf(path_sep) + 1, src.length) ];
  2541. src = src.substring(0, src.lastIndexOf(path_sep));
  2542. }
  2543. for (let file of files) {
  2544. if (file.endsWith(".ts")) {
  2545. // Prevent duplicates, keep the newly added file
  2546. for (let included of tsdata.include) {
  2547. if (path_basename(included) == file) {
  2548. tsdata.include.splice(tsdata.include.indexOf(included), 1);
  2549. break;
  2550. }
  2551. }
  2552. tsdata.include.push(src + path_sep + file);
  2553. if (file == "main.ts") {
  2554. main_ts = src + path_sep + file;
  2555. }
  2556. }
  2557. }
  2558. }
  2559. // Include main.ts last
  2560. if (main_ts != null) {
  2561. tsdata.include.splice(tsdata.include.indexOf(main_ts), 1);
  2562. tsdata.include.push(main_ts);
  2563. }
  2564. fs_ensuredir(projectdir);
  2565. fs_writefile(path_join(projectdir, 'tsconfig.json'), JSON.stringify(tsdata, null, 4));
  2566. // alang compiler
  2567. globalThis.options = options;
  2568. let source = '';
  2569. let file_paths = tsdata.include;
  2570. for (let file_path of file_paths) {
  2571. let file = fs_readfile(file_path);
  2572. file = ts_preprocessor(file, file_path);
  2573. source += file;
  2574. }
  2575. if (goptions.alangjs) {
  2576. globalThis.std = std;
  2577. globalThis.fs_readfile = fs_readfile;
  2578. globalThis.fs_writefile = fs_writefile;
  2579. globalThis.flags.alang_source = source;
  2580. globalThis.flags.alang_output = os_cwd() + path_sep + "build" + path_sep + "iron.c";
  2581. let alang = irondir + '/tools/amake/alang.js';
  2582. (1, eval)(fs_readfile(alang));
  2583. }
  2584. else {
  2585. // let alang_input = os_cwd() + path_sep + "build" + path_sep + "iron.ts";
  2586. // fs_writefile(alang_input, source);
  2587. let alang_output = os_cwd() + path_sep + "build" + path_sep + "iron.c";
  2588. let start = Date.now();
  2589. amake.alang(source, alang_output);
  2590. console.log("alang took " + (Date.now() - start) + "ms.");
  2591. }
  2592. }
  2593. function export_project_files(name, options, exporter, defines) {
  2594. let ts_options = exporter.ts_options(defines);
  2595. write_ts_project("build", ts_options);
  2596. exporter.export();
  2597. return name;
  2598. }
  2599. function export_iron_project(project, options) {
  2600. let temp = path_join("build", "temp");
  2601. fs_ensuredir(temp);
  2602. let exporter = new IronExporter(project, options);
  2603. fs_ensuredir(path_join("build", "out"));
  2604. for (let source of project.sources) {
  2605. exporter.add_source_directory(source);
  2606. }
  2607. let asset_converter = new AssetConverter(exporter, options, project.asset_matchers);
  2608. let assets = asset_converter.run();
  2609. let shaderdir = path_join("build", "out", "data");
  2610. if (globalThis.flags.embed) {
  2611. shaderdir = path_join("build", "temp");
  2612. }
  2613. fs_ensuredir(shaderdir);
  2614. let exported_shaders = [];
  2615. let shader_compiler = new ShaderCompiler(exporter, shaderdir, temp, options, project.shader_matchers);
  2616. exported_shaders = shader_compiler.run();
  2617. // Write embed.h
  2618. if (globalThis.flags.embed) {
  2619. let embed_files = [];
  2620. for (let asset of assets) {
  2621. if (asset.noembed || asset.from.endsWith(".txt") || asset.from.endsWith(".md") || asset.from.endsWith(".json") || asset.from.endsWith(".js")) {
  2622. continue;
  2623. }
  2624. embed_files.push(path_resolve("build", "temp", asset.files[0]));
  2625. }
  2626. for (let shader of exported_shaders) {
  2627. embed_files.push(shader.files[0]);
  2628. embed_files.push(shader.files[1]);
  2629. }
  2630. if (embed_files.length > 0) {
  2631. let embed_header = "#pragma once\n";
  2632. for (let file of embed_files) {
  2633. embed_header += "const unsigned char " + path_basename(file).replaceAll(".", "_") + "[] = {\n"
  2634. if (platform === "windows") {
  2635. file = file.replaceAll("\\", "/");
  2636. }
  2637. embed_header += "#embed \"" + file + "\"\n";
  2638. embed_header += "};\n"
  2639. }
  2640. embed_header += "char *embed_keys[] = {\n"
  2641. for (let file of embed_files) {
  2642. embed_header += "\"./data/" + path_basename(file) + "\",\n";
  2643. }
  2644. embed_header += "};\n"
  2645. embed_header += "const unsigned char *embed_values[] = {\n"
  2646. for (let file of embed_files) {
  2647. embed_header += path_basename(file).replaceAll(".", "_") + ",\n";
  2648. }
  2649. embed_header += "};\n"
  2650. embed_header += "const int embed_sizes[] = {\n";
  2651. for (let file of embed_files) {
  2652. embed_header += "sizeof(" + path_basename(file).replaceAll(".", "_") + "),\n"
  2653. }
  2654. embed_header += "};\n"
  2655. embed_header += "int embed_count = " + embed_files.length + ";\n";
  2656. fs_writefile(path_join("build", "embed.h"), embed_header);
  2657. }
  2658. }
  2659. export_project_files(project.name, options, exporter, project.defines);
  2660. }
  2661. class Project {
  2662. constructor(name) {
  2663. this.cppStd = "c++17";
  2664. this.cStd = "c11";
  2665. this.cmdArgs = [];
  2666. this.cFlags = [];
  2667. this.cppFlags = [];
  2668. this.icon = "icon.png";
  2669. this.lto = true;
  2670. this.noFlatten = true;
  2671. this.name = name;
  2672. this.safe_name = name.replace(/[^A-z0-9\-\_]/g, "-");
  2673. this.version = "1.0";
  2674. this.debugdir = "build/out";
  2675. this.basedir = __dirname;
  2676. this.uuid = crypto_random_uuid();
  2677. this.files = [];
  2678. this.customs = [];
  2679. this.javadirs = [];
  2680. this.subProjects = [];
  2681. this.includedirs = [];
  2682. this.defines = [];
  2683. this.libs = [];
  2684. this.includes = [];
  2685. this.target_options = {android : {}, ios : {}};
  2686. this.executable_name = null;
  2687. this.sources = [];
  2688. this.asset_matchers = [];
  2689. this.shader_matchers = [];
  2690. }
  2691. get_executable_name() {
  2692. return this.executable_name;
  2693. }
  2694. flatten_subprojects() {
  2695. for (let sub of this.subProjects) {
  2696. sub.noFlatten = false;
  2697. sub.flatten_subprojects();
  2698. }
  2699. }
  2700. flatten() {
  2701. this.noFlatten = false;
  2702. this.flatten_subprojects();
  2703. }
  2704. internal_flatten() {
  2705. let out = [];
  2706. for (let sub of this.subProjects) {
  2707. sub.internal_flatten();
  2708. }
  2709. for (let sub of this.subProjects) {
  2710. if (sub.noFlatten) {
  2711. out.push(sub);
  2712. }
  2713. else {
  2714. if (!sub.lto) {
  2715. this.lto = false;
  2716. }
  2717. if (sub.icon != "icon.png") {
  2718. this.icon = sub.icon;
  2719. }
  2720. let subbasedir = sub.basedir;
  2721. for (let tkey of Object.keys(sub.target_options)) {
  2722. let target = sub.target_options[tkey];
  2723. for (let key of Object.keys(target)) {
  2724. let options = this.target_options[tkey];
  2725. let option = target[key];
  2726. if (options[key] == null)
  2727. options[key] = option;
  2728. // push library properties to current array instead
  2729. else if (Array.isArray(options[key]) && Array.isArray(option)) {
  2730. for (let value of option) {
  2731. if (!options[key].includes(value))
  2732. options[key].push(value);
  2733. }
  2734. }
  2735. }
  2736. }
  2737. for (let d of sub.defines) {
  2738. if (d.indexOf("=") >= 0) {
  2739. if (!contains_fancy_define(this.defines, d)) {
  2740. this.defines.push(d);
  2741. }
  2742. }
  2743. else {
  2744. if (!contains_define(this.defines, d)) {
  2745. this.defines.push(d);
  2746. }
  2747. }
  2748. }
  2749. for (let file of sub.files) {
  2750. let absolute = file.file;
  2751. if (!path_isabs(absolute)) {
  2752. absolute = path_join(subbasedir, file.file);
  2753. }
  2754. this.files.push({file : absolute.replace(/\\/g, "/"), options : file.options, projectDir : subbasedir, projectName : sub.name});
  2755. }
  2756. for (let custom of sub.customs) {
  2757. let absolute = custom.file;
  2758. if (!path_isabs(absolute)) {
  2759. absolute = path_join(subbasedir, custom.file);
  2760. }
  2761. this.customs.push({file : absolute.replace(/\\/g, "/"), command : custom.command, output : custom.output});
  2762. }
  2763. for (let i of sub.includedirs)
  2764. if (!this.includedirs.includes(path_resolve(subbasedir, i)))
  2765. this.includedirs.push(path_resolve(subbasedir, i));
  2766. for (let j of sub.javadirs)
  2767. if (!this.javadirs.includes(path_resolve(subbasedir, j)))
  2768. this.javadirs.push(path_resolve(subbasedir, j));
  2769. for (let lib of sub.libs) {
  2770. if (!this.libs.includes(lib))
  2771. this.libs.push(lib);
  2772. }
  2773. for (let flag of sub.cFlags) {
  2774. if (!this.cFlags.includes(flag)) {
  2775. this.cFlags.push(flag);
  2776. }
  2777. }
  2778. for (let flag of sub.cppFlags) {
  2779. if (!this.cppFlags.includes(flag)) {
  2780. this.cppFlags.push(flag);
  2781. }
  2782. }
  2783. }
  2784. }
  2785. this.subProjects = out;
  2786. }
  2787. getName() {
  2788. return this.name;
  2789. }
  2790. get_safe_name() {
  2791. return this.safe_name;
  2792. }
  2793. get_uuid() {
  2794. return this.uuid;
  2795. }
  2796. addCFlag(flag) {
  2797. this.cFlags.push(flag);
  2798. }
  2799. addCFlags() {
  2800. for (let i = 0; i < arguments.length; ++i) {
  2801. if (typeof arguments[i] === "string") {
  2802. this.addCFlag(arguments[i]);
  2803. }
  2804. }
  2805. }
  2806. add_file_for_real(file, options) {
  2807. for (let index in this.files) {
  2808. if (this.files[index].file === file) {
  2809. this.files[index] = {file : file, options : options, projectDir : this.basedir, projectName : this.name};
  2810. return;
  2811. }
  2812. }
  2813. this.files.push({file : file, options : options, projectDir : this.basedir, projectName : this.name});
  2814. }
  2815. search_files(current) {
  2816. if (current === undefined) {
  2817. for (let sub of this.subProjects)
  2818. sub.search_files(undefined);
  2819. this.search_files(this.basedir);
  2820. for (let includeobject of this.includes) {
  2821. if (path_isabs(includeobject.file) && includeobject.file.includes("**")) {
  2822. let starIndex = includeobject.file.indexOf("**");
  2823. let endIndex = includeobject.file.substring(0, starIndex).replace(/\\/g, "/").lastIndexOf("/");
  2824. this.search_files(includeobject.file.substring(0, endIndex));
  2825. }
  2826. if (includeobject.file.startsWith("../")) {
  2827. let start = "../";
  2828. while (includeobject.file.startsWith(start)) {
  2829. start += "../";
  2830. }
  2831. this.search_files(path_resolve(this.basedir, start));
  2832. }
  2833. }
  2834. return;
  2835. }
  2836. let files = fs_readdir(current);
  2837. for (let f in files) {
  2838. let file = path_join(current, files[f]);
  2839. let follow = true;
  2840. try {
  2841. if (fs_isdir(file)) {
  2842. follow = false;
  2843. }
  2844. } catch (err) {
  2845. follow = false;
  2846. }
  2847. if (!follow) {
  2848. continue;
  2849. }
  2850. file = path_relative(this.basedir, file);
  2851. for (let includeobject of this.includes) {
  2852. let include = includeobject.file;
  2853. if (path_isabs(include)) {
  2854. let inc = include;
  2855. inc = path_relative(this.basedir, inc);
  2856. include = inc;
  2857. }
  2858. if (matches(stringify(file), stringify(include))) {
  2859. this.add_file_for_real(stringify(file), includeobject.options);
  2860. }
  2861. }
  2862. }
  2863. let dirs = fs_readdir(current);
  2864. for (let d of dirs) {
  2865. let dir = path_join(current, d);
  2866. if (d.startsWith("."))
  2867. continue;
  2868. let follow = true;
  2869. try {
  2870. if (!fs_isdir(dir)) {
  2871. follow = false;
  2872. }
  2873. } catch (err) {
  2874. follow = false;
  2875. }
  2876. if (!follow) {
  2877. continue;
  2878. }
  2879. this.search_files(dir);
  2880. }
  2881. }
  2882. add_cfiles(file, options) {
  2883. this.includes.push({file : file, options : options});
  2884. }
  2885. add_define(define) {
  2886. if (contains_define(this.defines, define)) {
  2887. return;
  2888. }
  2889. this.defines.push(define);
  2890. }
  2891. add_include_dir(include) {
  2892. if (this.includedirs.includes(include))
  2893. return;
  2894. this.includedirs.push(include);
  2895. }
  2896. add_lib(lib) {
  2897. this.libs.push(lib);
  2898. }
  2899. add_assets(match, options) {
  2900. if (!options)
  2901. options = {};
  2902. if (!path_isabs(match)) {
  2903. let base = stringify(path_resolve(this.basedir));
  2904. if (!base.endsWith('/')) {
  2905. base += '/';
  2906. }
  2907. match = base + match.replace(/\\/g, '/');
  2908. }
  2909. this.asset_matchers.push({match : match, options : options});
  2910. }
  2911. add_tsfiles(source) {
  2912. this.sources.push(path_resolve(path_join(this.basedir, source)));
  2913. }
  2914. add_shaders(match, options) {
  2915. if (!options)
  2916. options = {};
  2917. if (!path_isabs(match)) {
  2918. let base = stringify(path_resolve(this.basedir));
  2919. if (!base.endsWith('/')) {
  2920. base += '/';
  2921. }
  2922. match = base + match.replace(/\\/g, '/');
  2923. }
  2924. this.shader_matchers.push({match : match, options : options});
  2925. }
  2926. getFiles() {
  2927. return this.files;
  2928. }
  2929. getJavaDirs() {
  2930. return this.javadirs;
  2931. }
  2932. getSubProjects() {
  2933. return this.subProjects;
  2934. }
  2935. getIncludeDirs() {
  2936. return this.includedirs;
  2937. }
  2938. getDefines() {
  2939. return this.defines;
  2940. }
  2941. getLibs() {
  2942. return this.libs;
  2943. }
  2944. get_debug_dir() {
  2945. return this.debugdir;
  2946. }
  2947. add_project(directory) {
  2948. let from = path_isabs(directory) ? directory : path_join(this.basedir, directory);
  2949. if (!fs_exists(from)) {
  2950. return;
  2951. }
  2952. let project = load_project(from, false);
  2953. this.subProjects.push(project);
  2954. this.asset_matchers = this.asset_matchers.concat(project.asset_matchers);
  2955. this.sources = this.sources.concat(project.sources);
  2956. this.shader_matchers = this.shader_matchers.concat(project.shader_matchers);
  2957. this.defines = this.defines.concat(project.defines);
  2958. return project;
  2959. }
  2960. static create(directory) {
  2961. let project = load_project(path_resolve(directory), true);
  2962. let defines = [];
  2963. for (let define of defines) {
  2964. project.add_define(define);
  2965. }
  2966. return project;
  2967. }
  2968. }
  2969. function export_amake_project() {
  2970. console.log('Creating ' + goptions.target + ' project files.');
  2971. let project = Project.create(".");
  2972. if (goptions.graphics === "metal") {
  2973. project.add_cfiles(path_join("build", 'sources', '*'), {});
  2974. }
  2975. project.search_files(undefined);
  2976. project.internal_flatten();
  2977. fs_ensuredir("build");
  2978. let exporter = null;
  2979. if (goptions.ccompiler === "tcc") {
  2980. exporter = new MakeExporter(goptions.ccompiler, goptions.cppcompiler, "", "", "", "");
  2981. }
  2982. else if (goptions.target === 'ios' || goptions.target === 'macos') {
  2983. exporter = new XCodeExporter();
  2984. }
  2985. else if (goptions.target === 'android') {
  2986. exporter = new AndroidExporter();
  2987. }
  2988. else if (goptions.target === 'wasm') {
  2989. exporter = new WasmExporter();
  2990. }
  2991. else if (goptions.target === 'linux') {
  2992. exporter = new LinuxExporter();
  2993. }
  2994. else {
  2995. exporter = new VisualStudioExporter();
  2996. }
  2997. exporter.export_solution(project);
  2998. return project;
  2999. }
  3000. function compile_project(make, project) {
  3001. if (make.status != 0) {
  3002. os_exit(1);
  3003. }
  3004. let executable_name = project.get_safe_name();
  3005. if (project.get_executable_name()) {
  3006. executable_name = project.get_executable_name();
  3007. }
  3008. if (goptions.target === "linux") {
  3009. let from = path_resolve(path_join("build", goptions.build_path), executable_name);
  3010. let to = path_resolve(".", project.get_debug_dir(), executable_name);
  3011. fs_copyfile(from, to);
  3012. os_chmod(to, "+x");
  3013. }
  3014. else if (goptions.target === "windows") {
  3015. let from = path_join("x64", goptions.debug ? "Debug" : "Release", executable_name + ".exe");
  3016. let to = path_resolve("..", project.get_debug_dir(), executable_name + ".exe");
  3017. fs_copyfile(from, to);
  3018. }
  3019. else if (goptions.target === "wasm") {
  3020. let from = path_resolve(path_join("build", goptions.build_path), executable_name + ".wasm");
  3021. let to = path_resolve(".", project.get_debug_dir(), "start.wasm");
  3022. fs_copyfile(from, to);
  3023. }
  3024. if (goptions.run) {
  3025. if (goptions.target === "macos") {
  3026. os_exec("build/" + (goptions.debug ? "Debug" : "Release") + "/" + project.name + ".app/Contents/MacOS/" + project.name, [], {cwd : "build"});
  3027. }
  3028. else if (goptions.target === "linux") {
  3029. os_exec(path_resolve(".", project.get_debug_dir(), executable_name), [], {cwd : path_resolve(".", project.get_debug_dir())});
  3030. }
  3031. else if (goptions.target === "windows") {
  3032. os_exec(path_resolve("..", project.get_debug_dir(), executable_name), [], {cwd : path_resolve(".", project.get_debug_dir())});
  3033. }
  3034. }
  3035. }
  3036. function main() {
  3037. console.log('Using Iron from ' + irondir);
  3038. goptions.build_path = goptions.debug ? 'Debug' : 'Release';
  3039. let project = export_amake_project();
  3040. let project_name = project.get_safe_name();
  3041. if (goptions.compile && project_name !== '') {
  3042. console.log('Compiling...');
  3043. let make = null;
  3044. if (goptions.target == 'linux' || goptions.target == 'wasm' || goptions.ccompiler == "tcc") {
  3045. let cores = os_cpus_length();
  3046. make = os_exec('make', [ '-j', cores.toString() ], {cwd : path_join("build", goptions.build_path)});
  3047. }
  3048. else if (goptions.target == 'macos' || goptions.target == 'ios') {
  3049. let xcode_options = [ '-configuration', goptions.debug ? 'Debug' : 'Release', '-project', project_name + '.xcodeproj' ];
  3050. make = os_exec('xcodebuild', xcode_options, {cwd : "build"});
  3051. }
  3052. else if (goptions.target == 'windows') {
  3053. let vswhere = path_join(os_env('ProgramFiles(x86)'), 'Microsoft Visual Studio', 'Installer', 'vswhere.exe');
  3054. let vsvars = os_exec(vswhere, [ '-products', '*', '-latest', '-find', 'VC\\Auxiliary\\Build\\vcvars64.bat' ]).stdout.trim();
  3055. fs_writefile(path_join("build", 'build.bat'), '@call "' + vsvars + '"\n' +
  3056. '@MSBuild.exe "' + path_resolve("build", project_name + '.vcxproj') +
  3057. '" /m /clp:ErrorsOnly /p:Configuration=' + (goptions.debug ? 'Debug' : 'Release') +
  3058. ',Platform=x64');
  3059. make = os_exec('build.bat', [], {cwd : "build"});
  3060. }
  3061. else if (goptions.target == 'android') {
  3062. let gradlew = (os_platform() === 'win32') ? 'gradlew.bat' : 'bash';
  3063. let args = (os_platform() === 'win32') ? [] : [ 'gradlew' ];
  3064. args.push('assemble' + (goptions.debug ? 'Debug' : 'Release'));
  3065. make = os_exec(gradlew, args, {cwd : path_join("build", project_name)});
  3066. }
  3067. if (make !== null) {
  3068. compile_project(make, project);
  3069. }
  3070. }
  3071. }
  3072. function default_target() {
  3073. if (os_platform() === 'linux') {
  3074. return 'linux';
  3075. }
  3076. else if (os_platform() === 'win32') {
  3077. return 'windows';
  3078. }
  3079. else {
  3080. return 'macos';
  3081. }
  3082. }
  3083. let goptions = {
  3084. target : default_target(),
  3085. graphics : 'default',
  3086. visualstudio : 'vs2026',
  3087. compile : false,
  3088. run : false,
  3089. debug : false,
  3090. ccompiler : 'clang',
  3091. cppcompiler : 'clang++',
  3092. arch : 'default',
  3093. alangjs : false,
  3094. js : false,
  3095. ashader : false,
  3096. };
  3097. let args = scriptArgs;
  3098. for (let i = 1; i < args.length; ++i) {
  3099. let arg = args[i];
  3100. if (arg.startsWith("--")) {
  3101. let name = arg.substring(2);
  3102. let value = true;
  3103. if (i < args.length - 1 && !args[i + 1].startsWith("--")) {
  3104. ++i;
  3105. value = args[i];
  3106. }
  3107. goptions[name] = value;
  3108. }
  3109. }
  3110. if (goptions.js) {
  3111. globalThis.std = std;
  3112. globalThis.fs_readfile = fs_readfile;
  3113. globalThis.fs_writefile = fs_writefile;
  3114. globalThis.fs_exists = fs_exists;
  3115. globalThis.fs_readdir = fs_readdir;
  3116. (1, eval)(fs_readfile(goptions.js));
  3117. std.exit();
  3118. }
  3119. if (goptions.ashader) {
  3120. let type = args[3];
  3121. let from = args[4];
  3122. let to = args[5];
  3123. amake.ashader(type, from, to);
  3124. std.exit();
  3125. }
  3126. if (goptions.run) {
  3127. goptions.compile = true;
  3128. }
  3129. if (goptions.graphics === "default") {
  3130. if (goptions.target === "wasm") {
  3131. goptions.graphics = "webgpu";
  3132. }
  3133. else if (os_platform() === "win32") {
  3134. goptions.graphics = "direct3d12";
  3135. }
  3136. else if (os_platform() === "darwin") {
  3137. goptions.graphics = "metal";
  3138. }
  3139. else {
  3140. goptions.graphics = "vulkan";
  3141. }
  3142. }
  3143. let start = Date.now();
  3144. main();
  3145. console.log("Done in " + (Date.now() - start) + "ms.");