2
0

make.js 107 KB

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