H__PAGEZEROx__TEXT__text__TEXT__stubs__TEXT__stub_helper__TEXThHh__const__TEXT0__cstring__TEXTE__unwind_info__TEXTHH__eh_frame__TEXThPohP__DATA  __program_vars__DATA(__nl_symbol_ptr__DATA((l__got__DATA080m__la_symbol_ptr__DATAh`ht__const__DATA__data__DATA__common__DATA8 __bss__DATAXH__LINKEDIT"0XXp`)8( PggPr5 /usr/lib/dyldILcID$HCHL2I$@@AD$HKHQHHL蟑HC[A\A^A_]UHAVSIHHKHQHSL1AHKHQHHHRHC[A^]UHAVSHL0HSHHLfHKAAF HC@@t AF tHHA tHL HCHHC[A^]UHAWAVSPIH$L0HKHHLLeHC@@t AF tHHA tHL襌HCHHCH[A^A_]UHAWAVSHIHL0HUL:BHLeHKAHC@@t AF tHHA tHL)HCHHCH[A^A_]UHAWAVSPH@IHCxtLpE1AGtu@ILp(ILpMt7I7F tAF tHL蕊I7HL^ HKLHCH[A^A_]UHSPHHKHHqHr IJ HKA@tH0F tHQB t HHKHHKH[]UHAVSAHHcHHw1MtfuHC L@ HC HH0HDxAuHCHK H9AsHA[A^]UHAWAVAUATSHMMA։ItLIM+E8E1HcHIMHMMt fAtHUDrI+M8H5L{^I] Lc L{0HI+E8HC8IHC(MCB$A CBLHDwcBHC(I1AuIMIU H9JsHJH[A\A]A^A_]UHHVH1]kwUHAWAVATSH0MHHIHHHELeLHqLLHL{AƅtDH0[A\A^A_]IGHX{ tIGHx@hHK H Hs H@@tHNH9uLUHHGxFuAHHH@Hp]r}]UHG ]UHAWAVATS  ILwH HcHAFW11L1#AFW1L1聒I^I^H A^A^EfWAFWtiHcH I^LH<#IGHx~L蠐EfWHRjAAGA)(MA,A^W%LHƀ"LIEfW1A~UÉ[A\A^A_]%6GZUHfUHSPHH0HSHHj\1ɅHSHHHHKH[]UHAVSI|!IFHx~L虏L[A^]ېu'I^H5FL1*H@@CIF[A^]UHSPHHsHH襒HCH[]UHHt HGH@HHGH]UHHGHPH0]UHAVSIHHGHx~HHL_+HKHAGHCH([A^]UHAWAVSPAHL}I=HDL1E1#HtHKHUHCH[A^A_]UHG?t6&uA~=H?G 9r2HH7H HHHtH9~ HHA9p}1]H| H?H:MtHL IH@XHH0HH HHHEUHAWAVAUATSHI1LuILeI$LmIE@HljLLM&IHtfIGHHIOHM@HuHt#IG@@tLPAAAAAH8DLYtADED9|1A LȉDH0HtH5L1H5LHPH8HDHDXALPAD;DuLH5mETHH5LZLH5HU1;x~LH5r1 LH5`LLAtDL1LH5EH1LLyyH`:tHXLH5 1SHheuLLLLHcLH[A^A_]UHAVSIHعLk1uZH߾H11HL8HH߾cH߾H߾عLF[A^]UHSPHHعH߾H[]UHAWAVATSI׉ICHtJILt9LعLL1ɅLDLE1L[A\A^A_]UHAWAVATSIAIqHHuLDL H[A\A^A_]UHAWAVSPIAHHX H߃u1+Du H HDkH߉HH5HL1PHDHH[A^A_]UHAWAVAUATSPIAIHtILD~LD1II<$Ht1Lt=I|HHuH5LL1LDHH[A\A]A^A_]H[A\A]A^A_]UHAWAVATSIIAHs~HDL[A\A^A_]%MtMt L1IL[A\A^A_]UHAWAVSPAIHHuL+LDH;HH[A^A_]UHAVSIHJt[A^]MtH5HL1[A^]!H5H1[A^] UHAWAVSPAAHD9u H[A^A_]HDHDHH[A^A_]UHAVSAHAt[A^]HVHD[A^]nUHAWAVSHAHL}L6A?u%H߾E HDHEH[A^A_]UHAVSHEAH~HDH[A^]yEH[A^]UHAWAVATSHAHLeLIA<$u>HDtHHDH߾RHDHbLH[A\A^A_]UHAWAVSPIAH~HDH[A^A_]VLH[A^A_]UHAWAVATSHHOHGHH)H9L{HHH)L40H9LCLH)rH9sH5L1LLIH3HSH HC H9tLULL#LsHCL#L[A\A^A_]UHAWAVSPHIIH)HLH蜼I_H[A^A_]UHAWAVSPIIHHLHHLHYI^H[A^A_]UHAVSHLwH7HWLHC H9t#LyL[A^][A^]UHHw]UHAWAVAUATSPHLwHULILk L9+tLLeHLHLL荻Lc1L9+@ƃLLzH[A\A]A^A_]UHH~HF H(F]UHH~HF H(FHH]UHAWAVSPAHAEt[HDAH߉1tH߾1IH߾Et,IcHDBHD1 H߾HDOIAIcHDtDH[A^A_]ÅxWUHAWAVSPAHAH߉1EHDL-HLVHD1H[A^A_] UHAWAVAUATSH(IIIHHHEMt;H5[LL1H5KLHHu1H52VH5LHDHHHHtHcHƄ MtDu?HH5L衸HHHLL`AtHcQ L1H5HLHHMAH[HѷAMtH起LEtwH5&LQH5L0AHHH;EuDH([A\A]A^A_]衶UHAWAVATSAIHj8sIHD1HHH5HLM1HDH߾[A\A^A_]UHAWAVAUATSPIIE1L%1I}tbB #9u*IcMQAUAD HHuAEI}ضAE1#u,I}Ķ tuI}豶AADH[A\A]A^A_]UHAVSIH~IHH{t 1H[A^]H{HKIUHHHEH0HPH5HH]UHHFHtHHFH1]UHAVSHHIHȶHUHHBH5LHE1fH[A^]UHAWAVSPIHt9HLAH߾*tAH߾E1E1AHDDH[A^A_]UHAWAVSPIHAAH߉Lbt*HDyAH߾1E1E1DH[A^A_]UHAWAVSPHUL}H߾LIA?uH5H1H߾LH[A^A_]UHAWAVATSI։IH"tLL[A\A^A_]LwPH HcHH5RLLiH*H5HDLLnLILH5LLH1FLLL1҅t-H5LH1L (H5L%;cUHAWAVSPAIHH[عH߾LteH߾@H߾عH1LD_HtH5HL1H߾H߾LH߾&H߾H[A^A_]UHAWAVAUATSPAIItLL.IHuLIMLL)LLHLLttM~6A}.tDL1@LLHTLLL3LMeA}.+E1 LLH[A\A]A^A_]UHAWAVAUATSPAIIIJyDMt91MtI?tIG1H8H@uLLL޺LMtLDH[A\A]A^A_]H[A\A]A^A_]UHAWAVSPHEIIHtH5L1q1cI9tH5L1H[A^A_]JAEf.u{H5LH[A^A_]H[A^A_]UHAWAVAUATSPAIIHZDI?tOD۸D)EE~EL2AuIwLDILuIMuALDH[A\A]A^A_]UHAWAVATSIAH]AtEH߾HDVAE1H11H߾HDLED[A\A^A_]UHAWAVATSAIIHH(عcH߾LH߾&uYH߾HL1 HLH߾1E1H߾H߾LH߾H߾Et H߾HL[A\A^A_][A\A^A_]UHAWAVAUATSH8 IIHIHuHHEHȮHHLLpH@(̳@HL蹮HteIMMMI)HLIHHL輭LMMHLLHHLWIHuLLHLH1H uH H;MuH8 [A\A]A^A_]٫UHSPH=(1.HHtH5/HHH[]HHtH2UHo1]UHAVSL5tI1H5 HH1(I>1[A^]UHAWAVATSE1AAHHsH߾AH߾u&HDPu2HDDzu5H߾H߾umH߾AXH߾3H߾H5HAH߾H߾qD[A\A^A_]UHAVSIعH5v1L1LpHL!H5LuHLLoLHà uH5+L HeL[A^]UHSPHH߾׹)HH[]UHSPHtHH[]UH߾JH߾H߾BH5gHsH߾!HH[] UHAWAVSPIHJH vHH L1LމAƃ t8t3u;L1A**YfXLLD IcLH[A^A_]UHAVSH11IH߾7HL1t H[A^]LQ H11H[A^]UHAVSHIH߾H߾t*E~%HDH߾H߾cH[A^] UHSPHYH߾tHԶH߾=H:H[]UHAVSIH H HU HDLLH1LL1[A^]UHAWAVATSH11\IH߾11HIH߾1ɃD$IHLL_H߉D[A\A^A_][ UHAWAVATSHHHUؾtIHµH߾1IH߾OAMt)H߾L1HUHLHMKOHnH߾1yIH߾UH߾H5 H1LM1AH߉|H[A\A^A_]UHAVSHAH߾DH߾uH$AD[A^]UHSPHHH߾t H߾1E10mH5XH1H߾HH[]UHSPHsH߾H߾HJpL Hߺ1E1H߉1H[]lUHAWAVAUATSPIAH51LEA޻L%lLLL1E1LHUHIŃrI $H=&HUI $LLiA˃_HlH H=RϣH;g1H5L1H[A\A]A^A_]UHSPHH߾H߾H߉dH[]UHSPHtHH߾H߾CHHH[]UHSPHH߾1H߾;H߾H[]UHSPHH߾H߾H߾H߾bH[]UHAWAVATSI螿ALu*AL18#uAIcLALIcH H9HNHHHHHtLA)ED[A\A^A_]UHAVSISLttH0LoH[LtH5L1[A^]cL謾L~[A^]UHAWAVAUATSH(IL~{ILHULHHIID$H#rHLH5L軡HA<-t>A<+u@A5LLȽ6E1CHÄxHUh#D< DmL}LuMcAE1;GЃ w @ǃMHILkD9|I}[A}@xHgDuAFr K:9|K u F;Fu]]UHF;Fu]2]pUHAVSH HIHHHc HA~,HUBIFH@PHuHFELCMCHUBLH#HCHuHFHUHBLC=~6LH.1ɃHU BLHC H [A^]Ð"""bgUHAWAVATSIHI tA tqA?uAGr AN:9|ANuAFr AO:9|AO<[A\A^A_]UHAVSIHgAHr$tHL u >AV 1IvHjAVC C$Hs(HTAF[A^]UHHcNHHHB8H~Hʃ?H5/<xHʁ?1?@ ։0]UHAWAVSPII> u7IH@8IcO?uAN 1@ ƃ"L?LL% A?uAGr AN:9|ANu AvrA|$:9| AL$uANrAT$:9|AL$<uԃDEAEź@D   L"LAFA H[A\A]A^A_]UHHH@HHcO t]UHAWAVSPAIBHHiQHH$H?D1Eǁc  ރ+ ƃ+L.L{AE~u[A^]IHICwUHع赗]UHSPHlH߾ uHcH[]UH]$UHAWAVSPHAH߾xAH߾耗tH9H߾H߾[tHH߾ZH߾DE蝬1H[A^A_]UHSPHH߾ HH1H[]UHSPHH߾2H߾HuHHDܩD[A\A^A_]UHHAAELG A@BtI@(HG(1EHEHEЈ]UHH]UH]UH勇]UH1xBHO H`H9AtH9tAAqHIH9AAuuEt HJx]UHSPHHt1HMHHvxHDHt8HKHUHC#HCxFuH@Hx1H[]'1H[]UHAWAVAUATSPAHIFBLcuL3II9_ t>L{1UHSPHHMHHvxHtHMHSBHCH[]UHAWAVAUATSHHHI>>uIMHHIME1LsxIAuLE1ۊL]HuHMHKHMHK8HML~EL%}k~] wpIcLMt:AFBt3IH HQHJHHt IF(H+B8HHHH C(#LSfEMtAFB uINQBH xHCHCMt\AFB$ VMtVAC C4A{&tLIC@ C6IC@ C5MtA{&u/H5wHs HC,HiQ1C7`C4fC5TICHHhHq HH @HDHs H(K,@,C0H+H HDHC<H}荋L]AIDŽjH+wLuiHHq(HHxHG8H)HHcDLDɃ?E1A!w LIcLLLIIEJH LHCLSdAAAHML]HCH8SAAAAAAxAmEH]H߾f6lHtIEHMIEH߾LlHHEHtx&uIE@HIEkH@LpHL<IIEL @EIEEEHEH@x~,1L}IcLLL(HHEH@Hc@H9|ڋEHH[A\A]A^A_]CP[[[UUUUUUUUUUUU[[[[[[[rUHAWAVSPIHFH cCL|H5|HLLI1UHSHHH0HWHOLG LO(t&)`)p)U)])e)m)u)}HUHzHEHBH0HH+HHbHUHAVSHHEHG @BIHH Q HtH1H\9 H93tyHH9uL@ HL)H|PHHHxL)HH9}9HII9u-HyHp(H+w8HHHMHt HHM5H&sH[A^]HAH@XHxHP HH sHEH{H5{L1H[A^]釆UHFHBHzUHAWAVATSHIIHI~u EHuH"LDLLLUHAWAVSPIHI~u HHEHuH"LDLL[H5dzLH1UHHЋNH5@HT@HLH9uH5Nz1H5az1zUHSPHHHt:HKHS8AHKAHsHFHCHHߺ1 H߾8UHAWAVSHHH.HHEHW BBIHHHH@HHHHt#HR(H+P8HHHH D<AHphHtH H}<;fE?H5zHUHDM1~H%.HH;Eu HH[A^A_]dUHAWAVATSILw t A$tCAFB@ujE1IIv(HH@HH8H@HHH)HHtBHc׋?A$A$AFB@uLsAIB$A\t5I|$(H9v+HtH)HHHH 9t LIF(ID$(A|$ t [A\A^A_]Et ADŽ$IF(ANB@ID$HIL0UHAWAVAUATSPHMAAIL=mAvLDHMHHXDMD$81A1A؃?@#~X܃r)uID9~M\t)u5HHHH9OH9M9N.D9)D9}A@tD9uHcAH9|AHH9jAIcAӃ?uAAA9s ]H=eHc4HAAAHLDHILDDHMMMHvHvATID$0HTuHH HMHHv1HID$XHHH HHlmHEHMHHXvuLDHMHmTID$XHHHH HL=mLELDDHMbH5uLcH uHuHDH[A\A]A^A_] J|UHSPHrHH lHt28cu-.HG0HLu H H H OlH H[]UHAVSHHXHuMLs@s IHxXuKIt(HSHXHCHK H9AsHAHAI`H)`HHHQHPHC@IiUHAVSHItu0IFHH5 uLBH@@C IF@HI^[A^]UHAWAVATSHIIHDH@ǀHOXHHGXHHb_u HLAH@HCXfDEHĠ[A\A^A_]UHAWAVAUATSHIH_8LcLmIuLcMIHLLgbHUIF8D9}J (HI)HIuMAJ 8HIN0IVIN@H)HIVHtHHqH)HHHHuIN Ht=HHqH)HHqH)HHABtHQ H)HHA HIHtIF8H[A\A]A^A_]UHSPHAB}8HKH+K8Hȃ@B9M9LAB}HH[]H߾+H߾CH5VjH1UHAWAVSPIH_HG HtHHH@H9HBI+^8HCKIA6BD9DLAAB| LL'?B"A E;}LDH[A^A_]H[A^A_]UHAWAVAUATSHH%HHELMHHCL{ HK8II)MoI)͉PxL}HK0H)HOH߾UHCH@IGƃAOBHPHAƃHC8IMoILcAgBH/%HH;EuHĈ[A\A]A^A_][UHAWAVAUATSPAII_8II)܋F?&IG0I+GHLI_8LLH޺xHIOH9vAHQHH9wIOHIOH^HHxI_IG0H)H)HHw H9ILLDo D9H6HHIG0I+GH=O LIG H@HuLRIG fDp@Mg8L @IOHH@BIGHx~LAtL1LIwHHH)LAIGD)@HuIGDDuԀ MwIG0L)Hw H9ILLMwMtrHcHHHHLH)IVIWAHADAt:H)HIHIMIWHrIw@HHuMg8IG8N4 IIIG HXHuHLHHI_ EfC@L#Ls G HLHCHO8HK(CBIGIGHx~LE1AtFHC(HCE1@BtH@(@?%u KB LHC(DH[A\A]A^A_]HnkLHUHAWAVSPHIL t,tI+^8LhI^8IWHB(IF(IWIAG@IV t=P1I;^sHH9u)~)AHʃwINH[A^A_]UHAVSAHf=r t?=sIEufHuHW!Euff[A^]H5TlH1H߾UHAWAVAUATSPIHt fEfAfAdžIFHcHH)H5LHkEԃÃL-Mf MAD$BuMd$MufD}MMn8Ml$8LLSLLMD}Mf AD$B$AfAdžLID$(ILLHUÉEԃ^-&|!A^ IVL,IFIN HA]fEfAH[A\A]A^A_]UHSPHH=HC K t4HK`H9HHHֺteH[]C HK8HH8H@Bu1HH HtHP0H߾HSHHH)HHHH1H[]/HH[]H5iH5fH5hjH UHAVSHHt 6H)Ls`HC L9t'@BuH߾ HH|[A^]UH1f]UHfuLG G IH+G8I@8A@Bt1]HGH9u8H5yi6IH HtIP0HGHcHHHHIH5i1|UHAWAVAUATSHIHHG HELDfELHADžt?Ls8HLx HDLHEHC DEfHLDH[A\A]A^A_]UHAWAVATSH`IfH]H3HSXHKPE1Dc,Lc0DcH/s :AHGHHHOD8HsPAu$HgLHSH3HKXL)HgLHSHK H3LCXLE{LHH[A^A_]UHAVSIHHW4I@@AFHCH߾8UHSPHHG HBtHBHH(Hfx@uHKH9HsHHHP0HP HsHHH)HH[]UHAWAVSPHtIHI2HSHt H[A^A_]H5fLLH1}pLUHAWAVAUATSH(IIIHH}HUHMDEH5fAԉEESLmкHLLAԉEAE\HuкHLAԉE̅?H54fHLAԉEELmкHLLAԉEAELmкHLLAԉEAELmкHLLAԉEAELmкHLLAԉEAELmкHLLAԉEIExVucLmкHLLAԉEH(w@IMu9LmкHLLAԉEANAMuHuкHLAԉEH]L1HCH([A\A]A^A_]UHAWAVAUATSPIIzt'EAEu0I}IMHuкAUAEI~hH9tLJAEAN(MЅI}IML}кLAUAEAN,AI}IML}кLAUAEAN AI}IML}кLAUAEAN AuoI}IML}кLAUAEAN AuHI}IML}кLAUAEANAu!I}IMHuкAUAEA^AI1M~0ALʀ?UЅuI}IMHuAUAEAL?~!t t.uhI<LAEVt-uLAEI HMЅu3I}IMA MЅuI}IMHuAUAEHI9AEfDeЅuI}IMHuкAUAEE~aI1L}INXLMЅu?I}IMLAUAEINXL MЅuI}IMLAUAEHI9uE~ D}ЅuI}IMHuкAUAEE~1IF@IvhHA}t#IE@@tH0F tLAEMmHx@tHPHHHuLI|$puID$ HEHEID$pHtLI|$puID$ LI$L1*I$L1Ml$ I$I$HEI$HH HuIL$hHt*IT$hA tH1H2H0H1HHHH HuADŽ$Lo I|$pPLIOhLL!ILL LL1H[A\A]A^A_] IH AWTʈP AVt_I_IIL1bBIILJAGH߾ZH5$H1H߾LHH0HDH DHGHH0H}DH DH'HVH0H oDH1 H[]UHAWAVAUATSPIIIIaHH@H5]DLlL#H"HCMtL7NLعLYLLH[A\A]A^A_]YUHSPHNuHCH߾عjVHSHCH߾lHHHMH@HEHH[]UHSPHH5DCIH-1@H1H[]XjUHH5CH9l]UHAVSH_MuHRAH߾?MtBH߾1mHv9HHH߾wLH߾J>HpBH߾عNUH߾BLH߾JHE1HD[A^]UHAWAVAUATSPIE11RmIH8L1lIǾL_HLhH5)BLjL+HKHCA7t@H=B,Ht*IGLH1A+HE1B|:b<tHcBL*eLL+HHtH[A\A]A^A_]L1LH[A\A]A^A_]bhUHH5AHBv]UHAWAVATSI1/lIH7L1kIǾL^HH@H5ALi1+LL+HH ! HKHt[A\A^A_]L1L[A\A^A_]gUHSPHH5F@[HHƺH[]UHAWAVSPI]HE1LxH5_@LhL;HHC,HHtH[A^A_]L11H[A^A_]gUHSPHkH?H߾hHtHxtH5@HNH5r@ HNH[]UHSPHH5O?THHƺH[] UHAVSIHo?hHHxuH5Z?L1cH[A^]UHAWAVSPIIعLQL'MHHxuIH5&?LL1cHH[A^A_]UHAWAVSPIIHH~FH߾1KHHt HL>H߾HH߾عLHTH߾عLH[A^A_]PUHAWAVAUATSPIII[HE1LhH55>LfL+HWHCLL](HHtH[A\A]A^A_]W'8`)H5(>LLH1H[A\A]A^A_]`bUHSPHH=fH8'1@H1H[]dUHAWAVSPAHNEAAGHcHLHDNH߾EAH5HDH[A^A_](NUHAWAVATSHI׹!KILֹ1II~t|ILDHR=LDhE~"ԹLFAȉɉ=ԹuI6LAƉLIt-DH[A\A^A_]H5<L1H[A\A^A_]`A|2D)L1jIH5<LH1H[A\A^A_]`LչIE1tL1CL׹EH;LeHHHMH@HEL>UHAWAVAUATSHX AIIHBHHElCL\%LuLLAAsH;LfLLDiELDulgH ILHHHjHLUhHLLK%IHHH`iE1M1e1ɀ8*kvLaHLHHj Hg HL$HH= tHhAHlTn,LDž$HL3$LAEHAM~IEHHIMD8 LI#ADAwDH KD<@! @D#uA-tA+uLlD1A0HLJ xL(E1H9HL#MAƉL$L11*HE1AAgLL1 LLAEE1HW9HE1AH<9H1HH߉AE9u"HPItLAIHE~eH 9ttMHI9u>Lt2-t+uLЃ w Lu拽LL#L>"HcƄLLHCAHu LjFE1AăsELLLz!tL118^A!EuL?LFD+HHH;Eu)DHX [A\A]A^A_]H7LDaZd UHAWAVAUATSH8 IH^HHELHL%f1ۃ t~ LcIL E1AD$HAL$~I$HHI $ LÃt tC>II uA L DHtuC u>HH;rLL8cIFHHPH HId tHNCH1HH .H H;MuH8 [A\A]A^A_]UHAWAVATSAHE1L%CEt=w#AD>u Ѓ wHtAD[A\A^A_]UHSPHHcG H=|C19KPS LH;GHO~HHHHCCH[]UHSPHH4]H8H߉H[][UHAWAVAUATSPIIA<9AAL{>Lރu+>L1҅tF@LH54H1qAHU _EtBHUоHLH;E'J@LH54.E 1DA9`EuL11ZH[A\A]A^A_]UHSPHH1@H1H[]RZUHSPHH1H[]UHSPHHHƺH[]RUHAWAVSPHIH3H H߾\AH߾1_IcH$LH6tH11H[A^A_]YLHHAH[A^A_]UHAWAVSPHIH =H߾1O\AǺ H߾Y_IcHG$L1He1@H1H[A^A_]XUHAVSHIH߾;HL[A^]RUHSPHH1ZHxt3H8t-H1H߾ZHHHMH@HEH1H[]UHSPHHp1ZHxtHH5S2H1wAH522 Hd@H[]UHSPHH19ZH HHH?H51H@H[]ÐUHAWAVAUATSPIH5.yLHA1L-J4+LsyILHEg HAHuH[A\A]A^A_]UHH8H5r11]49H -H wH8H5K1H1]9]UHWUHAWAVATSH@AIHHw`H L}<L`9H{8KH5(.LM18EtXIL{8A$H߃w"1 H{8HCHHH501o8DH561LLH1N8H{8QUHAWAVSPIH_8HIvIHCHHHKL0AN@HIwPHSHHWxtLpHHCHx~H[HCLH[A^A_]UHSPHFFp.H~8DF !HV@HF0HHFHN`H5,[wHChH{8HCHH0HP HKHHHA H[]UHSPHGO G!uHsHCHC CC !H[]UHAWAVAUATSHHuIHHHEHGHH@L5 AH!E'AD$?IcLI@H/s8LK HGHHHOAI@H/s HGHHHOA-I@H/sHGHHHOA[u]L^ IOHHAxL1 IGHH@.A#I@H/s{HGHHHOAwAsA[A~u=I@H/2LD I@H/IcHFDuI@H/LDx I@H/s AHGHHHOD E'IcDuIGHH0HPLHMH$x@  HGHHHO0A7D9u#LDI@H/-L5iHn[~#\u9L\I@H/s;C&  LsI@H/s7?HGHHHOAa0!~G[h"ty'ttHGHHHOA.H wXHc HA   t uJL]A \tAa!Afbu AHBt0LH, AE1E1HcH DtKLdI@H/sHGHHHOCLD,KAAAƉAuA1A@LH,% DIOHH)AL5HA A LuI@H/A L L AAH1IGHH@SIGHHHI@H/sHGHHHOAHcBD1tS t uLAA I@H/spHGHHHOAIGHHHLDA7D9#HGHHHOA1{@LH+ L LcHA7LI@H/s HGHHHO8A?HcBD0t/I)HI1I@LH*Y H1}@LH*< I@H/skHGHHHOAIGHHXH}L*~$AH]L)I3LIHIwL5\HaL.I@H/I@H/I@H/38I@H/LQI@H/|I@H/pHGHHHOAIGHH0HPHHLQHMH(-L)LHuD%gHGHHHOA.L.L.yHGHHHOAA:L:D HGHHHOAA=L=HGHHHOAL=A>L>pHGHHHOAA/L/BHGHHHOAL=ruA<L<VADHHH;EH[A\A]A^A_]HGHHHOAL=~DIcH DtH0HH;Eu_LHuH[A\A]A^A_]HGHHHOADV[HH5,&H5&L%# H5r&L! eveeveuuuuuuuuuu)Fgr}UHSPHHw(C H[]UHAWAVSPAH_HHKHSHqH9v3H?H9s:L<H8H3LHL{HKHqHHsD4H[A^A_]H5$1>UHAVSHD7H@H/sHGHHHO t u'D9t"H{@H/sHGHHHOCC=t[A^]H5#H1UHAWAVSPID7DI@H/s7HGHHHOA1ۃ=u91L=I@H/sHGHHHOAÃ=t1D91ىH[A^A_]UHAWAVATSAIH7DgOH{@H/sHGHHHO t uoHe u(H߾ HxMuFHCHH@8MtHH{@H/s#HGHHHO3 ~ t]uHD9u3HH{@H/sHGHHHOMt,HCHIcH0HPHHC?HH)HI[A\A^A_]MH"HsHDH{8H5!D1(HHƺ!UHSP197u*HH@H/s4HGHHHOH[]UHAWAVAUATSHIHD?DH{@H/sHGHHHOA0u%H5 "H0H!L=!LDL=!L-L%!HLt HLHc3BD.uH߃.u3.HH{@H/sFHGHHHO1Cp<.t'HSHHJHtHHq| .uD HHuHCHH8Hu HuRD{pHCpA8t'HSHHJHtHHqD8| uD HHuHCHH8HuHt2}uHEI#EA"H[A\A]A^A_]spHߺ.H5 Hߺ"tUHAVSIH7t*HH{@H/sHGHHHOHL%FUHSPH7H{@H/sHGHHHOHH tHH[;H[]UHSPHH79t H19u/H H{@H/sVHGHHHOH[]UH@8t'HOHHAHtH Hx@8tuTHHu]UHAVSH :VH1L0H5[H1VAH+HH߾1%H*HH߾1IHL*HH߾1IHL*HH߾b1[A^]UHSPH%H߾t1(HHHHHo*WGT H?*H[]UHSPH)GH*H[]UHSPHFH)H[]UHSPHFE H߾ G(E^H)H[]UHSPH$tH߾W"H߾cFHH[]UHSPH7FH!)H[]UHSPH FY1 H(H[]UHSPHEH(H[]UHAVSHHLuLJ&A>t HH(H߾REHZ(H[A^]UHSPH#tH߾/!H߾;EhHH[]UHAVSHH#tLH߾o#t;H߾1%IHHwVMuHRH߾/&H5L1#HL'L)HkLع8)LKL1%H5L18LL1%L=>LI7Lx"LHP(HIHuHL'H5bH`H fLhLH5HH LLH5/ L H&L&HLعKHL|&HLعKHLT&Lع#LpH5LJL7H[A^A_]UHAWAVAUATSPMIIHHIHuLIHt6H2H߾ع~"H߾AH߾Et HLJMHH HL$LHHHLLH߾H߾]H߾LH[A\A]A^A_]%UHAVSIDH~BHLH"L+HLHCHHw1[A^]UHAWAVSPHA19IH߾19HLHtAAHH߾AHH5HDHADH[A^A_]UHAWAVAUATSPHA109IH߾19IHH߾18IHH߾18HLLLIHu HH߾ADH[A\A]A^A_]UHSPH9H߾"u)H1!H߾lH߾&%H߾ع HH߾"1H[]UHAWAVATSIIHHع H߾LH߾IH߾M1A>*4LHIHH߾عV HL1H߾H߾L:"H߾BHPH߾7#H߾2A>*uH߾E1PLL&HtE1HH1 .HHAHHnAD[A\A^A_]UHAWAVAUATSH( MHIIIHEHHEH;;tLLHLGIAE<;t%L;HtIHL)ILHIMLL_L1CLHHWLGHL1LHH5W$HuWLH5RH1LLH|9MH 91HH HH;EuHH( [A\A]A^A_]UHAVSH1)5IHwH߾عH߾LuH5HL1$[A^]UHAVSI14H LHHt'HLH1:1@LH[A^][A^]UHAWAVSPI1i4IH;LHHt.HLHL1@LHH[A^A_]XH[A^A_]UHAWAVSPHE113IHǾ.JHL)HLHH߾1H HHtHt1IHHL?t$u>H5HLL1AHLADH[A^A_]H1LH[A^A_]mUHAWAVATSIIH׹H߾19IHuH5 HL1,H Lq HLL[A\A^A_]UHAWAVSPIHtHL@H[A^A_]H߾1IH߾1H5T HLLI1H[A^A_]+UHAWAVATSIIHH F HHCHHǾ-HtAIHH)LH?H5 LH1(LLHu0ILH5 LH1LLH[A\A^A_][A\A^A_]UHAWAVATSHIH/HHEؾ1s1ILGALL=H LL*uzL1H} LLLHX LL.HPHIDL)LLH' LLHXLt+H5UHXL{tLtH5 L1)LVL#L A|SA޻LCu+LLL11E1A˃uHpHH;EuHĐ[A\A^A_]/UHAWAVAUATSH( HH/HHEо1s/IH߾[ H>H߾عH߾LH߾9H߾ HH3H H߾׹tH5 H1(ALL- H߾LAu7H߾ L>2H߾1HLLH1'(HLH߾1E1/H߾ H߃t7H߅t+ L2  IGLH߾E H߾1E1H߾ tH߾LH߾LRu*H߾4H߾ H߾L\H)HH;EuH( [A\A]A^A_]UHr*rwƒ ʉ]UHJB]1Ɂr1ɉwUHH]UHAWAVAUATSHMIIՉI /s7A}u IEHEHuLasA|$u3I $HMA0sUA}L}AEEHuL$HMHUL8IAFAEA|$uzIUI $LIHuL"A|$uML}LLAEЉIAAFL}HuLåuPL}AEEA|$uML}LL蒥t!AEЉAAFL}ȃLLLLAH[A\A]A^A_]1 wgUHL[Ic4L]H.H)CH#HH镰HHHH!H H1HHHH鰰HHHïUHHf(fW H HcHXw\qYkf()M4f(f(]YfWfTPfUfVX2f(H]^^f(H]fWf(H]fw}UHHcH.qЉȃ DE]UHAWAVATSHIIHHHDu+tA-t HE1E10uSH xuHPHLtC1HHDt HcHPHLu4ʊLu11%1H HH4JHPHLu@tPHDu@ @u!HHEHDIANL)HH51LHt1H[A\A^A_]L}LLIL9tDtHHEHDuHȄuAUHHs AH?I1IMȉ$? DHHH9w)H I B4]UHAWAVATSH@HIHȮHHE؃~u!LH H}211uLcEH Le2L1PLcH5Lf|u fBD=.0IHuLLBH@@CH2HH;Eu H@[A\A^A_]UHAWAVAUATSHHHIIHHHEH%HIH]E1I_IG0H)H/L苆I_LL)HCIGLLBH@@CAUcHTHu%IIGHHIOH(;HHN6oHuodfVIGHHIOVHHHNVUcH(HHFpsH(HHFI_HCIGLH5IGHHIOH(HHN H(!HHFH(7HHF2HNHQHVH HNHQHV@HFHHHNЈUHDLH51"HFHHHNHHHHDHVMgIL$IOLHH?I$@@AD$HNHQHVHc H@IwHL9HFHHHNH0H}HcHuH)I_HCIGLZHFHHHNL(LeL1H 1HcI_HCIGLLI_HCIGLHu>H@@CAMIL%IHE1I_IG0H)HL I_LHKIOLLH>H@@CEtALDIGH@H H H;Mu$H HH[A\A]A^A_]H5L1wUHHL0IRIJMB MJ(t&)`)p)U)])e)m)u)}H[HHEHULRHEHBH0HH +H H;Mu H]UHAWAVAUATSPIHIHIĊ<@t*<=uSHM9IWLHCD>M9vlAF.fA..ILL)IHLHLPH߾ DH[string IAF"I IM9s7Hu2LHLMWHLHLH[A\A]A^A_]jII)HMDM9MGLHLHO$.IfAD$..AD$.AD$fA$"]H[A\A]A^A_]UHSPH/H1 & H5eH1/H[]UHSPHfHnfbf\f|^HH[]UHAWAVAUATSHX!IH6HHEH1IL~L 1HA?!uHHIIHHIMH5L^H%HL_#LLA<%tM=HH;rH AHIHHqH MwLIIE.EtEHkJ|DHt,DHKJ|?tNAt vHuCIIrLLH5L1!LHXM!ƅƅLIHHHHHHH H!OLPBL1 fIc6LdHLIcvLDHLIcvL$HLIcv LHLIcvHLHaL~IcvHlLH@LWIcvHLH"L4IcvHLtHLAv xLHLHHH;EuHX![A\A]A^A_]wUHAVSHIH߾pLHH[A^]UHAVSI118HHALHt [A^][A^]UHAVSHH߾uGE1A 1OIH߾%tH~5Hu1[A^]DUHSPH1HHHlH[]UHAVSI1HH1@LH[A^]UHAVSH1|IH߾1jLH1@H1[A^]DUHAVSH11IHPH qH߾HH $ L蠸L LD I\$0HE@K:HHKHIXQ(PIH @HKHHCL@L) IAD$,= = Ml$0AELL3A|$,u*L耱LiLHA|$,tL El$L}LLqLL,H}1LuDE1H]IFPIHcH4ITLLHdAD$A,u.AL議LLH3AAD$,t؃=L|HuL1H]LHD I|$0HuH7I|$0DAM} HH@8HcMȺ?#@";aH]LHANjLmLLz2A} uAuIH@8HcM%Av:E1HMLDvLD=!gIHcH IH4LbE}<L1LD/L!0LuDALD`HID$0H:HHut0~t*L)HEPL,+L*HuЀ~tKI~8H5~"#IN0IvXH DA LH1INXHH4@HHq L+HuLMD$DVEAT$:D)I|$LoXAMA8s8A|$ MMIcL$4I$H[PI IHHQHH| D9wAT$:AT$AA^tY|(A~AvAnAfA^AVANAFA>A 6A .A&AAA A A LmLmLeDHX;E~dAEELI}0DL5HqTXLLuL(I}0DLLDE5A߃uLmȸDLmIM8fH8[A\A]A^A_]I}0HH5L褤qqqqqqqUHAWAVAUATSH8IHLg0GEE1L 11E1 #AD}HELmHIEAE EuHED}D}H{0L)H߾{{}ubH߾}{MMЅEPH]LH޺'HCpS$L6K$LmEt6LL1)E}2uHEpUL2o6EC[t=$uH=u HLHL1EEЋC;t ,HX{}D}]tH]LH(K(HEpUL5I$H@8McAF#<}D I$H@8B?}% I $HI8BH8[A\A]A^A_]UHAWAVAUATSHhMЉUHuILo0Lg8M}Ic_ A9]0|RIW Iw@L LAmIG@IcO 9}$HHH9tIG@HHH9uLLsIIG@IcM0QAU0L$AG tAD$ tHLL tHpL ]A\$(IN0HHLpIF0(=@ E1Dh0Dh8DhuEH{0H]HCH [A^]UHAVSHLw8VH5LH1HH艔UHAWAVAUATSH(EA͉UAIH_0mLEDeHt(DvA1HMAS:QHSHRXr(qRQ AHCHHKLDHDLH4HDHEt'UԹ<Du>)D}D1EHDuD&AH߾*DAH߉DkHD&H([A\A]A^A_]UHAWAVSPLw0)ӋPs5ADIAWLHE~NLDH[A^A_]t LH~&E~^9u^9]u FNu^9]ufVH6Hu H6Hut&1Ƀ4MLE1LIE8D=AHuLDTL=HuLwD9uI}0Hu~I}0?HMLDD9~ A)IE0DxHnI$HHh_AD$W1I$H[A\A]A^A_]UHAVSHLwHw8K\Hh`HCHp0HcPIAǻLIH=rLHEtHI9uHHHfHH;EuH8 [A\A]A^A_]芝UHAWAVATSH0 HHfHHEؾAAH߾MH߾袻LHL%H5HLDwtH5H1A HHeHH;EuDH0 [A\A^A_]UH][UHAWAVAUATSH HHeHHEۺtLPH߾LIIHHXHHMH'LAH`A$<%uZMl$A|$%H%H;rHAMHIHHpH DHH;rHA$HIHHqH EHHHxEwD;tLX|LDHg1A $Ѓ IA$Ѓ IA$<.u6ID$AL$IT$ I HCAD$Ѓ HIЃ wLH51ƅ%LL)HSHL<ƄA$W~VBH [HcHLD2HLLH5&"HxLH1谛EAtEt GHHH5x"LD:HxHްiIHcHH`EI9M_XQLD~HxH1LDHhHHH;rHHHHPH"HhL=XHH;EuDH8 [A\A]A^A_]UHAWAVSH8 IHXHHELL=HIHLI7HtH1Ɋ3HHHH9w1HHWHH;EuH8 [A^A_]VUHAWAVSPIHUILHHHyHEHHH9s1HHLHHMHyHHH9s1HHHۺHOH9HOH)}H5L1I4HHLHOH[A^A_]UHAWAVATSH0 HHVHHELLIIHH_I?t$I1A<DAHHH9r1HcH VHH;EuH0 [A\A^A_]ߌUHAWAVAUATSH HHUHHEA1IHPHXHH`HHHHjA>y1HXIHHPHhLljANjlhHpD$~GHH;rHHHHPH˃IcLHEeALpMcDH HcHHxMHEDHA8B ɸHHHH9|H9|HDHj5`II?HHDdHxMHED$HA)B HHHtHDH`HHDE1EHxHLMnDIHA LHpZIHEDHLHIH9tHDHa HHLELHxLHDHKIAM,H HHtHDHH`HHDE1HHLHxH_IHEDHHH.H;tHDHHHHHHH;rHHHHPHHLIHHH;rHXHHHPHEiHp`ut91Ɋ A H9u!HtJ'H1Ɋ HH9uHEHP8EHHPHH;EuHĈ [A\A]A^A_]譇SSDDUHAWAVAUATSH(I1۾1HELuHHM8tv1L}H}HHUHMMaAHcELcmIŸL)H9vLHIAAuLHCLHEȀ8uLHaH([A\A]A^A_]UHAWAVAUATSHxHHOHHEо1IHxLuH߾LHEH߾IIMyLHH9sE1IIII9vHH߾ HhHHpA<$+E1H]LHhLHxHMLEALc}LceK@2@ƃ[t.t%u r] HHH]&1@8]UHAWAVSPAA/z.H HcHADHCADHBA1A ADHBADHBfADH|B KADHaB@0ADHFBAw{DH/B#DAS%BăwFH HcHAFZwBLIcLA !ulLAF jTtXuOA5A[AF:AALAJI>H5]1i2A'AALHA1H[A^A_]L+AAƃs A9H1ҍHQBЃ w H |AuI>H5s1袭hkkQQQ,C!UHSPHƃr+H1ۍ HPJЃ w H |ڍCwH?H5ڹ1茬H[]UHAWAVAUATSHAAH}~8AALD)1ۍPHEDHcH w1A EtAAϸDHLH)dAt^1H۹IEADEwAHuȉMEDADH9tH}H5_D1谫MHuAArHH[A\A]A^A_]ÐUHAWAVAUATSPIIIBtu4AF 1I$HHH=rt AF 9LLHII1LL1tIML}Ѓ{ uAD$@t IEI;$tHcCHHL<L,I1LL1LtM+~IAF B89s/IvHHHHH1:uL1UHAWAVSPHIF?^ȃwwH HcHH]HgYq, E؅IAN փHcttEuAN #gAN փ1OAN H #A 8L;A uI IwAW ~AG AG L;AN A#G HHIFH[A^A_]sUHHFO H9s HHGFO Љ!HcHHOHnyuH9qtHcQHHHHuH]UHO #F HcHHOHnyDuH9qtHcQHHHHuH]UHAWAVATSHIIF?L5YnIu^A$EeMf.uCzAf. mr7mf.v)H,[tRuI4$LH[A\A^A_]#LLHHs1L&u-HcCHHHHuI4$LH[A\A^A_]tILH[A\A^A_]UHAWAVATSIDg EtIFAL$H|tPH?oI9FA\$LHxt^@D<LLxADu81A1B!SH|uA܉D)ډكwWADD)r,C'LHxuADD)A܃wDsLbÃxu[A\A^A_]UHSP1u/H?HHHrtHwHH[]UHSPHBjqH1胍H5=H1H[]UHAWAVAUATSHH IH+HHEHrnH賣IHL]L HLL~ q 脮IHL8L9}8LLLHHHLL蔦HI9uuHHLLHަH*HH;EuHH [A\A]A^A_]aUHAWAVAUATSHIHu_L踭HL`LtwLoIH~M9~HˈL'L9|8HMHML}LcLHULLAHKL9HMLLU1H[A\A]A^A_]H5oL1H[A\A]A^A_]ʛUHAWAVSPI~ALƺL:E~ DLHʍHCHHwIcLHtlL背H[A^A_]UHAWAVAUATSHIHuL萣HL蓀L~   IE1H)|:H=wDAALD|t/LmILHAHI9uDH[A\A]A^A_]H59L1H[A\A]A^A_]nUHAWAVAUATSHIHuLiHLH谢IH9t"M~ HCI9~HLLuLLALmI9}:LmII\$LHALLUII9LuILmLLLAոH[A\A]A^A_]UHAWAVAUATSH(HpIH߾`IH߾PIH]H߾~E1AMHH}ȾBLL)LeHE]HmL(t H5L赟HHELDeHބHDt H+HDtHNJLL)HU~AH}]LmLeHMxnILLAHEJ0LUIM9uCH}]HMLex1ILLIH}ȉLULLeIIM9uLM}H([A\A]A^A_]UHAVSHHHusH߾̨IHNhH߾24H߾}~H߾aH߾zHuHߺDO1H[A^]UHAVSIHWtlH5kH见H߾訅t HTIH5 HxH߾yt H^IFH߾ zI>tI~u4H߾艝I>u HgII~u HňIF[A^]UHAWAVSPIHIHHH߾l|u.H߾{H߉{H5`HHL1LH[A^A_]NUHAWAVAUATSHH9AIHHuHULcH߾LA$McH߾LA$H߾KLuL}HtLAT$H߾LAT$ xEHEA)ALmDLcH߾LA$H߾L}LA$H߾u:H߾OxH߾L}LA$H߾YH߾LAT$H߾LAT$L}ALu9H߾LA$H߾yALMcH߾LLeH߾LLmAUH߾LAULEgMcH߾LH߾tiMcILeL;m|HH51H߾=wIH߾LA$H߾qADžuDHEAGAL}EAFELcH߾LHEH߾&EtUL;eHH5Q1ZH߾vIH߾LHEH߾A΅uAFE9AH߾YvH߾LuLLeA$H߾LA$H߾LAT$H߾LAT$HMD)HuA)H}WA9ADLADLLLHLEDE9H߾uHH[A\A]A^A_]UHAWAVSPAAHwtlH߾wAHDwAHDuwH߾1E1H߾HzAH߾)uDH[A^A_]HDDH[A^A_]xUHAWAVSPI1L=aJc4;LLɵINHYIFHXLHH`uH[A^A_]UHAVSAHHrxuDC 1[A^]UHFtuHH(HHHOHHHHtHOHH]H^]UHAWAVSPEHML+8HGHxH{HCHpHsHCHPHSEuHCHHHKAD)HHHsH)HC HBHDCEtHCHK8HPHS@B9H[A^A_]UHAWAVAUATSPEIIIHDxuHLDxt2AHHLLMADH[A\A]A^A_]E1UHAWAVATSHDIIIjt H[A\A^A_]ÍCsAu$AE(tuXLLLHuLt#A~u AEHuLu H |LLL$H |LLLUHSPAHHOtHKAtu19 H[]ÐUHAWAVSH(I<t <@t<=u HH >|H]HKL3HsHSH5hH+|H)L}HL(A?SfH}H]H ;QH5hH|H]HH{HsH{H_H{HKH{H7H{H#L}HLnI?xVH}H]HLf.]H}H]H3LlHIFH@FIFIN0HIFH)H L1L HCH}H19HH([A^A_]H5zH5zH5zH5zH}UHAWAVAUATSPHIIHHEI_hH]кLHRAG(H]кLH8AG,H]кLHAG H]кLHAG H]кLHAG H]кLHLc#I>LH11H8TIG8EgLHHH]кLHLc#I>LH11SIG0EgMHEI1DHI9uIE1LHu1EHw2HHc H1LHuEB#^<t<<u[LJ#@@ALHuEB#LHuHEJ#BD#M9t I_0I>H]кLHlHcI>HH11RIGXA_H~_AI1HHI9u1LeкLLEIOXDLLEIOXD HI9uH]кLHHcI>H 11@RIG@A_ H~WAHAtIO@HHI9u1I>IO@HIG@IWhH4LHI9uH]кLHGLc#I>LH11HQIGHEgLHHH]кLHHcI>HH11oQIGPA_$H~oAI1HHI9u1LeLIOPHLLEIOPDLLEIOPD HI9uH]кLH^D#E~I1LuIOXHHI9uH[A\A]A^A_]ÐO:UHAWAVAUATSHIIIHHHEHNHLmLLHLLHMuHHH;EuH[A\A]A^A_]LLpLUHSPHHH?HSH5u1kH;UHAWAVATSHIHILeߺL6A$H9u H[A\A^A_]I?H5uL1^kLHsUHSPHHN4HuH[]H5WuHFUHAVSHHLuLAHUHuLuHLIHt6H;HsHHUU4IHUHHbH;HULȨ1H[A^]UHSPHNR}H1uH5~'H1H5}VHpHtH߾wH[]UHAWAVAUATSPILmоL IL襍IIEHMHHLHIEHyHHH9s1HHH~HH9~H#tLMtUA$ x LMLEHHH?HuLHhr_ HEH}LEHUH HBBH+J H A Iq0fAfAIfAQ fAQPfAI@fAA0I`MOAALDH}HUHBLB IGHB(HHHJ(D MIAMAygfAAfA5 LHMH+HHMHIDi AAIcA<IG0I+GHH9LDH}HELMHHLIGMLDLELM-LMHMIHpHXIBD1FE~II1A|]At] tHHH}LMHM HEHD ID H@HI9uHp@ uLx`L}IGHx~ IMOLHEH@IG] HuLMLMLMMH}Ѕ_HuLM`HuL1MMLEq{I7AMŅuHHHHM1Dk2CLMHhA}LpuAEXDHhMLHXL"XH}IMLpHhAEAExu`uL.H]LHMMMLpMH}Ѕr\`AAAHJHH ArIAK!HIGHEH@x ~LLLrILL!HMABIW zHBIGmIW JB`Mg M4$IT$LL:IH@X HHEH@I\$ x ~IHr LI9sLLffHHH9rID$ L)LHB HMHAL)LIHAHBID$(HB(JB HQ HĈ[A\A]A^A_]H5CH5CH5CL1f61RYz(UtaQ`8{0N b@ SEC^UHSPHHwH HUSHtHUHtHHHHHKH[]UHH~ HVHNW]UHAWAVATSHtbIIIHHtIw!LrtAIIwHIHIwI9IFLHIH)II_II)HuE1L[A\A^A_]UHAVSHHHVH9s"H!A LCH3LqHLsH[A^]UHAWAVSPHA1XIHt$H;H5BHL1'=A H߾h>DH[A^A_]UHAWAVATSH1WIAH߾1WIH5AHLH1E1H1-9H߾16IH߾0HXL$u%\%1=@H2:ADHĘ[A^A_]UHAWAVSPI6H8E1HtVHHCHtEx.tHH{H1tH;WHCHuE1AL9DH[A^A_]UHAWAVSPHA1RIHǾt$H6H5=HL17A H߾19DH[A^A_]UHAWAVAUATSPI\/14L=,LHu1LHu1BRHH߾;IH߾:IMtM9LIBMIDIMtLH)LH+6E1L0LLi6L0LCL13HuPL.ILECLH 6AE1H]DsL<.9D1L9.H[A\A]A^A_]UHAWAVSPHA1QIH>t$H4H5e;HL16A H߾^7DH[A^A_]UHAWAVSHHA1PIHXHH߅tn4tk u|H5:d11u9H5H;H4HuHc4H߾:H5&;H4H*EH4H߾:7H5:HL1,5XH5:HL15ADHĘ[A^A_]UHAVSHI1H}1NuHiE@BHcMHH+HLH3H[A^]UHAWAVAUATSHIHHHEE111NHtI1H10 DHHHuLL 1ɈD HHuLu 1ɈD HHuLa 1ɈD HHu@H=9H5. HH}H IH EDEDMEHPEHXEHhEHpEHxEHEEHEDUD]DeL`Dm]DuD}H 8H}&11AWAVSAUATASARuuxphXP+ HpH`Hu.2AH4HH;EuDHĈ[A\A]A^A_] UHAVSH@HHHHE1=MLHL@HL1HHH;EuH@[A^] UHAWAVSH@HHHHE1LIH߾1LLLHL@HL'1H3HH;EuH@[A^A_] UH1܀8wHHs]Ã}1UHAWAVSPIHM<6Iϊ<8wHHLrL Ht Ht H1LL9MF1Hފt\t /)߃tt*u+uj/Hb;.u{.uHL9vE8/uE;.tCL9v x/t/HH9s-L9s(HÊKHL9sHKH9Hr A/L>tH^HL9UL9v HHx/HDL9HH[A^A_]UHAWAVAUATSHHHHEЃ}15AHI>$u,Aΰ$A HÄ HQL9HrLпL?DIHLIHƺ?'f/fAfAU:u.1/t uѿHp:HtIcHHcH/HпHsHŠ /tuH9sf..C/Hي=t H9sJ 'HHÊtHH9rHK{/HEHYH9HBH>HH;EuHH[A\A]A^A_].HUHAVSHE11QIHtAH߾/D[A^]UHSPHH5D"H1aWH5HH1IWH5HH11WH5'4Hc-H5L4H2H,H584H2H584H&-H5h4H2H5l4H-H5H5H2H5L5H,H5D5Hv21H[]UHAWAVAUATSH(I։IHHHE11$1L111CALHIcM,AE4I6IHuH5L,H Ln-L#L"L"AH5k3L,AL1DE1E13L1҅t.'Hp)L1~'HWA &D,HHH;EuDH([A\A]A^A_]UHAWAVSHIIHHHEHH9"HH1HH޹H5L1*LL)H=v1LH)L1E1E12t=LH5L(LL(LLt` !^L7#tH5L(LL{(L5L1%HHu!o~5L1%HLH+(H7HH;EuH[A^A_]UHAWAVATSIA VHHHAI6H,H51HX-EuHDLAHu]D[A\A^A_]UHAWAVAUATSPIE111BHL11lBHtLIHtDH;IL0A9|,IcHHH)HL1@L )ADH[A\A]A^A_]UHSPH1OBt=HHHHHHHufHnfb f\ f|M H&H[]UHHcHHEtHHHHHHЊHDŽu]Ð%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % %%%%%%%%%% %"%$%&%(%*%,%.%0%2%4%6%8%:%<%>%@%B%D%F%H%J%L%N%P%R%T%V%X%ZLAS%hxhhhhhhhhh*h<hNxh_nhodh}ZhPhFhh4h*h hh hhh)h8hGhUhghwhhhhhhhvhlhbhXh&Nh6DhF:hV0hf&huhhhhhhhh!h>hX$LuaVersion: Lua 5.3.0 Copyright (C) 1994-2015 Lua.org, PUC-Rio $$LuaAuthors: R. Ierusalimschy, L. H. de Figueiredo, W. Celes $p@ p@P?  o t { R -DT! @?cܥL@$@9RFߑ?>C`qATPP\l<f_G..light userdata%s expected, got %snumber has no integer representationcannot %s %s: %sPANIC: unprotected error in call to Lua API (%s) _GLua 5.3_VERSIONtypeassertcollectgarbagedofileerrorgetmetatableipairsloadfileloadnextpairspcallprintrawequalrawlenrawgetrawsetselectsetmetatabletonumbertostringxpcallassertion failed!stoprestartcollectcountstepsetpausesetstepmulisrunning__metatable__indexbt=(load)too many nested functionsreader function must return a string__pairs'tostring' must return a string to 'print' table or string expectedindex out of rangenil or table expectedcannot change a protected metatablebase out of range library 'bit32' has been deprecatedfunction or expression too complexcontrol structure too longopcodesconstantscreateresumerunningstatuswrapyieldisyieldablethread expectedtoo many arguments to resumecannot resume dead coroutinetoo many results to resumesuspendednormaldeaddebuggetuservaluegethookgetinfogetlocalgetregistrygetupvalueupvaluejoinupvalueidsetuservaluesethooksetlocalsetupvaluetracebacklua_debug> cont =(debug command)external hookcallreturnlinetail callflnStu>%sinvalid optionsourceshort_srclinedefinedlastlinedefinedwhatcurrentlinenupsnparamsisvarargnamenamewhatistailcallactivelinesfunclevel out of rangeLua function expectedinvalid upvalue indexk__modeattempt to %s a %s value%sconcatenatenumber%s has no integer representationattempt to compare two %s valuesattempt to compare %s with %s(*temporary)(*vararg)=[C]C=?mainLuahookfor iteratormetamethodlocal_ENVglobalfieldupvalueconstant (%s '%s')%s:%d: %sC stack overflowattempt to yield across a C-call boundaryattempt to yield from outside a coroutineerror in error handlingcannot resume non-suspended coroutinebinarytextattempt to load a %s chunk (mode is '%s')Lua  no messageerror in __gc metamethod (%s)packagecoroutinetableioosstringmathutf8_IO_inputstdin_IO_outputstdoutstderrcloseflushinputlinesoutputpopentmpfilewriteFILE*attempt to use a closed filestandard %s file is closedcannot open file '%s' (%s)file is already closedtoo many arguments%sinvalid formatpPeErwainvalid modewclosed filefile%lld%.14gseeksetvbuf__gcsetcurendnofullfile (closed)file (%p)cannot close standard file'%c''%s'andbreakdoelseelseifforfunctiongotoifinnotorrepeatthenuntilwhile//.....==>=<=~=<<>>::%s near %slexical element too longinvalid long string delimiterchunk has too many linescommentunfinished long %s (starting at line %d)unfinished stringinvalid escape sequencehexadecimal digit expectedmissing '{'UTF-8 value too largemissing '}'decimal escape too largeEexXPp-+malformed numberpihugemaxintegerminintegerabsacosasinatanceilcosdegexptointegerfloorfmodultlogmaxminmodfradrandomrandomseedsinsqrttanzerowrong number of argumentsinterval is emptyinterval too largeintegerfloattoo many %s (limit is %d)memory allocation error: block too bigpathLUA_PATH_5_3LUA_PATH/usr/local/share/lua/5.3/?.lua;/usr/local/share/lua/5.3/?/init.lua;/usr/local/lib/lua/5.3/?.lua;/usr/local/lib/lua/5.3/?/init.lua;./?.lua;./?/init.luacpathLUA_CPATH_5_3LUA_CPATH/usr/local/lib/lua/5.3/?.so;/usr/local/lib/lua/5.3/loadall.so;./?.so/ ; ? ! - configloaded_PRELOADpreloadloadlibsearchpathseeallsearchersinit/ no file '%s' no field package.preload['%s']'package.%s' must be a stringerror loading module '%s' from file '%s': %s_luaopen_%s no module '%s' in file '%s';;;;LUA_NOENVmodulerequire_NAME_M_PACKAGE'module' not called from a Lua function'package.searchers' must be a tablemodule '%s' not found:%s-0123456789(null)<\%d>%p%invalid option '%%%c' to 'lua_pushfstring'[string ""]nNMOVELOADKLOADKXLOADBOOLLOADNILGETUPVALGETTABUPGETTABLESETTABUPSETUPVALSETTABLENEWTABLESELFADDSUBMULMODPOWDIVIDIVBANDBORBXORSHLSHRUNMBNOTNOTLENCONCATJMPEQLTLETESTTESTSETCALLTAILCALLRETURNFORLOOPFORPREPTFORCALLTFORLOOPSETLISTCLOSUREVARARGEXTRAARGclockdatedifftimeexecutegetenvremoverenamesetlocaletimetmpname%c*tsechourdaymonthyearwdayydayisdstaAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%EcCxXyYOdeHImMSuUVwWyinvalid conversion specifier '%%%s'allcollatectypemonetarynumericfield '%s' missing in date table/tmp/lua_XXXXXXunable to generate a unique filenameupvaluesmain functionfunction at line %dtoo many %s (limit is %d) in %sC levelscannot use '...' outside a vararg functionselffunctionslocal variables or '...' expectedunexpected symbolfunction arguments expectedlabels/gotos at line %d jumps into the scope of local '%s'<%s> at line %d not inside a loopno visible label '%s' for at line %d%s expected (to close %s at line %d)%s expected'=' or 'in' expected(for index)(for limit)(for step)(for generator)(for state)(for control)label '%s' already defined on line %dsyntax errornot enough memorybytechardumpfindformatgmatchgsublenlowermatchrepreversesubupperpackpacksizeunpackstring slice too longvalue out of rangeunable to dump given function^$*+?.([%-pattern too complexmissing '[' after '%%f' in patterntoo many capturesinvalid pattern capturemalformed pattern (missing arguments to '%%b')malformed pattern (ends with '%%')malformed pattern (missing ']')invalid capture index %%%dunfinished captureno valuellinvalid option '%%%c' to 'format'invalid format (repeated flags)invalid format (width or precision too long)\%d\%03dstring/function/table expectedinvalid replacement value (a %s)invalid use of '%c' in replacement stringresulting string too largeinteger overflowunsigned overflowwrong lengthstring length does not fit in given sizestring contains zerosinvalid next option for option 'X'format asks for alignment not power of 2missing size for format option 'c'invalid format option '%c'integral size (%d) out of limits [1,%d]format result too largevariable-length formatinitial position out of stringdata string too shorttoo many results%d-byte integer does not fit into Lua Integertable index is niltable index is NaNinvalid key to 'next'table overflowconcatinsertmovesort__newindexinvalid value (%s) at index %d in table for 'concat'position out of boundswrong number of arguments to 'insert'too many results to unpackinitial position must be positiveinvalid order function for sortingbooleannumberthreadproto__len__eq__add__sub__mul__mod__pow__div__idiv__band__bor__bxor__shl__shr__unm__bnot__lt__le__concat__callperform bitwise operation onperform arithmetic onbinary stringnot aversion mismatch informat mismatch incorruptedintsize_tInstructionlua_Integerlua_Numberendianness mismatch infloat format mismatch intruncated%s: %s precompiled chunk%s size mismatch incharpatternoffsetcodepointcodesposition out of rangeinitial position is a continuation byteout of rangeinvalid UTF-8 code%Ufinal position out of stringindexgettable chain too long; possible loopsettable chain too long; possible loopstring length overflowget length ofattempt to divide by zeroattempt to perform 'n%%0''for' limit must be a number'for' step must be a number'for' initial value must be a numberunable to switch to directory '%s'cp %s %sunable to copy file to '%s'%s/%sunable to create directory '%s'unable to remove directory '%s''%s' could not be accessed'%s' was not foundAn unknown error %d occured while accessing '%s'mtimesize/dev/urandom%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02XLua 5.3.0 Copyright (C) 1994-2015 Lua.org, PUC-Rio_COPYRIGHT_GENIE_VERSIONversion 1167 (commit b139103697bbb62db895e4cc7bfe202bcff4ff25)_GENIE_VERSION_STRCopyright (c) 2014-2018 Branimir Karadžić, Neil Richardson, Mike Popoloski, Drew Solomon, Ted de Munnik, Miodrag Milanović Brett Vickers, Terry Hendrix II, Johan Skoeld. Copyright (C) 2002-2013 Jason Perkins and the Premake Project_PREMAKE_COPYRIGHTmacosx_OSPATHisabsolutegetabsolutegetrelativechdircopyfile_is64bitisdirgetcwdisfilematchdonematchisfilematchnamematchnextmatchstartmkdirpathsearchrmdirstatticksuuidendswith_ACTION_ARGS_OPTIONS_premake_main_PREMAKE_COMMANDfunction os.executef(cmd, ...) local arg={...} cmd = string.format(cmd, table.unpack(arg)) return os.execute(cmd) end local function parse_ld_so_conf(conf_file) local first, last local dirs = { } local file = io.open(conf_file) if file == nil then return dirs end for line in file:lines() do first = line:find("#", 1, true) if first ~= nil then line = line:sub(1, first - 1) end if line ~= "" then first, last = line:find("include%s+") if first ~= nil then local include_glob = line:sub(last + 1) local includes = os.matchfiles(include_glob) for _, v in ipairs(includes) do dirs = table.join(dirs, parse_ld_so_conf(v)) end else table.insert(dirs, line) end end end return dirs end function os.findlib(libname) local path, formats if os.is("windows") then formats = { "%s.dll", "%s" } path = os.getenv("PATH") else if os.is("macosx") then formats = { "lib%s.dylib", "%s.dylib" } path = os.getenv("DYLD_LIBRARY_PATH") else formats = { "lib%s.so", "%s.so" } path = os.getenv("LD_LIBRARY_PATH") or "" for _, v in ipairs(parse_ld_so_conf("/etc/ld.so.conf")) do path = path .. ":" .. v end end table.insert(formats, "%s") path = path or "" if os.is64bit() then path = path .. ":/lib64:/usr/lib64/:usr/local/lib64" end path = path .. ":/lib:/usr/lib:/usr/local/lib" end for _, fmt in ipairs(formats) do local name = string.format(fmt, libname) local result = os.pathsearch(name, path) if result then return result end end end function os.get() return _OPTIONS.os or _OS end function os.is(id) return (os.get():lower() == id:lower()) end local _64BitHostTypes = { "x86_64", "ia64", "amd64", "ppc64", "powerpc64", "sparc64", "arm64" } function os.is64bit() if (os._is64bit()) then return true end local arch = "" if _OS == "windows" then arch = os.getenv("PROCESSOR_ARCHITECTURE") elseif _OS == "macosx" then arch = os.outputof("echo $HOSTTYPE") else arch = os.outputof("uname -m") end if nil ~= arch then arch = arch:lower() for _, hosttype in ipairs(_64BitHostTypes) do if arch:find(hosttype) then return true end end end return false end local function domatch(result, mask, wantfiles) if mask:startswith("./") then mask = mask:sub(3) end local basedir = mask local starpos = mask:find("%*") if starpos then basedir = basedir:sub(1, starpos - 1) end basedir = path.getdirectory(basedir) if (basedir == ".") then basedir = "" end local recurse = mask:find("**", nil, true) mask = path.wildcards(mask) local function matchwalker(basedir) local wildcard = path.join(basedir, "*") local m = os.matchstart(wildcard) while (os.matchnext(m)) do local isfile = os.matchisfile(m) if ((wantfiles and isfile) or (not wantfiles and not isfile)) then local fname = path.join(basedir, os.matchname(m)) if fname:match(mask) == fname then table.insert(result, fname) end end end os.matchdone(m) if recurse then m = os.matchstart(wildcard) while (os.matchnext(m)) do if not os.matchisfile(m) then local dirname = os.matchname(m) matchwalker(path.join(basedir, dirname)) end end os.matchdone(m) end end matchwalker(basedir) end function os.matchdirs(...) local arg={...} local result = { } for _, mask in ipairs(arg) do domatch(result, mask, false) end return result end function os.matchfiles(...) local arg={...} local result = { } for _, mask in ipairs(arg) do domatch(result, mask, true) end return result end local builtin_mkdir = os.mkdir function os.mkdir(p) local dir = iif(p:startswith("/"), "/", "") for part in p:gmatch("[^/]+") do dir = dir .. part if (part ~= "" and not path.isabsolute(part) and not os.isdir(dir)) then local ok, err = builtin_mkdir(dir) if (not ok) then return nil, err end end dir = dir .. "/" end return true end function os.outputof(cmd) local pipe = io.popen(cmd) local result = pipe:read('*a') pipe:close() return result end local builtin_rmdir = os.rmdir function os.rmdir(p) local dirs = os.matchdirs(p .. "/*") for _, dname in ipairs(dirs) do os.rmdir(dname) end local files = os.matchfiles(p .. "/*") for _, fname in ipairs(files) do os.remove(fname) end builtin_rmdir(p) end function path.getbasename(p) local name = path.getname(p) local i = name:findlast(".", true) if (i) then return name:sub(1, i - 1) else return name end end function path.removeext(name) local i = name:findlast(".", true) if (i) then return name:sub(1, i - 1) else return name end end function path.getdirectory(p) local i = p:findlast("/", true) if (i) then if i > 1 then i = i - 1 end return p:sub(1, i) else return "." end end function path.getdrive(p) local ch1 = p:sub(1,1) local ch2 = p:sub(2,2) if ch2 == ":" then return ch1 end end function path.getextension(p) local i = p:findlast(".", true) if (i) then return p:sub(i) else return "" end end function path.getname(p) local i = p:findlast("[/\\]") if (i) then return p:sub(i + 1) else return p end end function path.getcommonbasedir(a, b) a = path.getdirectory(a)..'/' b = path.getdirectory(b)..'/' local idx = 0 while (true) do local tst = a:find('/', idx + 1, true) if tst then if a:sub(1,tst) == b:sub(1,tst) then idx = tst else break end else break end end local result = '' if idx > 1 then result = a:sub(1, idx - 1)-- Remove the trailing slash to be consistent with other functions. end return result end function path.hasextension(fname, extensions) local fext = path.getextension(fname):lower() if type(extensions) == "table" then for _, extension in pairs(extensions) do if fext == extension then return true end end return false else return (fext == extensions) end end function path.iscfile(fname) return path.hasextension(fname, { ".c", ".m" }) end function path.iscppfile(fname) return path.hasextension(fname, { ".cc", ".cpp", ".cxx", ".c++", ".c", ".m", ".mm" }) end function path.iscxfile(fname) return path.hasextension(fname, ".cx") end function path.isobjcfile(fname) return path.hasextension(fname, { ".m", ".mm" }) end function path.iscppheader(fname) return path.hasextension(fname, { ".h", ".hh", ".hpp", ".hxx" }) end function path.iscppmodule(fname) return path.hasextension(fname, { ".ixx", ".cppm" }) end function path.isappxmanifest(fname) return path.hasextension(fname, ".appxmanifest") end function path.isandroidbuildfile(fname) return path.getname(fname) == "AndroidManifest.xml" end function path.isnatvis(fname) return path.hasextension(fname, ".natvis") end function path.isasmfile(fname) return path.hasextension(fname, { ".asm", ".s", ".S" }) end function path.isvalafile(fname) return path.hasextension(fname, ".vala") end function path.isgresource(fname) local ending = ".gresource.xml" return ending == "" or fname:sub(-#ending) == ending end function path.isswiftfile(fname) return path.hasextension(fname, ".swift") end function path.issourcefile(fname) return path.iscfile(fname) or path.iscppfile(fname) or path.iscxfile(fname) or path.isasmfile(fname) or path.isvalafile(fname) or path.isswiftfile(fname) end function path.issourcefilevs(fname) return path.hasextension(fname, { ".cc", ".cpp", ".cxx", ".c++", ".c" }) or path.iscxfile(fname) or path.iscppmodule(fname) end function path.isobjectfile(fname) return path.hasextension(fname, { ".o", ".obj" }) end function path.isresourcefile(fname) return path.hasextension(fname, ".rc") end function path.isimagefile(fname) local extensions = { ".png" } local ext = path.getextension(fname):lower() return table.contains(extensions, ext) end function path.join(...) local arg={...} local numargs = select("#", ...) if numargs == 0 then return ""; end local allparts = {} for i = numargs, 1, -1 do local part = select(i, ...) if part and #part > 0 and part ~= "." then while part:endswith("/") do part = part:sub(1, -2) end table.insert(allparts, 1, part) if path.isabsolute(part) then break end end end return table.concat(allparts, "/") end function path.rebase(p, oldbase, newbase) p = path.getabsolute(path.join(oldbase, p)) p = path.getrelative(newbase, p) return p end function path.translate(p, sep) if (type(p) == "table") then local result = { } for _, value in ipairs(p) do table.insert(result, path.translate(value)) end return result else if (not sep) then if (os.is("windows")) then sep = "\\" else sep = "/" end end local result = p:gsub("[/\\]", sep) return result end end function path.wildcards(pattern) pattern = pattern:gsub("([%+%.%-%^%$%(%)%%])", "%%%1") pattern = pattern:gsub("%*%*", "\001") pattern = pattern:gsub("%*", "\002") pattern = pattern:gsub("\001", ".*") pattern = pattern:gsub("\002", "[^/]*") return pattern end function path.trimdots(p) local changed repeat changed = true if p:startswith("./") then p = p:sub(3) elseif p:startswith("../") then p = p:sub(4) else changed = false end until not changed return p end function path.rebase(p, oldbase, newbase) p = path.getabsolute(path.join(oldbase, p)) p = path.getrelative(newbase, p) return p end function path.replaceextension(p, newext) local ext = path.getextension(p) if not ext then return p end if #newext > 0 and not newext:findlast(".", true) then newext = "."..newext end return p:match("^(.*)"..ext.."$")..newext end function string.explode(s, pattern, plain) if (pattern == '') then return false end local pos = 0 local arr = { } for st,sp in function() return s:find(pattern, pos, plain) end do table.insert(arr, s:sub(pos, st-1)) pos = sp + 1 end table.insert(arr, s:sub(pos)) return arr end function string.findlast(s, pattern, plain) local curr = 0 local term = nil repeat local next, nextterm = s:find(pattern, curr + 1, plain) if (next) then curr = next term = nextterm end until (not next) if (curr > 0) then return curr, term end end function string.startswith(haystack, needle) return (haystack:find(needle, 1, true) == 1) end function string.trim(s) return (s:gsub("^%s*(.-)%s*$", "%1")) end function table.contains(t, value) for _, v in pairs(t) do if v == value then return true end end return false end function table.icontains(t, value) for _, v in ipairs(t) do if v == value then return true end end return false end function table.deepcopy(object) local seen = {} local function copy(object) if type(object) ~= "table" then return object elseif seen[object] then return seen[object] end local clone = {} seen[object] = clone for key, value in pairs(object) do clone[key] = copy(value) end setmetatable(clone, getmetatable(object)) return clone end return copy(object) end function table.extract(arr, fname) local result = { } for _,v in ipairs(arr) do table.insert(result, v[fname]) end return result end function table.flatten(arr) local result = { } local function flatten(arr) for _, v in ipairs(arr) do if type(v) == "table" then flatten(v) else table.insert(result, v) end end end flatten(arr) return result end function table.implode(arr, before, after, between) local result = "" for _,v in ipairs(arr) do if (result ~= "" and between) then result = result .. between end result = result .. before .. v .. after end return result end function table.insertflat(tbl, values) if type(values) == "table" then for _, value in ipairs(values) do table.insertflat(tbl, value) end else table.insert(tbl, values) end end function table.isempty(t) return next(t) == nil end function table.join(...) local arg={...} local result = { } for _,t in ipairs(arg) do if type(t) == "table" then for _,v in ipairs(t) do table.insert(result, v) end else table.insert(result, t) end end return result end function table.keys(tbl) local keys = {} for k, _ in pairs(tbl) do table.insert(keys, k) end return keys end function table.sortedpairs(t) local keys = table.keys(t) local i = 0 table.sort(keys) return function() i = i + 1 if keys[i] == nil then return nil end return keys[i], t[keys[i]] end end function table.merge(...) local arg={...} local result = { } for _,t in ipairs(arg) do if type(t) == "table" then for k,v in pairs(t) do result[k] = v end else error("invalid value") end end return result end function table.translate(arr, translation) local result = { } for _, value in ipairs(arr) do local tvalue if type(translation) == "function" then tvalue = translation(value) else tvalue = translation[value] end if (tvalue) then table.insert(result, tvalue) end end return result end function table.reverse(arr) for i=1, math.floor(#arr / 2) do arr[i], arr[#arr - i + 1] = arr[#arr - i + 1], arr[i] end return arr end function table.arglist(arg, value) if #value > 0 then local args = {} for _, val in ipairs(value) do table.insert(args, string.format("%s %s", arg, val)) end return table.concat(args, " ") else return "" end end io.eol = "\n" io.indent = "\t" io.indentLevel = 0 local function _escaper(v) return v end _esc = _escaper function io.capture() local prev = io.captured io.captured = '' return prev end function io.endcapture(restore) local captured = io.captured io.captured = restore return captured end local builtin_open = io.open function io.open(fname, mode) if (mode) then if (mode:find("w")) then local dir = path.getdirectory(fname) ok, err = os.mkdir(dir) if (not ok) then error(err, 0) end end end return builtin_open(fname, mode) end function io.printf(msg, ...) local arg={...} if not io.eol then io.eol = "\n" end if not io.indent then io.indent = "\t" end if type(msg) == "number" then s = string.rep(io.indent, msg) .. string.format(table.unpack(arg)) else s = string.format(msg, table.unpack(arg)) end if io.captured then io.captured = io.captured .. s .. io.eol else io.write(s) io.write(io.eol) end end function io.xprintf(msg, ...) local arg = {...} for i = 1, #arg do arg[i] = io.esc(arg[i]) end io.printf(msg, unpack(arg)) end function io.esc(value) if type(value) == "table" then local result = {} local n = #value for i = 1, n do table.insert(result, io.esc(value[i])) end return result end return _esc(value or "") end function io.escaper(func) _esc = func or _escaper end _p = io.printf _x = io.xprintf premake = { } premake.platforms = { Native = { cfgsuffix = "", }, x32 = { cfgsuffix = "32", }, x64 = { cfgsuffix = "64", }, Universal = { cfgsuffix = "univ", }, Universal32 = { cfgsuffix = "univ32", }, Universal64 = { cfgsuffix = "univ64", }, PS3 = { cfgsuffix = "ps3", iscrosscompiler = true, nosharedlibs = true, namestyle = "PS3", }, WiiDev = { cfgsuffix = "wii", iscrosscompiler = true, namestyle = "PS3", }, Xbox360 = { cfgsuffix = "xbox360", iscrosscompiler = true, namestyle = "windows", }, PowerPC = { cfgsuffix = "ppc", iscrosscompiler = true, }, ARM = { cfgsuffix = "ARM", iscrosscompiler = true, }, ARM64 = { cfgsuffix = "ARM64", iscrosscompiler = true, }, Orbis = { cfgsuffix = "orbis", iscrosscompiler = true, namestyle = "Orbis", }, Durango = { cfgsuffix = "durango", iscrosscompiler = true, nosharedlibs = true, namestyle = "windows", }, TegraAndroid = { cfgsuffix = "tegraandroid", iscrosscompiler = true, namestyle = "TegraAndroid", }, NX32 = { cfgsuffix = "nx32", iscrosscompiler = true, namestyle = "NX", }, NX64 = { cfgsuffix = "nx64", iscrosscompiler = true, namestyle = "NX", }, Emscripten = { cfgsuffix = "emscripten", iscrosscompiler = true, nosharedlibs = true, namestyle = "Emscripten", }, } local builtin_dofile = dofile function dofile(fname) local oldcwd = os.getcwd() local oldfile = _SCRIPT if (not os.isfile(fname)) then local path = os.pathsearch(fname, _OPTIONS["scripts"], os.getenv("PREMAKE_PATH")) if (path) then fname = path.."/"..fname end end _SCRIPT = path.getabsolute(fname) local newcwd = path.getdirectory(_SCRIPT) os.chdir(newcwd) local a, b, c, d, e, f = builtin_dofile(_SCRIPT) _SCRIPT = oldfile os.chdir(oldcwd) return a, b, c, d, e, f end function iif(expr, trueval, falseval) if (expr) then return trueval else return falseval end end function include(fname) local dir, name = premake.findDefaultScript(fname, false) if dir ~= nil then return dofile(dir .. "/" .. name) end return nil end function printf(msg, ...) local arg={...} print(string.format(msg, table.unpack(arg))) end function typex(t) local mt = getmetatable(t) if (mt) then if (mt.__type) then return mt.__type end end return type(t) end premake.action = { } premake.action.list = { } function premake.action.add(a) local missing for _, field in ipairs({"description", "trigger"}) do if (not a[field]) then missing = field end end if (missing) then error("action needs a " .. missing, 3) end premake.action.list[a.trigger] = a end function premake.action.call(name) local a = premake.action.list[name] for sln in premake.solution.each() do if a.onsolution then a.onsolution(sln) end if sln.postsolutioncallbacks then for _,cb in ipairs(sln.postsolutioncallbacks) do cb(sln) end end for prj in premake.solution.eachproject(sln) do if a.onproject then a.onproject(prj) end if prj.postprojectcallbacks then for _,cb in ipairs(prj.postprojectcallbacks) do cb(prj) end end end end if a.execute then a.execute() end end function premake.action.current() return premake.action.get(_ACTION) end function premake.action.get(name) return premake.action.list[name] end function premake.action.each() local keys = { } for _, action in pairs(premake.action.list) do table.insert(keys, action.trigger) end table.sort(keys) local i = 0 return function() i = i + 1 return premake.action.list[keys[i]] end end function premake.action.set(name) _ACTION = name local action = premake.action.get(name) if action then _OS = action.os or _OS end end function premake.action.supports(action, feature) if not action then return false end if action.valid_languages then if table.contains(action.valid_languages, feature) then return true end end if action.valid_kinds then if table.contains(action.valid_kinds, feature) then return true end end return false end premake.option = { } premake.option.list = { } function premake.option.add(opt) local missing for _, field in ipairs({ "description", "trigger" }) do if (not opt[field]) then missing = field end end if (missing) then error("option needs a " .. missing, 3) end premake.option.list[opt.trigger] = opt end function premake.option.get(name) return premake.option.list[name] end function premake.option.each() local keys = { } for _, option in pairs(premake.option.list) do table.insert(keys, option.trigger) end table.sort(keys) local i = 0 return function() i = i + 1 return premake.option.list[keys[i]] end end function premake.option.validate(values) for key, value in pairs(values) do local opt = premake.option.get(key) if (not opt) then return false, "invalid option '" .. key .. "'" end if (opt.value and value == "") then return false, "no value specified for option '" .. key .. "'" end if opt.allowed then local found = false for _, match in ipairs(opt.allowed) do if match[1] == value then found = true break end end if not found then return false, string.format("invalid value '%s' for option '%s'", value, key) end end end return true end premake.tree = { } local tree = premake.tree function premake.tree.new(n) local t = { name = n, children = { } } return t end function premake.tree.add(tr, p, onaddfunc) if p == "." then return tr end if p == "/" then return tr end local parentnode = tree.add(tr, path.getdirectory(p), onaddfunc) local childname = path.getname(p) if childname == ".." then return parentnode end local childnode = parentnode.children[childname] if not childnode or childnode.path ~= p then childnode = tree.insert(parentnode, tree.new(childname)) childnode.path = p if onaddfunc then onaddfunc(childnode) end end return childnode end function premake.tree.insert(parent, child) table.insert(parent.children, child) if child.name then parent.children[child.name] = child end child.parent = parent return child end function premake.tree.getlocalpath(node) if node.parent.path then return node.name elseif node.cfg then return node.cfg.name else return node.path end end function premake.tree.remove(node) local children = node.parent.children for i = 1, #children do if children[i] == node then table.remove(children, i) end end node.children = {} end function premake.tree.sort(tr) tree.traverse(tr, { onnode = function(node) table.sort(node.children, function(a,b) return a.name < b.name end) end }, true) end function premake.tree.traverse(t, fn, includeroot, initialdepth) local donode, dochildren donode = function(node, fn, depth) if node.isremoved then return end if fn.onnode then fn.onnode(node, depth) end if #node.children > 0 then if fn.onbranchenter then fn.onbranchenter(node, depth) end if fn.onbranch then fn.onbranch(node, depth) end dochildren(node, fn, depth + 1) if fn.onbranchexit then fn.onbranchexit(node, depth) end else if fn.onleaf then fn.onleaf(node, depth) end end end dochildren = function(parent, fn, depth) local i = 1 while i <= #parent.children do local node = parent.children[i] donode(node, fn, depth) if node == parent.children[i] then i = i + 1 end end end if not initialdepth then initialdepth = 0 end if includeroot then donode(t, fn, initialdepth) else dochildren(t, fn, initialdepth) end end premake.solution = { } premake.solution.list = { } function premake.solution.new(name) local sln = { } table.insert(premake.solution.list, sln) premake.solution.list[name] = sln setmetatable(sln, { __type="solution" }) sln.name = name sln.basedir = os.getcwd() sln.projects = { } sln.blocks = { } sln.configurations = { } sln.groups = { } sln.importedprojects = { } return sln end function premake.solution.each() local i = 0 return function () i = i + 1 if i <= #premake.solution.list then return premake.solution.list[i] end end end function premake.solution.eachproject(sln) local i = 0 return function () i = i + 1 if (i <= #sln.projects) then return premake.solution.getproject(sln, i) end end end function premake.solution.eachgroup(sln) local i = 0 return function() i = i + 1 if(i <= #sln.groups) then return premake.solution.getgroup(sln, i) end end end function premake.solution.get(key) return premake.solution.list[key] end function premake.solution.getproject(sln, idx) local prj = sln.projects[idx] local cfg = premake.getconfig(prj) cfg.name = prj.name return cfg end function premake.solution.getgroup(sln, idx) local grp = sln.groups[idx] return grp endpremake.project = { } function premake.project.buildsourcetree(prj, allfiles) local tr = premake.tree.new(prj.name) tr.project = prj local isvpath local function onadd(node) node.isvpath = isvpath end for fcfg in premake.project.eachfile(prj, allfiles) do isvpath = (fcfg.name ~= fcfg.vpath) local node = premake.tree.add(tr, fcfg.vpath, onadd) node.cfg = fcfg end premake.tree.sort(tr) return tr end function premake.eachconfig(prj, platform) if prj.project then prj = prj.project end local cfgs = prj.solution.configurations local i = 0 return function () i = i + 1 if i <= #cfgs then return premake.getconfig(prj, cfgs[i], platform) end end end function premake.project.eachfile(prj, allfiles) if not prj.project then prj = premake.getconfig(prj) end local i = 0 local t = iif(allfiles, prj.allfiles, prj.files) local c = iif(allfiles, prj.__allfileconfigs, prj.__fileconfigs) return function () i = i + 1 if (i <= #t) then local fcfg = c[t[i]] fcfg.vpath = premake.project.getvpath(prj, fcfg.name) return fcfg end end end function premake.esc(value) if (type(value) == "table") then local result = { } for _,v in ipairs(value) do table.insert(result, premake.esc(v)) end return result else value = value:gsub('&', "&") value = value:gsub('"', """) value = value:gsub("'", "'") value = value:gsub('<', "<") value = value:gsub('>', ">") value = value:gsub('\r', " ") value = value:gsub('\n', " ") return value end end function premake.filterplatforms(sln, map, default) local result = { } local keys = { } if sln.platforms then for _, p in ipairs(sln.platforms) do if map[p] and not table.contains(keys, map[p]) then table.insert(result, p) table.insert(keys, map[p]) end end end if #result == 0 and default then table.insert(result, default) end return result end function premake.findproject(name) for sln in premake.solution.each() do for prj in premake.solution.eachproject(sln) do if (prj.name == name) then return prj end end end end function premake.findfile(prj, extension) for _, fname in ipairs(prj.files) do if fname:endswith(extension) then return fname end end end function premake.getconfig(prj, cfgname, pltname) prj = prj.project or prj if pltname == "Native" or not table.contains(prj.solution.platforms or {}, pltname) then pltname = nil end local key = (cfgname or "") if pltname then key = key .. pltname end return prj.__configs[key] end function premake.getconfigname(cfgname, platform, useshortname) if cfgname then local name = cfgname if platform and platform ~= "Native" then if useshortname then name = name .. premake.platforms[platform].cfgsuffix else name = name .. "|" .. platform end end return iif(useshortname, name:lower(), name) end end function premake.getdependencies(prj) prj = prj.project or prj local results = { } for _, cfg in pairs(prj.__configs) do for _, link in ipairs(cfg.links) do local dep = premake.findproject(link) if dep and not table.contains(results, dep) then table.insert(results, dep) end end end return results end function premake.project.getbasename(prjname, pattern) return pattern:gsub("%%%%", prjname) end function premake.project.getfilename(prj, pattern) local fname = premake.project.getbasename(prj.name, pattern) fname = path.join(prj.location, fname) return path.getrelative(os.getcwd(), fname) end function premake.getlinks(cfg, kind, part) local result = iif (part == "directory" and kind == "all", cfg.libdirs, {}) local cfgname = iif(cfg.name == cfg.project.name, "", cfg.name) local pathstyle = premake.getpathstyle(cfg) local namestyle = premake.getnamestyle(cfg) local function canlink(source, target) if (target.kind ~= "SharedLib" and target.kind ~= "StaticLib") then return false end if premake.iscppproject(source) then return premake.iscppproject(target) elseif premake.isdotnetproject(source) then return premake.isdotnetproject(target) elseif premake.isswiftproject(source) then return premake.isswiftproject(source) or premake.iscppproject(source) end end for _, link in ipairs(cfg.links) do local item local prj = premake.findproject(link) if prj and kind ~= "system" then local prjcfg = premake.getconfig(prj, cfgname, cfg.platform) if kind == "dependencies" or canlink(cfg, prjcfg) then if (part == "directory") then item = path.rebase(prjcfg.linktarget.directory, prjcfg.location, cfg.location) elseif (part == "basename") then item = prjcfg.linktarget.basename elseif (part == "fullpath") then item = path.rebase(prjcfg.linktarget.fullpath, prjcfg.location, cfg.location) elseif (part == "object") then item = prjcfg end end elseif not prj and (kind == "system" or kind == "all") then if (part == "directory") then item = path.getdirectory(link) elseif (part == "fullpath") then item = link if namestyle == "windows" then if premake.iscppproject(cfg) then item = item .. ".lib" elseif premake.isdotnetproject(cfg) then item = item .. ".dll" end end elseif part == "name" then item = path.getname(link) elseif part == "basename" then item = path.getbasename(link) else item = link end if item:find("/", nil, true) then item = path.getrelative(cfg.project.location, item) end end if item then if pathstyle == "windows" and part ~= "object" then item = path.translate(item, "\\") end if not table.contains(result, item) then table.insert(result, item) end end end return result end function premake.getnamestyle(cfg) return premake.platforms[cfg.platform].namestyle or premake.gettool(cfg).namestyle or "posix" end function premake.getpathstyle(cfg) if premake.action.current().os == "windows" then return "windows" else return "posix" end end function premake.gettarget(cfg, direction, pathstyle, namestyle, system) if system == "bsd" then system = "linux" end local kind = cfg.kind if premake.iscppproject(cfg) or premake.isvalaproject(cfg) then if (namestyle == "windows" or system == "windows") and kind == "SharedLib" and direction == "link" and not cfg.flags.NoImportLib then kind = "StaticLib" end if namestyle == "posix" and system == "windows" and kind ~= "StaticLib" then namestyle = "windows" end end local field = "build" if direction == "link" and cfg.kind == "SharedLib" then field = "implib" end local name = cfg[field.."name"] or cfg.targetname or cfg.project.name local dir = cfg[field.."dir"] or cfg.targetdir or path.getrelative(cfg.location, cfg.basedir) local subdir = cfg[field.."subdir"] or cfg.targetsubdir or "." local prefix = "" local suffix = "" local ext = "" local bundlepath, bundlename dir = path.join(dir, subdir) if namestyle == "windows" then if kind == "ConsoleApp" or kind == "WindowedApp" then ext = ".exe" elseif kind == "SharedLib" then ext = ".dll" elseif kind == "StaticLib" then ext = ".lib" end elseif namestyle == "posix" then if kind == "WindowedApp" and system == "macosx" and not cfg.options.SkipBundling then bundlename = name .. ".app" bundlepath = path.join(dir, bundlename) dir = path.join(bundlepath, "Contents/MacOS") elseif (kind == "ConsoleApp" or kind == "WindowedApp") and system == "os2" then ext = ".exe" elseif kind == "SharedLib" then prefix = "lib" ext = iif(system == "macosx", ".dylib", ".so") elseif kind == "StaticLib" then prefix = "lib" ext = ".a" end elseif namestyle == "PS3" then if kind == "ConsoleApp" or kind == "WindowedApp" then ext = ".elf" elseif kind == "StaticLib" then prefix = "lib" ext = ".a" end elseif namestyle == "Orbis" then if kind == "ConsoleApp" or kind == "WindowedApp" then ext = ".elf" elseif kind == "StaticLib" then prefix = "lib" ext = ".a" elseif kind == "SharedLib" then ext = ".prx" end elseif namestyle == "TegraAndroid" then if kind == "ConsoleApp" or kind == "WindowedApp" or kind == "SharedLib" then prefix = "lib" ext = ".so" elseif kind == "StaticLib" then prefix = "lib" ext = ".a" end elseif namestyle == "NX" then if kind == "ConsoleApp" or kind == "WindowedApp" then ext = ".nspd_root" elseif kind == "StaticLib" then ext = ".a" elseif kind == "SharedLib" then ext = ".nro" end elseif namestyle == "Emscripten" then if kind == "ConsoleApp" or kind == "WindowedApp" then ext = ".html" elseif kind == "StaticLib" then ext = ".bc" elseif kind == "SharedLib" then ext = ".js" end end prefix = cfg[field.."prefix"] or cfg.targetprefix or prefix suffix = cfg[field.."suffix"] or cfg.targetsuffix or suffix ext = cfg[field.."extension"] or cfg.targetextension or ext local result = { } result.basename = name .. suffix result.name = prefix .. name .. suffix .. ext result.directory = dir result.subdirectory = subdir result.prefix = prefix result.suffix = suffix result.fullpath = path.join(result.directory, result.name) result.bundlepath = bundlepath or result.fullpath if pathstyle == "windows" then result.directory = path.translate(result.directory, "\\") result.subdirectory = path.translate(result.subdirectory, "\\") result.fullpath = path.translate(result.fullpath, "\\") end return result end function premake.gettool(prj) if premake.iscppproject(prj) then if _OPTIONS.cc then return premake[_OPTIONS.cc] end local action = premake.action.current() if action.valid_tools then return premake[action.valid_tools.cc[1]] end return premake.gcc elseif premake.isdotnetproject(prj) then return premake.dotnet elseif premake.isswiftproject(prj) then return premake.swift else return premake.valac end end function premake.project.getvpath(prj, abspath) local vpath = abspath local fname = path.getname(abspath) local max = abspath:len() - fname:len() -- First check for an exact match from the inverse vpaths if prj.inversevpaths and prj.inversevpaths[abspath] then return path.join(prj.inversevpaths[abspath], fname) end local matches = {} for replacement, patterns in pairs(prj.vpaths or {}) do for _, pattern in ipairs(patterns) do local i = abspath:find(path.wildcards(pattern)) if i == 1 then i = pattern:find("*", 1, true) or (pattern:len() + 1) local leaf if i < max then leaf = abspath:sub(i) else leaf = fname end if leaf:startswith("/") then leaf = leaf:sub(2) end local stem = "" if replacement:len() > 0 then stem, stars = replacement:gsub("%*", "") if stars == 0 then leaf = path.getname(leaf) end else leaf = path.getname(leaf) end table.insert(matches, path.join(stem, leaf)) end end end if #matches > 0 then -- for the sake of determinism, return the first alphabetically table.sort(matches) vpath = matches[1] end return path.trimdots(vpath) end function premake.hascppproject(sln) for prj in premake.solution.eachproject(sln) do if premake.iscppproject(prj) then return true end end end function premake.hasdotnetproject(sln) for prj in premake.solution.eachproject(sln) do if premake.isdotnetproject(prj) then return true end end end function premake.project.iscproject(prj) local language = prj.language or prj.solution.language return language == "C" end function premake.iscppproject(prj) local language = prj.language or prj.solution.language return (language == "C" or language == "C++") end function premake.isdotnetproject(prj) local language = prj.language or prj.solution.language return (language == "C#") end function premake.isvalaproject(prj) local language = prj.language or prj.solution.language return (language == "Vala") end function premake.isswiftproject(prj) local language = prj.language or prj.solution.language return (language == "Swift") end premake.config = { } local config = premake.config function premake.config.isdebugbuild(cfg) if cfg.flags.DebugRuntime then return true end if cfg.flags.ReleaseRuntime then return false end if cfg.flags.Optimize or cfg.flags.OptimizeSize or cfg.flags.OptimizeSpeed then return false end if not cfg.flags.Symbols then return false end return true end function premake.config.eachfile(cfg) local i = 0 local t = cfg.files return function () i = i + 1 if (i <= #t) then local fcfg = cfg.__fileconfigs[t[i]] fcfg.vpath = premake.project.getvpath(cfg.project, fcfg.name) return fcfg end end end function premake.config.isincrementallink(cfg) if cfg.kind == "StaticLib" then return false end return not config.islinkeroptimizedbuild(cfg.flags) and not cfg.flags.NoIncrementalLink end function premake.config.isoptimizedbuild(flags) return flags.Optimize or flags.OptimizeSize or flags.OptimizeSpeed end function premake.config.islinkeroptimizedbuild(flags) return config.isoptimizedbuild(flags) and not flags.NoOptimizeLink end function premake.config.iseditandcontinue(cfg) if cfg.flags.NoEditAndContinue or cfg.flags.Managed or (cfg.kind ~= "StaticLib" and not config.isincrementallink(cfg)) or config.islinkeroptimizedbuild(cfg.flags) then return false end return true end premake.bake = { } local bake = premake.bake local nocopy = { blocks = true, keywords = true, projects = true, __configs = true, } local nocascade = { makesettings = true, } local keeprelative = { basedir = true, location = true, } function premake.getactiveterms(obj) local terms = { _action = _ACTION:lower(), os = os.get() } for key, value in pairs(_OPTIONS) do if value ~= "" then table.insert(terms, value:lower()) else table.insert(terms, key:lower()) end end return terms end function premake.iskeywordmatch(keyword, terms) if keyword:startswith("not ") then return not premake.iskeywordmatch(keyword:sub(5), terms) end for _, pattern in ipairs(keyword:explode(" or ")) do for termkey, term in pairs(terms) do if term:match(pattern) == term then return termkey end end end end function premake.iskeywordsmatch(keywords, terms) local hasrequired = false for _, keyword in ipairs(keywords) do local matched = premake.iskeywordmatch(keyword, terms) if not matched then return false end if matched == "required" then hasrequired = true end end if terms.required and not hasrequired then return false else return true end end local function adjustpaths(location, obj) function adjustpathlist(list) for i, p in ipairs(list) do list[i] = path.getrelative(location, p) end end if obj.allfiles ~= nil then adjustpathlist(obj.allfiles) end for name, value in pairs(obj) do local field = premake.fields[name] if field and value and not keeprelative[name] then if field.kind == "path" then obj[name] = path.getrelative(location, value) elseif field.kind == "dirlist" or field.kind == "filelist" then adjustpathlist(value) elseif field.kind == "keypath" then for k,v in pairs(value) do adjustpathlist(v) end end end end end local function removevalue(tbl, remove) for index, item in ipairs(tbl) do if item == remove then table.remove(tbl, index) break end end end local function removevalues(tbl, removes) for k, v in pairs(tbl) do for _, pattern in ipairs(removes) do if pattern == tbl[k] then if type(k) == "number" then table.remove(tbl, k) else tbl[k] = nil end break end end end end local function mergefield(kind, dest, src, mergecopiestotail) local tbl = dest or { } if kind == "keyvalue" or kind == "keypath" then for key, value in pairs(src) do tbl[key] = mergefield("list", tbl[key], value, mergecopiestotail) end else for _, item in ipairs(src) do if tbl[item] then if mergecopiestotail then removevalue(tbl, item) table.insert(tbl, item) tbl[item] = item end else table.insert(tbl, item) tbl[item] = item end end end return tbl end local function mergeobject(dest, src) if not src then return end for fieldname, value in pairs(src) do if not nocopy[fieldname] then local field = premake.fields[fieldname] if field then if type(value) == "table" then dest[fieldname] = mergefield(field.kind, dest[fieldname], value, field.mergecopiestotail) if src.removes then removes = src.removes[fieldname] if removes then removevalues(dest[fieldname], removes) end end else dest[fieldname] = value end else dest[fieldname] = value end end end end local function merge(dest, obj, basis, terms, cfgname, pltname) local key = cfgname or "" pltname = pltname or "Native" if pltname ~= "Native" then key = key .. pltname end terms.config = (cfgname or ""):lower() terms.platform = pltname:lower() local cfg = {} mergeobject(cfg, basis[key]) adjustpaths(obj.location, cfg) mergeobject(cfg, obj) if (cfg.kind) then terms['kind']=cfg.kind:lower() end for _, blk in ipairs(obj.blocks) do if (premake.iskeywordsmatch(blk.keywords, terms))then mergeobject(cfg, blk) if (cfg.kind and not cfg.terms.kind) then cfg.terms['kind'] = cfg.kind:lower() terms['kind'] = cfg.kind:lower() end end end cfg.name = cfgname cfg.platform = pltname for k,v in pairs(terms) do cfg.terms[k] =v end dest[key] = cfg end local function collapse(obj, basis) local result = {} basis = basis or {} local sln = obj.solution or obj local terms = premake.getactiveterms(obj) merge(result, obj, basis, terms)--this adjusts terms for _, cfgname in ipairs(sln.configurations) do local terms_local = {} for k,v in pairs(terms)do terms_local[k]=v end merge(result, obj, basis, terms_local, cfgname, "Native")--terms cam also be adjusted here for _, pltname in ipairs(sln.platforms or {}) do if pltname ~= "Native" then merge(result, obj, basis,terms_local, cfgname, pltname)--terms also here end end end return result end local function builduniquedirs() local num_variations = 4 local cfg_dirs = {} local hit_counts = {} for sln in premake.solution.each() do for _, prj in ipairs(sln.projects) do for _, cfg in pairs(prj.__configs) do local dirs = { } dirs[1] = path.getabsolute(path.join(cfg.location, cfg.objdir or cfg.project.objdir or "obj")) dirs[2] = path.join(dirs[1], iif(cfg.platform == "Native", "", cfg.platform)) dirs[3] = path.join(dirs[2], cfg.name) dirs[4] = path.join(dirs[3], cfg.project.name) cfg_dirs[cfg] = dirs local start = iif(cfg.name, 2, 1) for v = start, num_variations do local d = dirs[v] hit_counts[d] = (hit_counts[d] or 0) + 1 end end end end for sln in premake.solution.each() do for _, prj in ipairs(sln.projects) do for _, cfg in pairs(prj.__configs) do local dir local start = iif(cfg.name, 2, 1) for v = start, iif(cfg.flags.SingleOutputDir==true,num_variations-1,num_variations) do dir = cfg_dirs[cfg][v] if hit_counts[dir] == 1 then break end end cfg.objectsdir = path.getrelative(cfg.location, dir) end end end end local function buildtargets() for sln in premake.solution.each() do for _, prj in ipairs(sln.projects) do for _, cfg in pairs(prj.__configs) do local pathstyle = premake.getpathstyle(cfg) local namestyle = premake.getnamestyle(cfg) cfg.buildtarget = premake.gettarget(cfg, "build", pathstyle, namestyle, cfg.system) cfg.linktarget = premake.gettarget(cfg, "link", pathstyle, namestyle, cfg.system) if pathstyle == "windows" then cfg.objectsdir = path.translate(cfg.objectsdir, "\\") end end end end end local function getCfgKind(cfg) if(cfg.kind) then return cfg.kind; end if(cfg.project.__configs[""] and cfg.project.__configs[""].kind) then return cfg.project.__configs[""].kind; end return nil end local function getprojrec(dstArray, foundList, cfg, cfgname, searchField, bLinkage) if(not cfg) then return end local foundUsePrjs = {}; for _, useName in ipairs(cfg[searchField]) do local testName = useName:lower(); if((not foundList[testName])) then local theProj = nil; local theUseProj = nil; for _, prj in ipairs(cfg.project.solution.projects) do if (prj.name:lower() == testName) then if(prj.usage) then theUseProj = prj; else theProj = prj; end end end --Must connect to a usage project. if(theUseProj) then foundList[testName] = true; local prjEntry = { name = testName, proj = theProj, usageProj = theUseProj, bLinkageOnly = bLinkage, }; dstArray[testName] = prjEntry; table.insert(foundUsePrjs, theUseProj); end end end for _, usePrj in ipairs(foundUsePrjs) do --Links can only recurse through static libraries. if((searchField ~= "links") or (getCfgKind(usePrj.__configs[cfgname]) == "StaticLib")) then getprojrec(dstArray, foundList, usePrj.__configs[cfgname], cfgname, searchField, bLinkage); end end end -- -- This function will recursively get all projects that the given configuration has in its "uses" -- field. The return values are a list of tables. Each table in that list contains the following: --name = The lowercase name of the project. --proj = The project. Can be nil if it is usage-only. --usageProj = The usage project. Can't be nil, as using a project that has no -- usage project is not put into the list. --bLinkageOnly = If this is true, then only the linkage information should be copied. -- The recursion will only look at the "uses" field on *usage* projects. -- This function will also add projects to the list that are mentioned in the "links" -- field of usage projects. These will only copy linker information, but they will recurse. -- through other "links" fields. -- local function getprojectsconnections(cfg, cfgname) local dstArray = {}; local foundList = {}; foundList[cfg.project.name:lower()] = true; --First, follow the uses recursively. getprojrec(dstArray, foundList, cfg, cfgname, "uses", false); --Next, go through all of the usage projects and recursively get their links. --But only if they're not already there. Get the links as linkage-only. local linkArray = {}; for prjName, prjEntry in pairs(dstArray) do getprojrec(linkArray, foundList, prjEntry.usageProj.__configs[cfgname], cfgname, "links", true); end --Copy from linkArray into dstArray. for prjName, prjEntry in pairs(linkArray) do dstArray[prjName] = prjEntry; end return dstArray; end local function isnameofproj(cfg, strName) local sln = cfg.project.solution; local strTest = strName:lower(); for prjIx, prj in ipairs(sln.projects) do if (prj.name:lower() == strTest) then return true; end end return false; end -- -- Copies the field from dstCfg to srcCfg. -- local function copydependentfield(srcCfg, dstCfg, strSrcField) local srcField = premake.fields[strSrcField]; local strDstField = strSrcField; if type(srcCfg[strSrcField]) == "table" then --handle paths. if (srcField.kind == "dirlist" or srcField.kind == "filelist") and (not keeprelative[strSrcField]) then for i,p in ipairs(srcCfg[strSrcField]) do table.insert(dstCfg[strDstField], path.rebase(p, srcCfg.project.location, dstCfg.project.location)) end else if(strSrcField == "links") then for i,p in ipairs(srcCfg[strSrcField]) do if(not isnameofproj(dstCfg, p)) then table.insert(dstCfg[strDstField], p) else printf("Failed to copy '%s' from proj '%s'.", p, srcCfg.project.name); end end else for i,p in ipairs(srcCfg[strSrcField]) do table.insert(dstCfg[strDstField], p) end end end else if(srcField.kind == "path" and (not keeprelative[strSrcField])) then dstCfg[strDstField] = path.rebase(srcCfg[strSrcField], prj.location, dstCfg.project.location); else dstCfg[strDstField] = srcCfg[strSrcField]; end end end -- -- This function will take the list of project entries and apply their usage project data -- to the given configuration. It will copy compiling information for the projects that are -- not listed as linkage-only. It will copy the linking information for projects only if -- the source project is not a static library. It won't copy linking information -- if the project is in this solution; instead it will add that project to the configuration's -- links field, expecting that Premake will handle the rest. -- local function copyusagedata(cfg, cfgname, linkToProjs) local myPrj = cfg.project; local bIsStaticLib = (getCfgKind(cfg) == "StaticLib"); for prjName, prjEntry in pairs(linkToProjs) do local srcPrj = prjEntry.usageProj; local srcCfg = srcPrj.__configs[cfgname]; for name, field in pairs(premake.fields) do if(srcCfg[name]) then if(field.usagecopy) then if(not prjEntry.bLinkageOnly) then copydependentfield(srcCfg, cfg, name) end elseif(field.linkagecopy) then --Copy the linkage data if we're building a non-static thing --and this is a pure usage project. If it's not pure-usage, then --we will simply put the project's name in the links field later. if((not bIsStaticLib) and (not prjEntry.proj)) then copydependentfield(srcCfg, cfg, name) end end end end if((not bIsStaticLib) and prjEntry.proj) then table.insert(cfg.links, prjEntry.proj.name); end end end local function inverseliteralvpaths() for sln in premake.solution.each() do for _,prj in ipairs(sln.projects) do prj.inversevpaths = {} for replacement, patterns in pairs(prj.vpaths or {}) do for _, pattern in ipairs(patterns) do if string.find(pattern, "*") == nil then prj.inversevpaths[pattern] = replacement end end end end end end function premake.bake.buildconfigs() for sln in premake.solution.each() do for _, prj in ipairs(sln.projects) do prj.location = prj.location or sln.location or prj.basedir adjustpaths(prj.location, prj) for _, blk in ipairs(prj.blocks) do adjustpaths(prj.location, blk) end end sln.location = sln.location or sln.basedir end -- convert paths for imported projects to be relative to solution location for sln in premake.solution.each() do for _, iprj in ipairs(sln.importedprojects) do iprj.location = path.getabsolute(iprj.location) end end inverseliteralvpaths() for sln in premake.solution.each() do local basis = collapse(sln) for _, prj in ipairs(sln.projects) do prj.__configs = collapse(prj, basis) for _, cfg in pairs(prj.__configs) do bake.postprocess(prj, cfg) end end end for sln in premake.solution.each() do for prjIx, prj in ipairs(sln.projects) do if(not prj.usage) then for cfgname, cfg in pairs(prj.__configs) do local usesPrjs = getprojectsconnections(cfg, cfgname); copyusagedata(cfg, cfgname, usesPrjs) end end end end for sln in premake.solution.each() do for prjIx, prj in ipairs(sln.projects) do for cfgName, cfg in pairs(prj.__configs) do cfg.build = true local removes = nil if cfg.removes ~= nil then removes = cfg.removes["platforms"]; end if removes ~= nil then for _,p in ipairs(removes) do if p == cfg.platform then cfg.build = false end end end end end end for sln in premake.solution.each() do local removeList = {}; for index, prj in ipairs(sln.projects) do if(prj.usage) then table.insert(removeList, 1, index); --Add in reverse order. end end for _, index in ipairs(removeList) do table.remove(sln.projects, index); end end builduniquedirs() buildtargets(cfg) end function premake.bake.postprocess(prj, cfg) cfg.project = prj cfg.shortname = premake.getconfigname(cfg.name, cfg.platform, true) cfg.longname = premake.getconfigname(cfg.name, cfg.platform) cfg.location = cfg.location or cfg.basedir local platform = premake.platforms[cfg.platform] if platform.iscrosscompiler then cfg.system = cfg.platform else cfg.system = os.get() end if cfg.kind == "Bundle" and _ACTION ~= "gmake" and (_ACTION ~= "ninja" and (not prj.options or not prj.options.SkipBundling)) and not _ACTION:match("xcode[0-9]") then cfg.kind = "SharedLib" end if cfg.kind == "SharedLib" and platform.nosharedlibs then cfg.kind = "StaticLib" end local removefiles = cfg.removefiles if _ACTION == 'gmake' or _ACTION == 'ninja' then removefiles = table.join(removefiles, cfg.excludes) end local removefilesDict = {} for _, fname in ipairs(removefiles) do removefilesDict[fname] = true end local files = {} for _, fname in ipairs(cfg.files) do if removefilesDict[fname] == nil then table.insert(files, fname) end end cfg.files = files local allfiles = {} local allfilesDict = {} if cfg.allfiles ~= nil then for _, fname in ipairs(cfg.allfiles) do if allfilesDict[fname] == nil then if removefilesDict[fname] == nil then allfilesDict[fname] = true table.insert(allfiles, fname) end end end end cfg.allfiles = allfiles for name, field in pairs(premake.fields) do if field.isflags then local values = cfg[name] for _, flag in ipairs(values) do values[flag] = true end end end local cfgfields = { {"__fileconfigs", cfg.files}, {"__allfileconfigs", cfg.allfiles}, } for _, cfgfield in ipairs(cfgfields) do local fieldname = cfgfield[1] local field = cfgfield[2] cfg[fieldname] = { } for _, fname in ipairs(field) do local fcfg = {} if premake._filelevelconfig then cfg.terms.required = fname:lower() for _, blk in ipairs(cfg.project.blocks) do if (premake.iskeywordsmatch(blk.keywords, cfg.terms)) then mergeobject(fcfg, blk) end end end fcfg.name = fname cfg[fieldname][fname] = fcfg table.insert(cfg[fieldname], fcfg) end end end premake.fields = {} premake.check_paths = false function premake.checkvalue(value, allowed) if (allowed) then if (type(allowed) == "function") then return allowed(value) else for _,v in ipairs(allowed) do if (value:lower() == v:lower()) then return v end end return nil, "invalid value '" .. value .. "'" end else return value end end function premake.getobject(t) local container if (t == "container" or t == "solution") then container = premake.CurrentContainer else container = premake.CurrentConfiguration end if t == "solution" then if typex(container) == "project" then container = container.solution end if typex(container) ~= "solution" then container = nil end end local msg if (not container) then if (t == "container") then msg = "no active solution or project" elseif (t == "solution") then msg = "no active solution" else msg = "no active solution, project, or configuration" end end return container, msg end function premake.setarray(obj, fieldname, value, allowed) obj[fieldname] = obj[fieldname] or {} local function add(value, depth) if type(value) == "table" then for _,v in ipairs(value) do add(v, depth + 1) end else value, err = premake.checkvalue(value, allowed) if not value then error(err, depth) end table.insert(obj[fieldname], value) end end if value then add(value, 5) end return obj[fieldname] end function premake.settable(obj, fieldname, value, allowed) obj[fieldname] = obj[fieldname] or {} table.insert(obj[fieldname], value) return obj[fieldname] end local function domatchedarray(fields, value, matchfunc) local result = { } function makeabsolute(value, depth) if (type(value) == "table") then for _, item in ipairs(value) do makeabsolute(item, depth + 1) end elseif type(value) == "string" then if value:find("*") then local arr = matchfunc(value); if (premake.check_paths) and (#arr == 0) then error("Can't find matching files for pattern :" .. value) end makeabsolute(arr, depth + 1) else table.insert(result, path.getabsolute(value)) end else error("Invalid value in list: expected string, got " .. type(value), depth) end end makeabsolute(value, 3) local retval = {} for index, field in ipairs(fields) do local ctype = field[1] local fieldname = field[2] local array = premake.setarray(ctype, fieldname, result) if index == 1 then retval = array end end return retval end function premake.setdirarray(fields, value) return domatchedarray(fields, value, os.matchdirs) end function premake.setfilearray(fields, value) return domatchedarray(fields, value, os.matchfiles) end function premake.setkeyvalue(ctype, fieldname, values) local container, err = premake.getobject(ctype) if not container then error(err, 4) end if not container[fieldname] then container[fieldname] = {} end if type(values) ~= "table" then error("invalid value; table expected", 4) end local field = container[fieldname] for key,value in pairs(values) do if not field[key] then field[key] = {} end table.insertflat(field[key], value) end return field end function premake.setstring(ctype, fieldname, value, allowed) local container, err = premake.getobject(ctype) if (not container) then error(err, 4) end if (value) then value, err = premake.checkvalue(value, allowed) if (not value) then error(err, 4) end container[fieldname] = value end return container[fieldname] end function premake.remove(fieldname, value) local cfg = premake.CurrentConfiguration cfg.removes = cfg.removes or {} cfg.removes[fieldname] = premake.setarray(cfg.removes, fieldname, value) end local function accessor(name, value) local kind = premake.fields[name].kind local scope = premake.fields[name].scope local allowed = premake.fields[name].allowed if (kind == "string" or kind == "path") and value then if type(value) ~= "string" then error("string value expected", 3) end end local container, err = premake.getobject(scope) if (not container) then error(err, 3) end if kind == "string" then return premake.setstring(scope, name, value, allowed) elseif kind == "path" then if value then value = path.getabsolute(value) end return premake.setstring(scope, name, value) elseif kind == "list" then return premake.setarray(container, name, value, allowed) elseif kind == "table" then return premake.settable(container, name, value, allowed) elseif kind == "dirlist" then return premake.setdirarray({{container, name}}, value) elseif kind == "filelist" or kind == "absolutefilelist" then local fields = {{container, name}} if name == "files" then local prj, err = premake.getobject("container") if (not prj) then error(err, 2) end table.insert(fields, {prj.blocks[1], "allfiles"}) end return premake.setfilearray(fields, value) elseif kind == "keyvalue" or kind == "keypath" then return premake.setkeyvalue(scope, name, value) end end function configuration(terms) if not terms then return premake.CurrentConfiguration end local container, err = premake.getobject("container") if (not container) then error(err, 2) end local cfg = { } cfg.terms = table.flatten({terms}) table.insert(container.blocks, cfg) premake.CurrentConfiguration = cfg cfg.keywords = { } for _, word in ipairs(cfg.terms) do table.insert(cfg.keywords, path.wildcards(word):lower()) end for name, field in pairs(premake.fields) do if (field.kind ~= "string" and field.kind ~= "path") then cfg[name] = { } end end return cfg end local function creategroup(name, sln, curpath, parent, inpath) local group = {} setmetatable(group, { __type = "group" }) table.insert(sln.groups, group) sln.groups[inpath] = group if parent ~= nil then table.insert(parent.groups, group) end group.solution = sln group.name = name group.uuid = os.uuid(curpath) group.parent = parent group.projects = { } group.groups = { } return group end local function creategroupsfrompath(inpath, sln) if inpath == nil then return nil end inpath = path.translate(inpath, "/") local groups = string.explode(inpath, "/") local curpath = "" local lastgroup = nil for i, v in ipairs(groups) do curpath = curpath .. "/" .. v:lower() local group = sln.groups[curpath] if group == nil then group = creategroup(v, sln, curpath, lastgroup, curpath) end lastgroup = group end return lastgroup end local function createproject(name, sln, isUsage) local prj = {} setmetatable(prj, { __type = "project", }) table.insert(sln.projects, prj) if(isUsage) then if(sln.projects[name]) then sln.projects[name].usageProj = prj; else sln.projects[name] = prj end else if(sln.projects[name]) then prj.usageProj = sln.projects[name]; end sln.projects[name] = prj end local group = creategroupsfrompath(premake.CurrentGroup, sln) if group ~= nil then table.insert(group.projects, prj) end prj.solution = sln prj.name = name prj.basedir = os.getcwd() prj.uuid = os.uuid(prj.name) prj.blocks = { } prj.usage = isUsage prj.group = group return prj; end function usage(name) if (not name) then if(typex(premake.CurrentContainer) ~= "project") then return nil end if(not premake.CurrentContainer.usage) then return nil end return premake.CurrentContainer end local sln if (typex(premake.CurrentContainer) == "project") then sln = premake.CurrentContainer.solution else sln = premake.CurrentContainer end if (typex(sln) ~= "solution") then error("no active solution", 2) end if((not sln.projects[name]) or ((not sln.projects[name].usage) and (not sln.projects[name].usageProj))) then premake.CurrentContainer = createproject(name, sln, true) else premake.CurrentContainer = iff(sln.projects[name].usage, sln.projects[name], sln.projects[name].usageProj) end configuration { } return premake.CurrentContainer end function project(name) if (not name) then if(typex(premake.CurrentContainer) ~= "project") then return nil end if(premake.CurrentContainer.usage) then return nil end return premake.CurrentContainer end local sln if (typex(premake.CurrentContainer) == "project") then sln = premake.CurrentContainer.solution else sln = premake.CurrentContainer end if (typex(sln) ~= "solution") then error("no active solution", 2) end if((not sln.projects[name]) or sln.projects[name].usage) then premake.CurrentContainer = createproject(name, sln) else premake.CurrentContainer = sln.projects[name]; end configuration { } return premake.CurrentContainer end function solution(name) if not name then if typex(premake.CurrentContainer) == "project" then return premake.CurrentContainer.solution else return premake.CurrentContainer end end premake.CurrentContainer = premake.solution.get(name) if (not premake.CurrentContainer) then premake.CurrentContainer = premake.solution.new(name) end configuration { } return premake.CurrentContainer end function group(name) if not name then return premake.CurrentGroup end premake.CurrentGroup = name return premake.CurrentGroup end function importvsproject(location) if string.find(_ACTION, "vs") ~= 1 then error("Only available for visual studio actions") end sln, err = premake.getobject("solution") if not sln then error(err) end local group = creategroupsfrompath(premake.CurrentGroup, sln) local project = {} project.location = location project.group = group project.flags = {} table.insert(sln.importedprojects, project) end function newaction(a) premake.action.add(a) end function newoption(opt) premake.option.add(opt) end function enablefilelevelconfig() premake._filelevelconfig = true end function newapifield(field) premake.fields[field.name] = field _G[field.name] = function(value) return accessor(field.name, value) end if field.kind == "list" or field.kind == "dirlist" or field.kind == "filelist" or field.kind == "absolutefilelist" then if field.name ~= "removefiles" and field.name ~= "files" then _G["remove"..field.name] = function(value) premake.remove(field.name, value) end end end end newapifield { name = "archivesplit_size", kind = "string", scope = "config", } newapifield { name = "basedir", kind = "path", scope = "container", } newapifield { name = "buildaction", kind = "string", scope = "config", allowed = { "Compile", "Copy", "Embed", "None" } } newapifield { name = "buildoptions", kind = "list", scope = "config", } newapifield { name = "buildoptions_asm", kind = "list", scope = "config", } newapifield { name = "buildoptions_c", kind = "list", scope = "config", } newapifield { name = "buildoptions_cpp", kind = "list", scope = "config", } newapifield { name = "buildoptions_objc", kind = "list", scope = "config", } newapifield { name = "buildoptions_objcpp", kind = "list", scope = "config", } newapifield { name = "buildoptions_vala", kind = "list", scope = "config", } newapifield { name = "clrreferences", kind = "list", scope = "container", } newapifield { name = "configurations", kind = "list", scope = "solution", } newapifield { name = "custombuildtask", kind = "table", scope = "config", } newapifield { name = "debugcmd", kind = "string", scope = "config", } newapifield { name = "debugargs", kind = "list", scope = "config", } newapifield { name = "debugdir", kind = "path", scope = "config", } newapifield { name = "debugenvs" , kind = "list", scope = "config", } newapifield { name = "defines", kind = "list", scope = "config", } newapifield { name = "deploymentoptions", kind = "list", scope = "config", usagecopy = true, } newapifield { name = "dependency", kind = "table", scope = "config", } newapifield { name = "deploymode", kind = "string", scope = "config", } newapifield { name = "excludes", kind = "filelist", scope = "config", } newapifield { name = "forcenative", kind = "filelist", scope = "config", } newapifield { name = "nopch", kind = "filelist", scope = "config", } newapifield { name = "files", kind = "filelist", scope = "config", } newapifield { name = "removefiles", kind = "filelist", scope = "config", } newapifield { name = "flags", kind = "list", scope = "config", isflags = true, usagecopy = true, allowed = function(value) local allowed_flags = { AntBuildDebuggable = 1, C7DebugInfo = 1, Cpp11 = 1, Cpp14 = 1, Cpp17 = 1, Cpp20 = 1, CppLatest = 1, DebugEnvsDontMerge = 1, DebugEnvsInherit = 1, DeploymentContent = 1, EnableMinimalRebuild = 1, EnableSSE = 1, EnableSSE2 = 1, EnableAVX = 1, EnableAVX2 = 1, PedanticWarnings = 1, ExtraWarnings = 1, FatalWarnings = 1, FloatFast = 1, FloatStrict = 1, FullSymbols = 1, GenerateMapFiles = 1, Hotpatchable = 1, LinkSupportCircularDependencies = 1, Managed = 1, MinimumWarnings = 1, NativeWChar = 1, No64BitChecks = 1, NoBufferSecurityCheck = 1, NoEditAndContinue = 1, NoExceptions = 1, NoFramePointer = 1, NoImportLib = 1, NoIncrementalLink = 1, NoJMC = 1, NoManifest = 1, NoMultiProcessorCompilation = 1, NoNativeWChar = 1, NoOptimizeLink = 1, NoPCH = 1, NoRTTI = 1, NoRuntimeChecks = 1, NoWinMD = 1, -- explicitly disables Windows Metadata NoWinRT = 1, -- explicitly disables Windows Runtime Extension FastCall = 1, StdCall = 1, SingleOutputDir = 1, ObjcARC = 1, Optimize = 1, OptimizeSize = 1, OptimizeSpeed = 1, DebugRuntime = 1, ReleaseRuntime = 1, SEH = 1, StaticRuntime = 1, Symbols = 1, Unicode = 1, UnitySupport = 1, Unsafe = 1, UnsignedChar = 1, UseFullPaths = 1, UseLDResponseFile = 1, UseObjectResponseFile = 1, WinMain = 1 } local englishToAmericanSpelling = { nooptimiselink = 'nooptimizelink', optimise = 'optimize', optimisesize = 'optimizesize', optimisespeed = 'optimizespeed', } local lowervalue = value:lower() lowervalue = englishToAmericanSpelling[lowervalue] or lowervalue for v, _ in pairs(allowed_flags) do if v:lower() == lowervalue then return v end end return nil, "invalid flag" end, } newapifield { name = "framework", kind = "string", scope = "container", allowed = { "1.0", "1.1", "2.0", "3.0", "3.5", "4.0", "4.5", "4.5.1", "4.5.2", "4.6", "4.6.1", "4.6.2", } } newapifield { name = "iostargetplatformversion", kind = "string", scope = "project", } newapifield { name = "macostargetplatformversion", kind = "string", scope = "project", } newapifield { name = "tvostargetplatformversion", kind = "string", scope = "project", } newapifield { name = "windowstargetplatformversion", kind = "string", scope = "project", } newapifield { name = "windowstargetplatformminversion", kind = "string", scope = "project", } newapifield { name = "forcedincludes", kind = "list", scope = "config", } newapifield { name = "imagepath", kind = "path", scope = "config", } newapifield { name = "imageoptions", kind = "list", scope = "config", } newapifield { name = "implibdir", kind = "path", scope = "config", } newapifield { name = "implibextension", kind = "string", scope = "config", } newapifield { name = "implibname", kind = "string", scope = "config", } newapifield { name = "implibprefix", kind = "string", scope = "config", } newapifield { name = "implibsuffix", kind = "string", scope = "config", } newapifield { name = "includedirs", kind = "dirlist", scope = "config", usagecopy = true, } newapifield { name = "systemincludedirs", kind = "dirlist", scope = "config", usagecopy = true, } newapifield { name = "userincludedirs", kind = "dirlist", scope = "config", usagecopy = true, } newapifield { name = "usingdirs", kind = "dirlist", scope = "config", usagecopy = true, } newapifield { name = "kind", kind = "string", scope = "config", allowed = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle", } } newapifield { name = "language", kind = "string", scope = "container", allowed = { "C", "C++", "C#", "Vala", "Swift", } } newapifield { name = "libdirs", kind = "dirlist", scope = "config", linkagecopy = true, } newapifield { name = "linkoptions", kind = "list", scope = "config", } newapifield { name = "links", kind = "list", scope = "config", allowed = function(value) if value:find('/', nil, true) then value = path.getabsolute(value) end return value end, linkagecopy = true, mergecopiestotail = true, } newapifield { name = "location", kind = "path", scope = "container", } newapifield { name = "makesettings", kind = "list", scope = "config", } newapifield { name = "messageskip", kind = "list", scope = "solution", isflags = true, usagecopy = true, allowed = function(value) local allowed_messages = { SkipCreatingMessage = 1, SkipBuildingMessage = 1, SkipCleaningMessage = 1, } local lowervalue = value:lower() for v, _ in pairs(allowed_messages) do if v:lower() == lowervalue then return v end end return nil, "invalid message to skip" end, } newapifield { name = "msgarchiving", kind = "string", scope = "config", } newapifield { name = "msgcompile", kind = "string", scope = "config", } newapifield { name = "msgprecompile", kind = "string", scope = "config", } newapifield { name = "msgcompile_objc", kind = "string", scope = "config", } newapifield { name = "msgresource", kind = "string", scope = "config", } newapifield { name = "msglinking", kind = "string", scope = "config", } newapifield { name = "objdir", kind = "path", scope = "config", } newapifield { name = "options", kind = "list", scope = "container", isflags = true, usagecopy = true, allowed = function(value) local allowed_options = { ForceCPP = 1, ArchiveSplit = 1, SkipBundling = 1, XcodeLibrarySchemes = 1, XcodeSchemeNoConfigs = 1, } local lowervalue = value:lower() for v, _ in pairs(allowed_options) do if v:lower() == lowervalue then return v end end return nil, "invalid option" end, } newapifield { name = "pchheader", kind = "string", scope = "config", } newapifield { name = "pchsource", kind = "path", scope = "config", } newapifield { name = "platforms", kind = "list", scope = "solution", allowed = table.keys(premake.platforms), } newapifield { name = "postbuildcommands", kind = "list", scope = "config", } newapifield { name = "prebuildcommands", kind = "list", scope = "config", } newapifield { name = "postcompiletasks", kind = "list", scope = "config", } newapifield { name = "prelinkcommands", kind = "list", scope = "config", } newapifield { name = "propertysheets", kind = "dirlist", scope = "config", } newapifield { name = "pullmappingfile", kind = "path", scope = "config", } newapifield { name = "applicationdatadir", kind = "path", scope = "config", } newapifield { name = "finalizemetasource", kind = "path", scope = "config", } newapifield { name = "resdefines", kind = "list", scope = "config", } newapifield { name = "resincludedirs", kind = "dirlist", scope = "config", } newapifield { name = "resoptions", kind = "list", scope = "config", } newapifield { name = "sdkreferences", kind = "list", scope = "config", } newapifield { name = "startproject", kind = "string", scope = "solution", } newapifield { name = "targetdir", kind = "path", scope = "config", } newapifield { name = "targetsubdir", kind = "string", scope = "config", } newapifield { name = "targetextension", kind = "string", scope = "config", } newapifield { name = "targetname", kind = "string", scope = "config", } newapifield { name = "targetprefix", kind = "string", scope = "config", } newapifield { name = "targetsuffix", kind = "string", scope = "config", } newapifield { name = "trimpaths", kind = "dirlist", scope = "config", } newapifield { name = "uuid", kind = "string", scope = "container", allowed = function(value) local ok = true if (#value ~= 36) then ok = false end for i=1,36 do local ch = value:sub(i,i) if (not ch:find("[ABCDEFabcdef0123456789-]")) then ok = false end end if (value:sub(9,9) ~= "-") then ok = false end if (value:sub(14,14) ~= "-") then ok = false end if (value:sub(19,19) ~= "-") then ok = false end if (value:sub(24,24) ~= "-") then ok = false end if (not ok) then return nil, "invalid UUID" end return value:upper() end } newapifield { name = "uses", kind = "list", scope = "config", } newapifield { name = "vapidirs", kind = "dirlist", scope = "config", } newapifield { name = "vpaths", kind = "keypath", scope = "container", } newapifield { name = "vsimportreferences", kind = "filelist", scope = "container", } newapifield { name = "dpiawareness", kind = "string", scope = "config", allowed = { "None", "High", "HighPerMonitor", } } newapifield { name = "xcodeprojectopts", kind = "table", scope = "config", } newapifield { name = "xcodetargetopts", kind = "table", scope = "config", } newapifield { name = "xcodescriptphases", kind = "table", scope = "config", } newapifield { name = "xcodecopyresources", kind = "table", scope = "project", } newapifield { name = "xcodecopyframeworks", kind = "filelist", scope = "project", } newapifield { name = "wholearchive", kind = "list", scope = "config", } newapifield { name = "swiftmodulemaps", kind = "filelist", scope = "config", } newapifield { name = "buildoptions_swift", kind = "list", scope = "config", } newapifield { name = "linkoptions_swift", kind = "list", scope = "config", } newapifield { name = "androidtargetapi", kind = "string", scope = "config", } newapifield { name = "androidminapi", kind = "string", scope = "config", } newapifield { name = "androidarch", kind = "string", scope = "config", allowed = { "armv7-a", "armv7-a-hard", "arm64-v8a", "x86", "x86_64", } } newapifield { name = "androidndktoolchainversion", kind = "string", scope = "config", } newapifield { name = "androidstltype", kind = "string", scope = "config", } newapifield { name = "androidcppstandard", kind = "string", scope = "config", allowed = { "c++98", "c++11", "c++1y", "gnu++98", "gnu++11", "gnu++1y", } } newapifield { name = "androidlinker", kind = "string", scope = "config", allowed = { "bfd", "gold", } } newapifield { name = "androiddebugintentparams", kind = "list", scope = "config", } newapifield { name = "antbuildjavasourcedirs", kind = "dirlist", scope = "config", } newapifield { name = "antbuildjardirs", kind = "dirlist", scope = "config", } newapifield { name = "antbuildjardependencies", kind = "list", scope = "config", } newapifield { name = "antbuildnativelibdirs", kind = "dirlist", scope = "config", } newapifield { name = "antbuildnativelibdependencies", kind = "list", scope = "config", } newapifield { name = "antbuildassetsdirs", kind = "dirlist", scope = "config", } newapifield { name = "postsolutioncallbacks", kind = "list", scope = "solution", } newapifield { name = "postprojectcallbacks", kind = "list", scope = "project", } newoption { trigger = "cc", value = "VALUE", description = "Choose a C/C++ compiler set", allowed = { { "gcc", "GNU GCC (gcc/g++)" }, { "ow", "OpenWatcom" }, { "ghs", "Green Hills Software" }, } } newoption { trigger = "dotnet", value = "VALUE", description = "Choose a .NET compiler set", allowed = { { "msnet", "Microsoft .NET (csc)" }, { "mono", "Novell Mono (mcs)" }, { "pnet", "Portable.NET (cscc)" }, } } newoption { trigger = "file", value = "FILE", description = "Read FILE as a Premake script; default is 'premake4.lua'" } newoption { trigger = "help", description = "Display this information" } newoption { trigger = "os", value = "VALUE", description = "Generate files for a different operating system", allowed = { { "bsd", "OpenBSD, NetBSD, or FreeBSD" }, { "linux", "Linux" }, { "macosx", "Apple Mac OS X" }, { "solaris", "Solaris" }, { "windows", "Microsoft Windows" }, } } newoption { trigger = "platform", value = "VALUE", description = "Add target architecture (if supported by action)", allowed = { { "x32", "32-bit" }, { "x64", "64-bit" }, { "universal", "Mac OS X Universal, 32- and 64-bit" }, { "universal32", "Mac OS X Universal, 32-bit only" }, { "universal64", "Mac OS X Universal, 64-bit only" }, { "ps3", "Playstation 3" }, { "orbis", "Playstation 4" }, { "xbox360", "Xbox 360" }, { "durango", "Xbox One" }, { "ARM", "ARM" }, { "ARM64", "ARM64" }, { "PowerPC", "PowerPC" }, { "nx32", "Nintendo Switch, 32-bit only" }, { "nx64", "Nintendo Switch, 64-bit only" }, } } newoption { trigger = "scripts", value = "path", description = "Search for additional scripts on the given path" } newoption { trigger = "debug-profiler", description = "GENie script generation profiler." } newoption { trigger = "version", description = "Display version information" } -- Copyright (c) 2013 Enrique García Cota local function smartQuote(str) if str:match('"') and not str:match("'") then return "'" .. str .. "'" end return '"' .. str:gsub('"', '\\"') .. '"' end local controlCharsTranslation = { ["\a"] = "\\a", ["\b"] = "\\b", ["\f"] = "\\f", ["\n"] = "\\n", ["\r"] = "\\r", ["\t"] = "\\t", ["\v"] = "\\v" } local function escapeChar(c) return controlCharsTranslation[c] end local function escape(str) local result = str:gsub("\\", "\\\\"):gsub("(%c)", escapeChar) return result end local function isIdentifier(str) return type(str) == 'string' and str:match( "^[_%a][_%a%d]*$" ) end local function isArrayKey(k, length) return type(k) == 'number' and 1 <= k and k <= length end local function isDictionaryKey(k, length) return not isArrayKey(k, length) end local defaultTypeOrders = { ['number'] = 1, ['boolean'] = 2, ['string'] = 3, ['table'] = 4, ['function'] = 5, ['userdata'] = 6, ['thread'] = 7 } local function sortKeys(a, b) local ta, tb = type(a), type(b) -- strings and numbers are sorted numerically/alphabetically if ta == tb and (ta == 'string' or ta == 'number') then return a < b end local dta, dtb = defaultTypeOrders[ta], defaultTypeOrders[tb] -- Two default types are compared according to the defaultTypeOrders table if dta and dtb then return defaultTypeOrders[ta] < defaultTypeOrders[tb] elseif dta then return true -- default types before custom ones elseif dtb then return false -- custom types after default ones end -- custom types are sorted out alphabetically return ta < tb end local function getDictionaryKeys(t) local keys, length = {}, #t for k,_ in pairs(t) do if isDictionaryKey(k, length) then table.insert(keys, k) end end table.sort(keys, sortKeys) return keys end local function getToStringResultSafely(t, mt) local __tostring = type(mt) == 'table' and rawget(mt, '__tostring') local str, ok if type(__tostring) == 'function' then ok, str = pcall(__tostring, t) str = ok and str or 'error: ' .. tostring(str) end if type(str) == 'string' and #str > 0 then return str end end local maxIdsMetaTable = { __index = function(self, typeName) rawset(self, typeName, 0) return 0 end } local idsMetaTable = { __index = function (self, typeName) local col = setmetatable({}, {__mode = "kv"}) rawset(self, typeName, col) return col end } local function countTableAppearances(t, tableAppearances) tableAppearances = tableAppearances or setmetatable({}, {__mode = "k"}) if type(t) == 'table' then if not tableAppearances[t] then tableAppearances[t] = 1 for k,v in pairs(t) do countTableAppearances(k, tableAppearances) countTableAppearances(v, tableAppearances) end countTableAppearances(getmetatable(t), tableAppearances) else tableAppearances[t] = tableAppearances[t] + 1 end end return tableAppearances end local function parse_filter(filter) if type(filter) == 'function' then return filter end -- not a function, so it must be a table or table-like filter = type(filter) == 'table' and filter or {filter} local dictionary = {} for _,v in pairs(filter) do dictionary[v] = true end return function(x) return dictionary[x] end end local function makePath(path, key) local newPath, len = {}, #path for i=1, len do newPath[i] = path[i] end newPath[len+1] = key return newPath end function inspect(rootObject, options) options = options or {} local depth = options.depth or math.huge local filter = parse_filter(options.filter or {}) local tableAppearances = countTableAppearances(rootObject) local buffer = {} local maxIds = setmetatable({}, maxIdsMetaTable) local ids = setmetatable({}, idsMetaTable) local level = 0 local blen = 0 -- buffer length local function puts(...) local args = {...} for i=1, #args do blen = blen + 1 buffer[blen] = tostring(args[i]) end end local function down(f) level = level + 1 f() level = level - 1 end local function tabify() puts("\n", string.rep(" ", level)) end local function commaControl(needsComma) if needsComma then puts(',') end return true end local function alreadyVisited(v) return ids[type(v)][v] ~= nil end local function getId(v) local tv = type(v) local id = ids[tv][v] if not id then id = maxIds[tv] + 1 maxIds[tv] = id ids[tv][v] = id end return id end local putValue -- forward declaration that needs to go before putTable & putKey local function putKey(k) if isIdentifier(k) then return puts(k) end puts( "[" ) putValue(k, {}) puts("]") end local function putTable(t, path) if alreadyVisited(t) then puts('') elseif level >= depth then puts('{...}') else if tableAppearances[t] > 1 then puts('<', getId(t), '>') end local dictKeys = getDictionaryKeys(t) local length = #t local mt = getmetatable(t) local to_string_result = getToStringResultSafely(t, mt) puts('{') down(function() if to_string_result then puts(' -- ', escape(to_string_result)) if length >= 1 then tabify() end -- tabify the array values end local needsComma = false for i=1, length do needsComma = commaControl(needsComma) puts(' ') putValue(t[i], makePath(path, i)) end for _,k in ipairs(dictKeys) do needsComma = commaControl(needsComma) tabify() putKey(k) puts(' = ') putValue(t[k], makePath(path, k)) end if mt then needsComma = commaControl(needsComma) tabify() puts(' = ') putValue(mt, makePath(path, '')) end end) if #dictKeys > 0 or mt then -- dictionary table. Justify closing } tabify() elseif length > 0 then -- array tables have one extra space before closing } puts(' ') end puts('}') end end -- putvalue is forward-declared before putTable & putKey putValue = function(v, path) if filter(v, path) then puts('') else local tv = type(v) if tv == 'string' then puts(smartQuote(escape(v))) elseif tv == 'number' or tv == 'boolean' or tv == 'nil' then puts(tostring(v)) elseif tv == 'table' then putTable(v, path) else puts('<',tv,' ',getId(v),'>') end end end putValue(rootObject, {}) return table.concat(buffer) end function printtable(name, table) print("table: ", name, inspect(table), "\n") end function printstack() print(debug.traceback(), "\n") end _profiler = {} function newProfiler(variant, sampledelay) if _profiler.running then print("Profiler already running.") return end variant = variant or "time" if variant ~= "time" and variant ~= "call" then print("Profiler method must be 'time' or 'call'.") return end local newprof = {} for k,v in pairs(_profiler) do newprof[k] = v end newprof.variant = variant newprof.sampledelay = sampledelay or 100000 return newprof end function _profiler.start(self) if _profiler.running then return end _profiler.running = self self.rawstats = {} self.callstack = {} if self.variant == "time" then self.lastclock = os.clock() debug.sethook( _profiler_hook_wrapper_by_time, "", self.sampledelay ) elseif self.variant == "call" then debug.sethook( _profiler_hook_wrapper_by_call, "cr" ) else print("Profiler method must be 'time' or 'call'.") sys.exit(1) end end function _profiler.stop(self) if _profiler.running ~= self then return end debug.sethook( nil ) _profiler.running = nil end function _profiler_hook_wrapper_by_call(action) if _profiler.running == nil then debug.sethook( nil ) end _profiler.running:_internal_profile_by_call(action) end function _profiler_hook_wrapper_by_time(action) if _profiler.running == nil then debug.sethook( nil ) end _profiler.running:_internal_profile_by_time(action) end function _profiler._internal_profile_by_call(self,action) local caller_info = debug.getinfo( 3 ) if caller_info == nil then print "No caller_info" return end local latest_ar = nil if table.getn(self.callstack) > 0 then latest_ar = self.callstack[table.getn(self.callstack)] end local should_not_profile = 0 for k,v in pairs(self.prevented_functions) do if k == caller_info.func then should_not_profile = v end end if latest_ar then if latest_ar.should_not_profile == 2 then should_not_profile = 2 end end if action == "call" then local this_ar = {} this_ar.should_not_profile = should_not_profile this_ar.parent_ar = latest_ar this_ar.anon_child = 0 this_ar.name_child = 0 this_ar.children = {} this_ar.children_time = {} this_ar.clock_start = os.clock() table.insert( self.callstack, this_ar ) else local this_ar = latest_ar if this_ar == nil then return -- No point in doing anything if no upper activation record end this_ar.clock_end = os.clock() this_ar.this_time = this_ar.clock_end - this_ar.clock_start if this_ar.parent_ar then this_ar.parent_ar.children[caller_info.func] = (this_ar.parent_ar.children[caller_info.func] or 0) + 1 this_ar.parent_ar.children_time[caller_info.func] = (this_ar.parent_ar.children_time[caller_info.func] or 0 ) + this_ar.this_time if caller_info.name == nil then this_ar.parent_ar.anon_child = this_ar.parent_ar.anon_child + this_ar.this_time else this_ar.parent_ar.name_child = this_ar.parent_ar.name_child + this_ar.this_time end end if this_ar.should_not_profile == 0 then local inforec = self:_get_func_rec(caller_info.func,1) inforec.count = inforec.count + 1 inforec.time = inforec.time + this_ar.this_time inforec.anon_child_time = inforec.anon_child_time + this_ar.anon_child inforec.name_child_time = inforec.name_child_time + this_ar.name_child inforec.func_info = caller_info for k,v in pairs(this_ar.children) do inforec.children[k] = (inforec.children[k] or 0) + v inforec.children_time[k] = (inforec.children_time[k] or 0) + this_ar.children_time[k] end end table.remove( self.callstack, table.getn( self.callstack ) ) end end function _profiler._internal_profile_by_time(self,action) local timetaken = os.clock() - self.lastclock local depth = 3 local at_top = true local last_caller local caller = debug.getinfo(depth) while caller do if not caller.func then caller.func = "(tail call)" end if self.prevented_functions[caller.func] == nil then local info = self:_get_func_rec(caller.func, 1, caller) info.count = info.count + 1 info.time = info.time + timetaken if last_caller then if last_caller.name then info.name_child_time = info.name_child_time + timetaken else info.anon_child_time = info.anon_child_time + timetaken end info.children[last_caller.func] = (info.children[last_caller.func] or 0) + 1 info.children_time[last_caller.func] = (info.children_time[last_caller.func] or 0) + timetaken end end depth = depth + 1 last_caller = caller caller = debug.getinfo(depth) end self.lastclock = os.clock() end function _profiler._get_func_rec(self,func,force,info) local ret = self.rawstats[func] if ret == nil and force ~= 1 then return nil end if ret == nil then ret = {} ret.func = func ret.count = 0 ret.time = 0 ret.anon_child_time = 0 ret.name_child_time = 0 ret.children = {} ret.children_time = {} ret.func_info = info self.rawstats[func] = ret end return ret end function _profiler.report( self, outfile, sort_by_total_time ) outfile:write [[Lua Profile output created by profiler.lua. Copyright Pepperfish 2002+ ]] local terms = {} if self.variant == "time" then terms.capitalized = "Sample" terms.single = "sample" terms.pastverb = "sampled" elseif self.variant == "call" then terms.capitalized = "Call" terms.single = "call" terms.pastverb = "called" else assert(false) end local total_time = 0 local ordering = {} for func,record in pairs(self.rawstats) do table.insert(ordering, func) end if sort_by_total_time then table.sort( ordering, function(a,b) return self.rawstats[a].time > self.rawstats[b].time end ) else table.sort( ordering, function(a,b) local arec = self.rawstats[a] local brec = self.rawstats[b] local atime = arec.time - (arec.anon_child_time + arec.name_child_time) local btime = brec.time - (brec.anon_child_time + brec.name_child_time) return atime > btime end ) end for i=1,#ordering do local func = ordering[i] local record = self.rawstats[func] local thisfuncname = " " .. self:_pretty_name(func) .. " " if string.len( thisfuncname ) < 42 then thisfuncname = string.rep( "-", math.floor((42 - string.len(thisfuncname))/2) ) .. thisfuncname thisfuncname = thisfuncname .. string.rep( "-", 42 - string.len(thisfuncname) ) end total_time = total_time + ( record.time - ( record.anon_child_time + record.name_child_time ) ) outfile:write( string.rep( "-", 19 ) .. thisfuncname .. string.rep( "-", 19 ) .. "\n" ) outfile:write( terms.capitalized.." count: " .. string.format( "%4d", record.count ) .. "\n" ) outfile:write( "Time spend total: " .. string.format( "%4.3f", record.time ) .. "s\n" ) outfile:write( "Time spent in children: " .. string.format("%4.3f",record.anon_child_time+record.name_child_time) .. "s\n" ) local timeinself = record.time - (record.anon_child_time + record.name_child_time) outfile:write( "Time spent in self: " .. string.format("%4.3f", timeinself) .. "s\n" ) outfile:write( "Time spent per " .. terms.single .. ": " .. string.format("%4.5f", record.time/record.count) .. "s/" .. terms.single .. "\n" ) outfile:write( "Time spent in self per "..terms.single..": " .. string.format( "%4.5f", timeinself/record.count ) .. "s/" .. terms.single.."\n" ) local added_blank = 0 for k,v in pairs(record.children) do if self.prevented_functions[k] == nil or self.prevented_functions[k] == 0 then if added_blank == 0 then outfile:write( "\n" ) -- extra separation line added_blank = 1 end outfile:write( "Child " .. self:_pretty_name(k) .. string.rep( " ", 41-string.len(self:_pretty_name(k)) ) .. " " .. terms.pastverb.." " .. string.format("%6d", v) ) outfile:write( " times. Took " .. string.format("%4.2f", record.children_time[k] ) .. "s\n" ) end end outfile:write( "\n" ) -- extra separation line outfile:flush() end outfile:write( "\n\n" ) outfile:write( "Total time spent in profiled functions: " .. string.format("%5.3g",total_time) .. "s\n" ) outfile:write( [[ END ]] ) outfile:flush() end function _profiler.lua_report(self,outfile) local ordering = {} local functonum = {} for func,record in pairs(self.rawstats) do table.insert(ordering, func) functonum[func] = table.getn(ordering) end outfile:write( "-- Profile generated by profiler.lua Copyright Pepperfish 2002+\n\n" ) outfile:write( "-- Function names\nfuncnames = {}\n" ) for i=1,table.getn(ordering) do local thisfunc = ordering[i] outfile:write( "funcnames[" .. i .. "] = " .. string.format("%q", self:_pretty_name(thisfunc)) .. "\n" ) end outfile:write( "\n" ) outfile:write( "-- Function times\nfunctimes = {}\n" ) for i=1,table.getn(ordering) do local thisfunc = ordering[i] local record = self.rawstats[thisfunc] outfile:write( "functimes[" .. i .. "] = { " ) outfile:write( "tot=" .. record.time .. ", " ) outfile:write( "achild=" .. record.anon_child_time .. ", " ) outfile:write( "nchild=" .. record.name_child_time .. ", " ) outfile:write( "count=" .. record.count .. " }\n" ) end outfile:write( "\n" ) outfile:write( "-- Child links\nchildren = {}\n" ) for i=1,table.getn(ordering) do local thisfunc = ordering[i] local record = self.rawstats[thisfunc] outfile:write( "children[" .. i .. "] = { " ) for k,v in pairs(record.children) do if functonum[k] then -- non-recorded functions will be ignored now outfile:write( functonum[k] .. ", " ) end end outfile:write( "}\n" ) end outfile:write( "\n" ) outfile:write( "-- Child call counts\nchildcounts = {}\n" ) for i=1,table.getn(ordering) do local thisfunc = ordering[i] local record = self.rawstats[thisfunc] outfile:write( "children[" .. i .. "] = { " ) for k,v in record.children do if functonum[k] then -- non-recorded functions will be ignored now outfile:write( v .. ", " ) end end outfile:write( "}\n" ) end outfile:write( "\n" ) outfile:write( "-- Child call time\nchildtimes = {}\n" ) for i=1,table.getn(ordering) do local thisfunc = ordering[i] local record = self.rawstats[thisfunc]; outfile:write( "children[" .. i .. "] = { " ) for k,v in pairs(record.children) do if functonum[k] then -- non-recorded functions will be ignored now outfile:write( record.children_time[k] .. ", " ) end end outfile:write( "}\n" ) end outfile:write( "\n\n-- That is all.\n\n" ) outfile:flush() end function _profiler._pretty_name(self,func) local info = self.rawstats[ func ].func_info local name = "" if info.what == "Lua" then name = "L:" end if info.what == "C" then name = "C:" end if info.what == "main" then name = " :" end if info.name == nil then name = name .. "<"..tostring(func) .. ">" else name = name .. info.name end if info.source then name = name else if info.what == "C" then name = name .. "@?" else name = name .. "@" end end name = name .. ":" if info.what == "C" then name = name .. "?" else name = name .. info.linedefined end return name end function _profiler.prevent(self, func, level) self.prevented_functions[func] = (level or 1) end _profiler.prevented_functions = { [_profiler.start] = 2, [_profiler.stop] = 2, [_profiler._internal_profile_by_time] = 2, [_profiler._internal_profile_by_call] = 2, [_profiler_hook_wrapper_by_time] = 2, [_profiler_hook_wrapper_by_call] = 2, [_profiler.prevent] = 2, [_profiler._get_func_rec] = 2, [_profiler.report] = 2, [_profiler.lua_report] = 2, [_profiler._pretty_name] = 2 } premake.dotnet = { } premake.dotnet.namestyle = "windows" local flags = { FatalWarning = "/warnaserror", Optimize = "/optimize", OptimizeSize = "/optimize", OptimizeSpeed = "/optimize", Symbols = "/debug", Unsafe = "/unsafe" } function premake.dotnet.getbuildaction(fcfg) local ext = path.getextension(fcfg.name):lower() if fcfg.buildaction == "Compile" or ext == ".cs" then return "Compile" elseif fcfg.buildaction == "Embed" or ext == ".resx" then return "EmbeddedResource" elseif fcfg.buildaction == "Copy" or ext == ".asax" or ext == ".aspx" then return "Content" else return "None" end end function premake.dotnet.getcompilervar(cfg) if (_OPTIONS.dotnet == "msnet") then return "csc" elseif (_OPTIONS.dotnet == "mono") then return "mcs" else return "cscc" end end function premake.dotnet.getflags(cfg) local result = table.translate(cfg.flags, flags) return result end function premake.dotnet.getkind(cfg) if (cfg.kind == "ConsoleApp") then return "Exe" elseif (cfg.kind == "WindowedApp") then return "WinExe" elseif (cfg.kind == "SharedLib") then return "Library" end end premake.gcc = { } premake.gcc.cc = "gcc" premake.gcc.cxx = "g++" premake.gcc.ar = "ar" premake.gcc.rc = "windres" premake.gcc.llvm = false local cflags = { EnableSSE = "-msse", EnableSSE2 = "-msse2", EnableAVX = "-mavx", EnableAVX2 = "-mavx2", PedanticWarnings = "-Wall -Wextra -pedantic", ExtraWarnings = "-Wall -Wextra", FatalWarnings = "-Werror", FloatFast = "-ffast-math", FloatStrict = "-ffloat-store", NoFramePointer = "-fomit-frame-pointer", Optimize = "-O2", OptimizeSize = "-Os", OptimizeSpeed = "-O3", Symbols = "-g", } local cxxflags = { Cpp11 = "-std=c++11", Cpp14 = "-std=c++14", Cpp17 = "-std=c++17", Cpp20 = "-std=c++20", CppLatest = "-std=c++2b", NoExceptions = "-fno-exceptions", NoRTTI = "-fno-rtti", UnsignedChar = "-funsigned-char", } local objcflags = { ObjcARC = "-fobjc-arc", } premake.gcc.platforms = { Native = { cppflags = "-MMD -MP", }, x32 = { cppflags = "-MMD -MP", flags = "-m32", }, x64 = { cppflags = "-MMD -MP", flags = "-m64", }, Universal = { ar = "libtool", cppflags = "-MMD -MP", flags = "-arch i386 -arch x86_64 -arch ppc -arch ppc64", }, Universal32 = { ar = "libtool", cppflags = "-MMD -MP", flags = "-arch i386 -arch ppc", }, Universal64 = { ar = "libtool", cppflags = "-MMD -MP", flags = "-arch x86_64 -arch ppc64", }, PS3 = { cc = "ppu-lv2-g++", cxx = "ppu-lv2-g++", ar = "ppu-lv2-ar", cppflags = "-MMD -MP", }, WiiDev = { cppflags = "-MMD -MP -I$(LIBOGC_INC) $(MACHDEP)", ldflags= "-L$(LIBOGC_LIB) $(MACHDEP)", cfgsettings = [[ ifeq ($(strip $(DEVKITPPC)),) $(error "DEVKITPPC environment variable is not set")' endif include $(DEVKITPPC)/wii_rules']], }, Orbis = { cc = "orbis-clang", cxx = "orbis-clang++", ar = "orbis-ar", cppflags = "-MMD -MP", }, Emscripten = { cc = "$(EMSCRIPTEN)/emcc", cxx = "$(EMSCRIPTEN)/em++", ar = "$(EMSCRIPTEN)/emar", cppflags = "-MMD -MP", }, NX32 = { cc = "clang", cxx = "clang++", ar = "armv7l-nintendo-nx-eabihf-ar", cppflags = "-MMD -MP", flags = "-march=armv7l", }, NX64 = { cc = "clang", cxx = "clang++", ar = "aarch64-nintendo-nx-elf-ar", cppflags = "-MMD -MP", flags = "-march=aarch64", }, } local platforms = premake.gcc.platforms function premake.gcc.getcppflags(cfg) local flags = { } table.insert(flags, platforms[cfg.platform].cppflags) if flags[1]:startswith("-MMD") then table.insert(flags, "-MP") end return flags end function premake.gcc.getcflags(cfg) local result = table.translate(cfg.flags, cflags) table.insert(result, platforms[cfg.platform].flags) if cfg.system ~= "windows" and cfg.kind == "SharedLib" then table.insert(result, "-fPIC") end return result end function premake.gcc.getcxxflags(cfg) local result = table.translate(cfg.flags, cxxflags) return result end function premake.gcc.getobjcflags(cfg) return table.translate(cfg.flags, objcflags) end function premake.gcc.getldflags(cfg) local result = { } if not cfg.flags.Symbols then if cfg.system == "macosx" then else table.insert(result, "-s") end end if cfg.kind == "Bundle" then table.insert(result, "-bundle") end if cfg.kind == "SharedLib" then if cfg.system == "macosx" then table.insert(result, "-dynamiclib") else table.insert(result, "-shared") end if cfg.system == "windows" and not cfg.flags.NoImportLib then table.insert(result, '-Wl,--out-implib="' .. cfg.linktarget.fullpath .. '"') end end if cfg.kind == "WindowedApp" and cfg.system == "windows" then table.insert(result, "-mwindows") end local platform = platforms[cfg.platform] table.insert(result, platform.flags) table.insert(result, platform.ldflags) return result end function premake.gcc.getlibdirflags(cfg) local result = { } for _, value in ipairs(premake.getlinks(cfg, "all", "directory")) do table.insert(result, '-L\"' .. value .. '\"') end return result end function premake.gcc.islibfile(p) if path.getextension(p) == ".a" then return true end return false end function premake.gcc.getlibfiles(cfg) local result = {} for _, value in ipairs(premake.getlinks(cfg, "system", "fullpath")) do if premake.gcc.islibfile(value) then table.insert(result, _MAKE.esc(value)) end end return result end function premake.gcc.getlinkflags(cfg) local result = {} for _, value in ipairs(premake.getlinks(cfg, "system", "fullpath")) do if premake.gcc.islibfile(value) then value = path.rebase(value, cfg.project.location, cfg.location) table.insert(result, _MAKE.esc(value)) elseif path.getextension(value) == ".framework" then table.insert(result, '-framework ' .. _MAKE.esc(path.getbasename(value))) else table.insert(result, '-l' .. _MAKE.esc(path.getname(value))) end end return result end function premake.gcc.wholearchive(lib) if premake.gcc.llvm then return {"-force_load", lib} elseif os.get() == "macosx" then return {"-Wl,-force_load", lib} else return {"-Wl,--whole-archive", lib, "-Wl,--no-whole-archive"} end end function premake.gcc.getarchiveflags(prj, cfg, ndx) local result = {} if cfg.platform:startswith("Universal") then if prj.options.ArchiveSplit then error("gcc tool 'Universal*' platforms do not support split archives") end table.insert(result, '-o') else if (not prj.options.ArchiveSplit) then if premake.gcc.llvm then table.insert(result, 'rcs') else table.insert(result, '-rcs') end else if premake.gcc.llvm then if (not ndx) then table.insert(result, 'qc') else table.insert(result, 'cs') end else if (not ndx) then table.insert(result, '-qc') else table.insert(result, '-cs') end end end end return result end function premake.gcc.getdefines(defines) local result = { } for _,def in ipairs(defines) do table.insert(result, "-D" .. def) end return result end function premake.gcc.getincludedirs(includedirs) local result = { } for _,dir in ipairs(includedirs) do table.insert(result, "-I\"" .. dir .. "\"") end return result end function premake.gcc.getquoteincludedirs(includedirs) local result = { } for _,dir in ipairs(includedirs) do table.insert(result, "-iquote \"" .. dir .. "\"") end return result end function premake.gcc.getsystemincludedirs(includedirs) local result = { } for _,dir in ipairs(includedirs) do table.insert(result, "-isystem \"" .. dir .. "\"") end return result end function premake.gcc.getcfgsettings(cfg) return platforms[cfg.platform].cfgsettings end premake.ghs = { } premake.ghs.namestyle = "PS3" premake.ghs.cc = "ccppc" premake.ghs.cxx = "cxppc" premake.ghs.ar = "cxppc" local cflags = { FatalWarnings = "--quit_after_warnings", Optimize = "-Ogeneral", OptimizeSize = "-Osize", OptimizeSpeed = "-Ospeed", Symbols = "-g", } local cxxflags = { NoExceptions = "--no_exceptions", NoRTTI = "--no_rtti", UnsignedChar = "--unsigned_chars", } premake.ghs.platforms = { Native = { cppflags = "-MMD", }, PowerPC = { cc = "ccppc", cxx = "cxppc", ar = "cxppc", cppflags = "-MMD", arflags = "-archive -o", }, ARM = { cc = "ccarm", cxx = "cxarm", ar = "cxarm", cppflags = "-MMD", arflags = "-archive -o", } } local platforms = premake.ghs.platforms function premake.ghs.getcppflags(cfg) local flags = { } table.insert(flags, platforms[cfg.platform].cppflags) return flags end function premake.ghs.getcflags(cfg) local result = table.translate(cfg.flags, cflags) table.insert(result, platforms[cfg.platform].flags) return result end function premake.ghs.getcxxflags(cfg) local result = table.translate(cfg.flags, cxxflags) return result end function premake.ghs.getldflags(cfg) local result = { } local platform = platforms[cfg.platform] table.insert(result, platform.flags) table.insert(result, platform.ldflags) return result end function premake.ghs.getlibdirflags(cfg) local result = { } for _, value in ipairs(premake.getlinks(cfg, "all", "directory")) do table.insert(result, '-L' .. _MAKE.esc(value)) end return result end function premake.ghs.getlibfiles(cfg) local result = {} return result end function premake.ghs.getlinkflags(cfg) local result = {} for _, value in ipairs(premake.getlinks(cfg, "system", "name")) do table.insert(result, '-lnk=' .. _MAKE.esc(value)) end return result end function premake.ghs.getarchiveflags(prj, cfg, ndx) if prj.options.ArchiveSplit then error("ghs tool does not support split archives") end local result = {} local platform = platforms[cfg.platform] table.insert(result, platform.arflags) return result end function premake.ghs.getdefines(defines) local result = { } for _,def in ipairs(defines) do table.insert(result, '-D' .. def) end return result end function premake.ghs.getincludedirs(includedirs) local result = { } for _,dir in ipairs(includedirs) do table.insert(result, "-I" .. _MAKE.esc(dir)) end return result end function premake.ghs.getcfgsettings(cfg) return platforms[cfg.platform].cfgsettings end premake.msc = { } premake.msc.namestyle = "windows" premake.ow = { } premake.ow.namestyle = "windows" premake.ow.cc = "WCL386" premake.ow.cxx = "WCL386" premake.ow.ar = "ar" local cflags = { PedanticWarnings = "-wx", ExtraWarnings = "-wx", FatalWarning = "-we", FloatFast = "-omn", FloatStrict = "-op", Optimize = "-ox", OptimizeSize = "-os", OptimizeSpeed = "-ot", Symbols = "-d2", } local cxxflags = { NoExceptions = "-xd", NoRTTI = "-xr", } premake.ow.platforms = { Native = { flags = "" }, } function premake.ow.getcppflags(cfg) return {} end function premake.ow.getcflags(cfg) local result = table.translate(cfg.flags, cflags) if (cfg.flags.Symbols) then table.insert(result, "-hw") -- Watcom debug format for Watcom debugger end return result end function premake.ow.getcxxflags(cfg) local result = table.translate(cfg.flags, cxxflags) return result end function premake.ow.getldflags(cfg) local result = { } if (cfg.flags.Symbols) then table.insert(result, "op symf") end return result end function premake.ow.getlibfiles(cfg) local result = {} return result end function premake.ow.getlinkflags(cfg) local result = { } return result end function premake.ow.getdefines(defines) local result = { } for _,def in ipairs(defines) do table.insert(result, '-D' .. def) end return result end function premake.ow.getincludedirs(includedirs) local result = { } for _,dir in ipairs(includedirs) do table.insert(result, '-I "' .. dir .. '"') end return result end premake.snc = { } premake.snc.cc = "snc" premake.snc.cxx = "g++" premake.snc.ar = "ar" local cflags = { PedanticWarnings = "-Xdiag=2", ExtraWarnings = "-Xdiag=2", FatalWarnings = "-Xquit=2", } local cxxflags = { NoExceptions = "", -- No exceptions is the default in the SNC compiler. NoRTTI = "-Xc-=rtti", } premake.snc.platforms = { PS3 = { cc = "ppu-lv2-g++", cxx = "ppu-lv2-g++", ar = "ppu-lv2-ar", cppflags = "-MMD -MP", } } local platforms = premake.snc.platforms function premake.snc.getcppflags(cfg) local result = { } table.insert(result, platforms[cfg.platform].cppflags) return result end function premake.snc.getcflags(cfg) local result = table.translate(cfg.flags, cflags) table.insert(result, platforms[cfg.platform].flags) if cfg.kind == "SharedLib" then table.insert(result, "-fPIC") end return result end function premake.snc.getcxxflags(cfg) local result = table.translate(cfg.flags, cxxflags) return result end function premake.snc.getldflags(cfg) local result = { } if not cfg.flags.Symbols then table.insert(result, "-s") end if cfg.kind == "SharedLib" then table.insert(result, "-shared") if not cfg.flags.NoImportLib then table.insert(result, '-Wl,--out-implib="' .. cfg.linktarget.fullpath .. '"') end end local platform = platforms[cfg.platform] table.insert(result, platform.flags) table.insert(result, platform.ldflags) return result end function premake.snc.getlibdirflags(cfg) local result = { } for _, value in ipairs(premake.getlinks(cfg, "all", "directory")) do table.insert(result, '-L' .. _MAKE.esc(value)) end return result end function premake.snc.getlibfiles(cfg) local result = {} return result end function premake.snc.getlinkflags(cfg) local result = {} for _, value in ipairs(premake.getlinks(cfg, "system", "name")) do table.insert(result, '-l' .. _MAKE.esc(value)) end return result end function premake.snc.getdefines(defines) local result = { } for _,def in ipairs(defines) do table.insert(result, '-D' .. def) end return result end function premake.snc.getincludedirs(includedirs) local result = { } for _,dir in ipairs(includedirs) do table.insert(result, "-I" .. _MAKE.esc(dir)) end return result end premake.valac = { } premake.valac.valac = "valac" premake.valac.cc = premake.gcc.cc premake.valac.glibrc = "glib-compile-resources" local valaflags = { DisableAssert = "--disable-assert", -- Disable assertions DisableSinceCheck = "--disable-since-check", -- Do not check whether used symbols exist in local packages DisableWarnings = "--disable-warnings", -- Disable warnings EnableChecking = "--enable-checking", -- Enable additional run-time checks EnableDeprecated = "--enable-deprecated", -- Enable deprecated features EnableExperimental = "--enable-experimental", -- Enable experimental features EnableExperimentalNonNull = "--enable-experimental-non-null", -- Enable experimental enhancements for non-null types EnableGObjectTracing = "--enable-gobject-tracing", -- Enable GObject creation tracing EnableMemProfiler = "--enable-mem-profiler", -- Enable GLib memory profiler FatalWarnings = "--fatal-warnings", -- Treat warnings as fatal HideInternal = "--hide-internal", -- Hide symbols marked as internal NoStdPkg = "--nostdpkg", -- Do not include standard packages Symbols = "-g", -- Produce debug information } local valaccflags = { Optimize = "-O2", OptimizeSize = "-Os", OptimizeSpeed = "-O3", Symbols = "-g", -- Produce debug information } premake.valac.platforms = { Native = { }, x64 = { flags = "-m64" }, } function premake.valac.getvalaflags(cfg) return table.translate(cfg.flags, valaflags) end function premake.valac.getvalaccflags(cfg) return table.translate(cfg.flags, valaccflags) end function premake.valac.getlinks(links) local result = { } for _, pkg in ipairs(links) do table.insert(result, '--pkg ' .. pkg) end return result end function premake.valac.getdefines(defines) local result = { } for _, def in ipairs(defines) do table.insert(result, '-D ' .. def) end return result end function premake.valac.getvapidirs(vapidirs) local result = { } for _, def in ipairs(vapidirs) do table.insert(result, '--vapidir=' .. def) end return result end premake.swift = { } premake.swift.swiftc = "swiftc" premake.swift.swift = "swift" premake.swift.cc = "gcc" premake.swift.ar = "ar" premake.swift.ld = "ld" premake.swift.dsymutil = "dsymutil" local swiftcflags = { Symbols = "-g", -- Produce debug information DisableWarnings = "--suppress-warnings", -- Disable warnings FatalWarnings = "--warnings-as-errors", -- Treat warnings as fatal Optimize = "-O -whole-module-optimization", OptimizeSize = "-O -whole-module-optimization", OptimizeSpeed = "-Ounchecked -whole-module-optimization", MinimumWarnings = "-minimum-warnings", } local swiftlinkflags = { StaticRuntime = "-static-stdlib", } premake.swift.platforms = { Native = { swiftcflags = "", swiftlinkflags = "", }, x64 = { swiftcflags = "", swiftlinkflags = "", } } local platforms = premake.swift.platforms function premake.swift.get_sdk_path(cfg) return string.trim(os.outputof("xcrun --show-sdk-path")) end function premake.swift.get_sdk_platform_path(cfg) return string.trim(os.outputof("xcrun --show-sdk-platform-path")) end function premake.swift.get_toolchain_path(cfg) return string.trim(os.outputof("xcode-select -p")) .. "/Toolchains/XcodeDefault.xctoolchain" end function premake.swift.gettarget(cfg) return "-target x86_64-apple-macosx10.11" end function premake.swift.getswiftcflags(cfg) local result = table.translate(cfg.flags, swiftcflags) table.insert(result, platforms[cfg.platform].swiftcflags) result = table.join(result, cfg.buildoptions_swift) if cfg.kind == "SharedLib" or cfg.kind == "StaticLib" then table.insert(result, "-parse-as-library") end table.insert(result, premake.swift.gettarget(cfg)) return result end function premake.swift.getswiftlinkflags(cfg) local result = table.translate(cfg.flags, swiftlinkflags) table.insert(result, platforms[cfg.platform].swiftlinkflags) result = table.join(result, cfg.linkoptions_swift) if cfg.kind == "SharedLib" or cfg.kind == "StaticLib" then table.insert(result, "-emit-library") else table.insert(result, "-emit-executable") end table.insert(result, premake.swift.gettarget(cfg)) return result end function premake.swift.getmodulemaps(cfg) local maps = {} if next(cfg.swiftmodulemaps) then for _, mod in ipairs(cfg.swiftmodulemaps) do table.insert(maps, string.format("-Xcc -fmodule-map-file=%s", mod)) end end return maps end function premake.swift.getlibdirflags(cfg) return premake.gcc.getlibdirflags(cfg) end function premake.swift.getldflags(cfg) local result = { platforms[cfg.platform].ldflags } local links = premake.getlinks(cfg, "siblings", "basename") for _,v in ipairs(links) do if path.getextension(v) == ".framework" then table.insert(result, "-framework "..v) else table.insert(result, "-l"..v) end end return result end function premake.swift.getlinkflags(cfg) return premake.gcc.getlinkflags(cfg) end function premake.swift.getarchiveflags(cfg) return "" end function premake.checkprojects() local action = premake.action.current() for sln in premake.solution.each() do if (#sln.projects == 0) then return nil, "solution '" .. sln.name .. "' needs at least one project" end if (#sln.configurations == 0) then return nil, "solution '" .. sln.name .. "' needs configurations" end for prj in premake.solution.eachproject(sln) do if (not prj.language) then return nil, "project '" ..prj.name .. "' needs a language" end if (action.valid_languages) then if (not table.contains(action.valid_languages, prj.language)) then return nil, "the " .. action.shortname .. " action does not support " .. prj.language .. " projects" end end for cfg in premake.eachconfig(prj) do if (not cfg.kind) then return nil, "project '" ..prj.name .. "' needs a kind in configuration '" .. cfg.name .. "'" end if (action.valid_kinds) then if (not table.contains(action.valid_kinds, cfg.kind)) then return nil, "the " .. action.shortname .. " action does not support " .. cfg.kind .. " projects" end end end if action.oncheckproject then action.oncheckproject(prj) end end end return true end function premake.checktools() local action = premake.action.current() if (not action.valid_tools) then return true end for tool, values in pairs(action.valid_tools) do if (_OPTIONS[tool]) then if (not table.contains(values, _OPTIONS[tool])) then return nil, "the " .. action.shortname .. " action does not support /" .. tool .. "=" .. _OPTIONS[tool] .. " (yet)" end else _OPTIONS[tool] = values[1] end end return true end function premake.showhelp() printf("") printf("Usage: genie [options] action [arguments]") printf("") printf("OPTIONS") printf("") for option in premake.option.each() do local trigger = option.trigger local description = option.description if (option.value) then trigger = trigger .. "=" .. option.value end if (option.allowed) then description = description .. "; one of:" end printf(" --%-15s %s", trigger, description) if (option.allowed) then for _, value in ipairs(option.allowed) do printf(" %-14s %s", value[1], value[2]) end end printf("") end printf("ACTIONS") printf("") for action in premake.action.each() do printf(" %-17s %s", action.trigger, action.description) end printf("") printf("For additional information, see https://github.com/bkaradzic/genie") end premake._filelevelconfig = false premake._checkgenerate = true function premake.generate(obj, filename, callback) local prev = io.capture() local abort = (callback(obj) == false) local new = io.endcapture(prev) if abort then premake.stats.num_skipped = premake.stats.num_skipped + 1 return end filename = premake.project.getfilename(obj, filename) if (premake._checkgenerate) then local delta = false local f, err = io.open(filename, "rb") if (not f) then if string.find(err, "No such file or directory") then delta = true else error(err, 0) end else local existing = f:read("*all") if existing ~= new then delta = true end f:close() end if delta then printf("Generating %q", filename) local f, err = io.open(filename, "wb") if (not f) then error(err, 0) end f:write(new) f:close() premake.stats.num_generated = premake.stats.num_generated + 1 else premake.stats.num_skipped = premake.stats.num_skipped + 1 end else printf("Generating %q", filename) local f, err = io.open(filename, "wb") if (not f) then error(err, 0) end f:write(new) f:close() premake.stats.num_generated = premake.stats.num_generated + 1 end end function premake.findDefaultScript(dir, search_upwards) search_upwards = search_upwards or true local last = "" while dir ~= last do for _, name in ipairs({ "genie.lua", "solution.lua", "premake4.lua" }) do local script0 = dir .. "/" .. name if (os.isfile(script0)) then return dir, name end local script1 = dir .. "/scripts/" .. name if (os.isfile(script1)) then return dir .. "/scripts/", name end end last = dir dir = path.getabsolute(dir .. "/..") if dir == "." or not search_upwards then break end end return nil, nil end iter = {} function iter.sortByKeys(arr, f) local a = table.keys(arr) table.sort(a, f) local i = 0 return function() i = i + 1 if a[i] ~= nil then return a[i], arr[a[i]] end end end Set_mt = {} function Set(t) local set = {} for k, l in ipairs(t) do set[l] = true end setmetatable(set, Set_mt) return set end function Set_mt.union(a, b) local res = Set{} for k in pairs(a) do res[k] = true end for k in pairs(b) do res[k] = true end return res end function Set_mt.intersection(a, b) local res = Set{} for k in pairs(a) do res[k] = b[k] end return res end local function get_cache(a) if not rawget(a, "__cache") then rawset(a, "__cache", Set_mt.totable(a)) end return rawget(a, "__cache") end function Set_mt.len(a) return #get_cache(a) end function Set_mt.implode(a, sep) return table.concat(get_cache(a), sep) end function Set_mt.totable(a) local res = {} for k in pairs(a) do table.insert(res, k) end return res end function Set_mt.difference(a, b) if getmetatable(b) ~= Set_mt then if type(b) ~= "table" then error(type(b).." is not a Set or table") end b=Set(b) end local res = Set{} for k in pairs(a) do res[k] = not b[k] or nil end rawset(res, "__cache", nil) return res end function Set_mt.__index(a, i) if type(i) == "number" then return get_cache(a)[i] end return Set_mt[i] or rawget(a, i) end Set_mt.__add = Set_mt.union Set_mt.__mul = Set_mt.intersection Set_mt.__sub = Set_mt.difference Set_mt.__len = Set_mt.len Set_mt.__concat = Set_mt.implodepremake.cmake = { } newaction { trigger = "cmake", shortname = "CMake", description = "Generate CMake project files", valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle" }, valid_languages = { "C", "C++" }, valid_tools = { cc = { "gcc" }, }, onsolution = function(sln) premake.generate(sln, "CMakeLists.txt", premake.cmake.workspace) end, onproject = function(prj) premake.generate(prj, "%%/CMakeLists.txt", premake.cmake.project) end, oncleansolution = function(sln) premake.clean.file(sln, "CMakeLists.txt") end, oncleanproject = function(prj) premake.clean.file(prj, "%%/CMakeLists.txt") end }function premake.cmake.workspace(sln) if (sln.location ~= _WORKING_DIR) then local name = string.format("%s/CMakeLists.txt", _WORKING_DIR) local f, err = io.open(name, "wb") if (not f) then error(err, 0) end f:write([[ # CMakeLists autogenerated by GENie project(GENie) cmake_minimum_required(VERSION 3.15) ######################################################################### # Set a default build type if none was specified # Source: https://blog.kitware.com/cmake-and-the-default-build-type/ set(default_build_type "Release") if(EXISTS "${CMAKE_SOURCE_DIR}/.git") set(default_build_type "Debug") endif() if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message(STATUS "Setting build type to '${default_build_type}' as none was specified.") set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING "Choose the type of build." FORCE) # Set the possible values of build type for cmake-gui set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") endif() ######################################################################### ]]) if os.is("windows") then f:write('cmake_policy(SET CMP0091 NEW)\n') end f:write('add_subdirectory('.. path.getrelative(_WORKING_DIR, sln.location) ..')\n') f:close() end _p([[ # CMakeLists autogenerated by GENie cmake_minimum_required(VERSION 3.15) ]]) if os.is("windows") then _p('cmake_policy(SET CMP0091 NEW)') end for i,prj in ipairs(sln.projects) do local name = premake.esc(prj.name) _p('add_subdirectory(%s)', name) end end local cmake = premake.cmake local tree = premake.tree local includestr = 'include_directories(../%s)' local definestr = 'add_definitions(-D%s)' local function is_excluded(prj, cfg, file) if table.icontains(prj.excludes, file) then return true end if table.icontains(cfg.excludes, file) then return true end return false end function cmake.excludedFiles(prj, cfg, src) for _, v in ipairs(src) do if (is_excluded(prj, cfg, v)) then _p(1, 'list(REMOVE_ITEM source_list ../%s)', v) end end end function cmake.list(value) if #value > 0 then return " " .. table.concat(value, " ") else return "" end end function cmake.listWrapped(value, prefix, postfix) if #value > 0 then return prefix .. table.concat(value, postfix .. prefix) .. postfix else return "" end end function cmake.files(prj) local ret = {} local tr = premake.project.buildsourcetree(prj) tree.traverse(tr, { onbranchenter = function(node, depth) end, onbranchexit = function(node, depth) end, onleaf = function(node, depth) assert(node, "unexpected empty node") if node.cfg then table.insert(ret, node.cfg.name) _p(1, '../%s', node.cfg.name) end end, }, true, 1) return ret end function cmake.header(prj) _p('# %s project autogenerated by GENie', premake.action.current().shortname) _p('cmake_minimum_required(VERSION 3.15)') if os.is("windows") then -- Add support for CMP0091, see https://cmake.org/cmake/help/latest/policy/CMP0091.html _p('cmake_policy(SET CMP0091 NEW)') end _p('') _p('project(%s)', premake.esc(prj.name)) _p('') _p('include(GNUInstallDirs)') end function cmake.customtasks(prj) local dirs = {} local tasks = {} for _, custombuildtask in ipairs(prj.custombuildtask or {}) do for _, buildtask in ipairs(custombuildtask or {}) do table.insert(tasks, buildtask) local d = string.format("${CMAKE_CURRENT_SOURCE_DIR}/../%s", path.getdirectory(path.getrelative(prj.location, buildtask[2]))) if not table.contains(dirs, d) then table.insert(dirs, d) _p('file(MAKE_DIRECTORY \"%s\")', d) end end end _p('') for _, buildtask in ipairs(tasks) do local deps = string.format("${CMAKE_CURRENT_SOURCE_DIR}/../%s ", path.getrelative(prj.location, buildtask[1])) local outputs = string.format("${CMAKE_CURRENT_SOURCE_DIR}/../%s ", path.getrelative(prj.location, buildtask[2])) local msg = "" for _, depdata in ipairs(buildtask[3] or {}) do deps = deps .. string.format("${CMAKE_CURRENT_SOURCE_DIR}/../%s ", path.getrelative(prj.location, depdata)) end _p('add_custom_command(') _p(1, 'OUTPUT %s', outputs) _p(1, 'DEPENDS %s', deps) for _, cmdline in ipairs(buildtask[4] or {}) do if (cmdline:sub(1, 1) ~= "@") then local cmd = cmdline local num = 1 for _, depdata in ipairs(buildtask[3] or {}) do cmd = string.gsub(cmd, "%$%(" .. num .. "%)", string.format("${CMAKE_CURRENT_SOURCE_DIR}/../%s ", path.getrelative(prj.location, depdata))) num = num + 1 end cmd = string.gsub(cmd, "%$%(<%)", string.format("${CMAKE_CURRENT_SOURCE_DIR}/../%s ", path.getrelative(prj.location, buildtask[1]))) cmd = string.gsub(cmd, "%$%(@%)", outputs) _p(1, 'COMMAND %s', cmd) else msg = cmdline end end _p(1, 'COMMENT \"%s\"', msg) _p(')') _p('') end end function cmake.depRules(prj) local maintable = {} for _, dependency in ipairs(prj.dependency) do for _, dep in ipairs(dependency) do if path.issourcefile(dep[1]) then local dep1 = premake.esc(path.getrelative(prj.location, dep[1])) local dep2 = premake.esc(path.getrelative(prj.location, dep[2])) if not maintable[dep1] then maintable[dep1] = {} end table.insert(maintable[dep1], dep2) end end end for key, _ in pairs(maintable) do local deplist = {} local depsname = string.format('%s_deps', path.getname(key)) for _, d2 in pairs(maintable[key]) do table.insert(deplist, d2) end _p('set(') _p(1, depsname) for _, v in pairs(deplist) do _p(1, '${CMAKE_CURRENT_SOURCE_DIR}/../%s', v) end _p(')') _p('') _p('set_source_files_properties(') _p(1, '\"${CMAKE_CURRENT_SOURCE_DIR}/../%s\"', key) _p(1, 'PROPERTIES OBJECT_DEPENDS \"${%s}\"', depsname) _p(')') _p('') end end function cmake.commonRules(conf, str) local Dupes = {} local t2 = {} for _, cfg in ipairs(conf) do local cfgd = iif(str == includestr, cfg.includedirs, cfg.defines) for _, v in ipairs(cfgd) do if(t2[v] == #conf - 1) then _p(str, v) table.insert(Dupes, v) end if not t2[v] then t2[v] = 1 else t2[v] = t2[v] + 1 end end end return Dupes end function cmake.cfgRules(cfg, dupes, str) for _, v in ipairs(cfg) do if (not table.icontains(dupes, v)) then _p(1, str, v) end end end function cmake.removeCrosscompiler(platforms) for i = #platforms, 1, -1 do if premake.platforms[platforms[i]].iscrosscompiler then table.remove(platforms, i) end end end function cmake.project(prj) io.indent = " " cmake.header(prj) _p('set(') _p('source_list') local source_files = cmake.files(prj) _p(')') _p('') local nativeplatform = iif(os.is64bit(), "x64", "x32") local cc = premake.gettool(prj) local platforms = premake.filterplatforms(prj.solution, cc.platforms, "Native") cmake.removeCrosscompiler(platforms) local configurations = {} for _, platform in ipairs(platforms) do for cfg in premake.eachconfig(prj, platform) do -- TODO: Extend support for 32-bit targets on 64-bit hosts if cfg.platform == nativeplatform then table.insert(configurations, cfg) end end end local commonIncludes = cmake.commonRules(configurations, includestr) local commonDefines = cmake.commonRules(configurations, definestr) _p('') for _, cfg in ipairs(configurations) do _p('if(CMAKE_BUILD_TYPE MATCHES \"%s\")', cfg.name) -- list excluded files cmake.excludedFiles(prj, cfg, source_files) -- add includes directories cmake.cfgRules(cfg.includedirs, commonIncludes, includestr) -- add build defines cmake.cfgRules(cfg.defines, commonDefines, definestr) -- set CXX flags _p(1, 'set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} %s\")', cmake.list(table.join(cc.getcppflags(cfg), cc.getcflags(cfg), cc.getcxxflags(cfg), cfg.buildoptions, cfg.buildoptions_cpp))) -- set C flags _p(1, 'set(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} %s\")', cmake.list(table.join(cc.getcppflags(cfg), cc.getcflags(cfg), cfg.buildoptions, cfg.buildoptions_c))) _p('endif()') _p('') end -- force CPP if needed if (prj.options.ForceCPP) then _p('set_source_files_properties(${source_list} PROPERTIES LANGUAGE CXX)') end -- add custom tasks cmake.customtasks(prj) -- per-dependency build rules cmake.depRules(prj) for _, cfg in ipairs(configurations) do _p('if(CMAKE_BUILD_TYPE MATCHES \"%s\")', cfg.name) if (prj.kind == 'StaticLib') then _p(1, 'add_library(%s STATIC ${source_list})', premake.esc(cfg.buildtarget.basename)) -- Install _p(1, 'install(TARGETS %s RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR})', premake.esc(cfg.buildtarget.basename)) end if (prj.kind == 'SharedLib') then _p(1, 'add_library(%s SHARED ${source_list})', premake.esc(cfg.buildtarget.basename)) -- Install _p(1, 'install(TARGETS %s RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR})', premake.esc(cfg.buildtarget.basename)) end if (prj.kind == 'ConsoleApp' or prj.kind == 'WindowedApp') then _p(1, 'add_executable(%s ${source_list})', premake.esc(cfg.buildtarget.basename)) local libdirs = cmake.listWrapped(premake.esc(premake.getlinks(cfg, "all", "directory")), " -L\"../", "\"") _p(1, 'target_link_libraries(%s%s%s%s%s%s)', premake.esc(cfg.buildtarget.basename), libdirs, cmake.list(cfg.linkoptions), cmake.list(cc.getldflags(cfg)), cmake.list(premake.esc(premake.getlinks(cfg, "siblings", "basename"))), cmake.list(cc.getlinkflags(cfg))) -- Install _p(1, 'install(TARGETS %s RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})', premake.esc(cfg.buildtarget.basename)) end _p('endif()') _p('') end end_MAKE = { } premake.make = { } local make = premake.make function _MAKE.esc(value) local result if (type(value) == "table") then result = { } for _,v in ipairs(value) do table.insert(result, _MAKE.esc(v)) end return result else result = value:gsub("\\", "\\\\") result = result:gsub(" ", "\\ ") result = result:gsub("%%(", "\\%(") result = result:gsub("%%)", "\\%)") result = result:gsub("$\\%((.-)\\%)", "$%(%1%)") return result end end function _MAKE.escquote(value) local result if (type(value) == "table") then result = { } for _,v in ipairs(value) do table.insert(result, _MAKE.escquote(v)) end return result else result = value:gsub(" ", "\\ ") result = result:gsub("\"", "\\\"") return result end end function premake.make_copyrule(source, target) _p('%s: %s', target, source) _p('\t@echo Copying $(notdir %s)', target) _p('\t-$(call COPY,%s,%s)', source, target) end function premake.make_mkdirrule(var) _p('\t@echo Creating %s', var) _p('\t-$(call MKDIR,%s)', var) _p('') end function make.list(value) if #value > 0 then return " " .. table.concat(value, " ") else return "" end end function _MAKE.getmakefilename(this, searchprjs) local count = 0 for sln in premake.solution.each() do if (sln.location == this.location) then count = count + 1 end if (searchprjs) then for _,prj in ipairs(sln.projects) do if (prj.location == this.location) then count = count + 1 end end end end if (count == 1) then return "Makefile" else return this.name .. ".make" end end function _MAKE.getnames(tbl) local result = table.extract(tbl, "name") for k,v in pairs(result) do result[k] = _MAKE.esc(v) end return result end function make.settings(cfg, cc) if #cfg.makesettings > 0 then for _, value in ipairs(cfg.makesettings) do _p(value) end end local toolsettings = cc.platforms[cfg.platform].cfgsettings if toolsettings then _p(toolsettings) end end newaction { trigger = "gmake", shortname = "GNU Make", description = "Generate GNU makefiles for POSIX, MinGW, and Cygwin", valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle" }, valid_languages = { "C", "C++", "C#", "Vala", "Swift" }, valid_tools = { cc = { "gcc", "ghs" }, dotnet = { "mono", "msnet", "pnet" }, valac = { "valac" }, swift = { "swift" }, }, onsolution = function(sln) premake.generate(sln, _MAKE.getmakefilename(sln, false), premake.make_solution) end, onproject = function(prj) local makefile = _MAKE.getmakefilename(prj, true) if premake.isdotnetproject(prj) then premake.generate(prj, makefile, premake.make_csharp) elseif premake.iscppproject(prj) then premake.generate(prj, makefile, premake.make_cpp) elseif premake.isswiftproject(prj) then premake.generate(prj, makefile, premake.make_swift) else premake.generate(prj, makefile, premake.make_vala) end end, oncleansolution = function(sln) premake.clean.file(sln, _MAKE.getmakefilename(sln, false)) end, oncleanproject = function(prj) premake.clean.file(prj, _MAKE.getmakefilename(prj, true)) end, gmake = {} } function premake.make_solution(sln) local cc = premake[_OPTIONS.cc] local platforms = premake.filterplatforms(sln, cc.platforms, "Native") _p('# %s solution makefile autogenerated by GENie', premake.action.current().shortname) _p('# Type "make help" for usage help') _p('') _p('ifndef config') _p(' config=%s', _MAKE.esc(premake.getconfigname(sln.configurations[1], platforms[1], true))) _p('endif') _p('export config') _p('') local projects = table.extract(sln.projects, "name") table.sort(projects) _p('PROJECTS := %s', table.concat(_MAKE.esc(projects), " ")) _p('') _p('.PHONY: all clean help $(PROJECTS)') _p('') _p('all: $(PROJECTS)') _p('') for _, prj in ipairs(sln.projects) do _p('%s: %s', _MAKE.esc(prj.name), table.concat(_MAKE.esc(table.extract(premake.getdependencies(prj), "name")), " ")) if (not sln.messageskip) or (not table.contains(sln.messageskip, "SkipBuildingMessage")) then _p('\t@echo "==== Building %s ($(config)) ===="', prj.name) end _p('\t@${MAKE} --no-print-directory -C %s -f %s', _MAKE.esc(path.getrelative(sln.location, prj.location)), _MAKE.esc(_MAKE.getmakefilename(prj, true))) _p('') end _p('clean:') for _ ,prj in ipairs(sln.projects) do _p('\t@${MAKE} --no-print-directory -C %s -f %s clean', _MAKE.esc(path.getrelative(sln.location, prj.location)), _MAKE.esc(_MAKE.getmakefilename(prj, true))) end _p('') _p('help:') _p(1,'@echo "Usage: make [config=name] [target]"') _p(1,'@echo ""') _p(1,'@echo "CONFIGURATIONS:"') local cfgpairs = { } for _, platform in ipairs(platforms) do for _, cfgname in ipairs(sln.configurations) do _p(1,'@echo " %s"', premake.getconfigname(cfgname, platform, true)) end end _p(1,'@echo ""') _p(1,'@echo "TARGETS:"') _p(1,'@echo " all (default)"') _p(1,'@echo " clean"') for _, prj in ipairs(sln.projects) do _p(1,'@echo " %s"', prj.name) end _p(1,'@echo ""') _p(1,'@echo "For more information, see https://github.com/bkaradzic/genie"') end -- -- premake.make.cpp = { } premake.make.override = { } premake.make.makefile_ignore = false local cpp = premake.make.cpp local make = premake.make function premake.make_cpp(prj) local cc = premake.gettool(prj) local platforms = premake.filterplatforms(prj.solution, cc.platforms, "Native") local action = premake.action.current() premake.gmake_cpp_header(prj, cc, platforms) premake.gmake_cpp_configs(prj, cc, platforms) table.sort(prj.allfiles) local objdirs = {} local additionalobjdirs = {} for _, file in ipairs(prj.allfiles) do if path.issourcefile(file) then objdirs[_MAKE.esc(path.getdirectory(path.trimdots(file)))] = 1 end end for _, custombuildtask in ipairs(prj.custombuildtask or {}) do for _, buildtask in ipairs(custombuildtask or {}) do additionalobjdirs[_MAKE.esc(path.getdirectory(path.getrelative(prj.location,buildtask[2])))] = 1 end end _p('OBJDIRS := \\') _p('\t$(OBJDIR) \\') for dir, _ in iter.sortByKeys(objdirs) do _p('\t$(OBJDIR)/%s \\', dir) end for dir, _ in iter.sortByKeys(additionalobjdirs) do _p('\t%s \\', dir) end _p('') _p('RESOURCES := \\') for _, file in ipairs(prj.allfiles) do if path.isresourcefile(file) then _p('\t$(OBJDIR)/%s.res \\', _MAKE.esc(path.getbasename(file))) end end _p('') _p('.PHONY: clean prebuild prelink') _p('') if os.is("MacOSX") and prj.kind == "WindowedApp" and not prj.options.SkipBundling then _p('all: $(OBJDIRS) $(TARGETDIR) prebuild prelink $(TARGET) $(dir $(TARGETDIR))PkgInfo $(dir $(TARGETDIR))Info.plist') else _p('all: $(OBJDIRS) $(TARGETDIR) prebuild prelink $(TARGET)') end _p('\t@:') _p('') if (prj.kind == "StaticLib" and prj.options.ArchiveSplit) then _p('define max_args') _p('\t$(eval _args:=)') _p('\t$(foreach obj,$3,$(eval _args+=$(obj))$(if $(word $2,$(_args)),$1 $(_args)$(EOL)$(eval _args:=)))') _p('\t$(if $(_args),$1 $(_args))') _p('endef') _p('') _p('define EOL') _p('') _p('') _p('endef') _p('') end _p('$(TARGET): $(GCH) $(OBJECTS) $(LIBDEPS) $(EXTERNAL_LIBS) $(RESOURCES) $(OBJRESP) $(LDRESP) | $(TARGETDIR) $(OBJDIRS)') if prj.kind == "StaticLib" then if prj.msgarchiving then _p('\t@echo ' .. prj.msgarchiving) else _p('\t@echo Archiving %s', prj.name) end if (not prj.archivesplit_size) then prj.archivesplit_size=200 end if (not prj.options.ArchiveSplit) then _p('ifeq (posix,$(SHELLTYPE))') _p('\t$(SILENT) rm -f $(TARGET)') _p('else') _p('\t$(SILENT) if exist $(subst /,\\\\,$(TARGET)) del $(subst /,\\\\,$(TARGET))') _p('endif') _p('\t$(SILENT) $(LINKCMD) $(LINKOBJS)' .. (os.is("MacOSX") and " 2>&1 > /dev/null | sed -e '/.o) has no symbols$$/d'" or "")) else _p('\t$(call RM,$(TARGET))') _p('\t@$(call max_args,$(LINKCMD),'.. prj.archivesplit_size ..',$(LINKOBJS))' .. (os.is("MacOSX") and " 2>&1 > /dev/null | sed -e '/.o) has no symbols$$/d'" or "")) _p('\t$(SILENT) $(LINKCMD_NDX)') end else if prj.msglinking then _p('\t@echo ' .. prj.msglinking) else _p('\t@echo Linking %s', prj.name) end _p('\t$(SILENT) $(LINKCMD)') end _p('\t$(POSTBUILDCMDS)') _p('') _p('$(TARGETDIR):') premake.make_mkdirrule("$(TARGETDIR)") _p('$(OBJDIRS):') if (not prj.solution.messageskip) or (not table.contains(prj.solution.messageskip, "SkipCreatingMessage")) then _p('\t@echo Creating $(@)') end _p('\t-$(call MKDIR,$@)') _p('') if os.is("MacOSX") and prj.kind == "WindowedApp" and not prj.options.SkipBundling then _p('$(dir $(TARGETDIR))PkgInfo:') _p('$(dir $(TARGETDIR))Info.plist:') _p('') end _p('clean:') if (not prj.solution.messageskip) or (not table.contains(prj.solution.messageskip, "SkipCleaningMessage")) then _p('\t@echo Cleaning %s', prj.name) end _p('ifeq (posix,$(SHELLTYPE))') _p('\t$(SILENT) rm -f $(TARGET)') _p('\t$(SILENT) rm -rf $(OBJDIR)') _p('else') _p('\t$(SILENT) if exist $(subst /,\\\\,$(TARGET)) del $(subst /,\\\\,$(TARGET))') _p('\t$(SILENT) if exist $(subst /,\\\\,$(OBJDIR)) rmdir /s /q $(subst /,\\\\,$(OBJDIR))') _p('endif') _p('') _p('prebuild:') _p('\t$(PREBUILDCMDS)') _p('') _p('prelink:') _p('\t$(PRELINKCMDS)') _p('') cpp.pchrules(prj) cpp.fileRules(prj, cc) cpp.dependencyRules(prj) for _, custombuildtask in ipairs(prj.custombuildtask or {}) do for _, buildtask in ipairs(custombuildtask or {}) do local deps = string.format("%s ",path.getrelative(prj.location,buildtask[1])) for _, depdata in ipairs(buildtask[3] or {}) do deps = deps .. string.format("%s ",path.getrelative(prj.location,depdata)) end _p('%s: %s | $(TARGETDIR) $(OBJDIRS)' ,path.getrelative(prj.location,buildtask[2]) , deps ) for _, cmdline in ipairs(buildtask[4] or {}) do local cmd = cmdline local num = 1 for _, depdata in ipairs(buildtask[3] or {}) do cmd = string.gsub(cmd,"%$%(" .. num .."%)", string.format("%s ",path.getrelative(prj.location,depdata))) num = num + 1 end cmd = string.gsub(cmd, "%$%(<%)", "$<") cmd = string.gsub(cmd, "%$%(@%)", "$@") _p('\t$(SILENT) %s',cmd) end _p('') end end _p('-include $(OBJECTS:%%.o=%%.d)') _p('ifneq (,$(PCH))') _p(' -include $(OBJDIR)/$(notdir $(PCH)).d') _p(' -include $(OBJDIR)/$(notdir $(PCH))_objc.d') _p('endif') end function premake.gmake_cpp_header(prj, cc, platforms) _p('# %s project makefile autogenerated by GENie', premake.action.current().shortname) _p('') _p('.SUFFIXES:') -- Delete the default suffix rules. _p('') _p('ifndef config') _p(' config=%s', _MAKE.esc(premake.getconfigname(prj.solution.configurations[1], platforms[1], true))) _p('endif') _p('') _p('ifndef verbose') _p(' SILENT = @') _p('endif') _p('') _p('SHELLTYPE := msdos') _p('ifeq (,$(ComSpec)$(COMSPEC))') _p(' SHELLTYPE := posix') _p('endif') _p('ifeq (/bin,$(findstring /bin,$(SHELL)))') _p(' SHELLTYPE := posix') _p('endif') _p('ifeq (/bin,$(findstring /bin,$(MAKESHELL)))') _p(' SHELLTYPE := posix') _p('endif') _p('') _p('ifeq (posix,$(SHELLTYPE))') _p(' MKDIR = $(SILENT) mkdir -p "$(1)"') _p(' COPY = $(SILENT) cp -fR "$(1)" "$(2)"') _p(' RM = $(SILENT) rm -f "$(1)"') _p('else') _p(' MKDIR = $(SILENT) mkdir "$(subst /,\\\\,$(1))" 2> nul || exit 0') _p(' COPY = $(SILENT) copy /Y "$(subst /,\\\\,$(1))" "$(subst /,\\\\,$(2))"') _p(' RM = $(SILENT) del /F "$(subst /,\\\\,$(1))" 2> nul || exit 0') _p('endif') _p('') _p('CC = %s', cc.cc) _p('CXX = %s', cc.cxx) _p('AR = %s', cc.ar) _p('') _p('ifndef RESCOMP') _p(' ifdef WINDRES') _p(' RESCOMP = $(WINDRES)') _p(' else') _p(' RESCOMP = %s', cc.rc or 'windres') _p(' endif') _p('endif') _p('') if (not premake.make.makefile_ignore) then _p('MAKEFILE = %s', _MAKE.getmakefilename(prj, true)) _p('') end end local function is_excluded(prj, cfg, file) if table.icontains(prj.excludes, file) then return true end if table.icontains(cfg.excludes, file) then return true end return false end function premake.gmake_cpp_configs(prj, cc, platforms) for _, platform in ipairs(platforms) do for cfg in premake.eachconfig(prj, platform) do premake.gmake_cpp_config(prj, cfg, cc) end end end function premake.gmake_cpp_config(prj, cfg, cc) _p('ifeq ($(config),%s)', _MAKE.esc(cfg.shortname)) cpp.platformtools(cfg, cc) local targetDir = _MAKE.esc(cfg.buildtarget.directory) _p(' ' .. (table.contains(premake.make.override,"OBJDIR") and "override " or "") .. 'OBJDIR = %s', _MAKE.esc(cfg.objectsdir)) _p(' ' .. (table.contains(premake.make.override,"TARGETDIR") and "override " or "") .. 'TARGETDIR = %s', iif(targetDir == "", ".", targetDir)) _p(' ' .. (table.contains(premake.make.override,"TARGET") and "override " or "") .. 'TARGET = $(TARGETDIR)/%s', _MAKE.esc(cfg.buildtarget.name)) _p(' DEFINES +=%s', make.list(_MAKE.escquote(cc.getdefines(cfg.defines)))) local id = make.list(cc.getincludedirs(cfg.includedirs)); local uid = make.list(cc.getquoteincludedirs(cfg.userincludedirs)) local sid = make.list(cc.getsystemincludedirs(cfg.systemincludedirs)) if id ~= "" then _p(' INCLUDES +=%s', id) end if uid ~= "" then _p(' INCLUDES +=%s', uid) end if sid ~= "" then _p(' INCLUDES +=%s', sid) end cpp.pchconfig(cfg) cpp.flags(cfg, cc) cpp.linker(prj, cfg, cc) table.sort(cfg.files) if cfg.flags.UseObjectResponseFile then _p(' OBJRESP = $(OBJDIR)/%s_objects', prj.name) else _p(' OBJRESP =') end _p(' OBJECTS := \\') for _, file in ipairs(cfg.files) do if path.issourcefile(file) then if not is_excluded(prj, cfg, file) then _p('\t$(OBJDIR)/%s.o \\' , _MAKE.esc(path.trimdots(path.removeext(file))) ) end end end _p('') _p(' define PREBUILDCMDS') if #cfg.prebuildcommands > 0 then _p('\t@echo Running pre-build commands') _p('\t%s', table.implode(cfg.prebuildcommands, "", "", "\n\t")) end _p(' endef') _p(' define PRELINKCMDS') if #cfg.prelinkcommands > 0 then _p('\t@echo Running pre-link commands') _p('\t%s', table.implode(cfg.prelinkcommands, "", "", "\n\t")) end _p(' endef') _p(' define POSTBUILDCMDS') if #cfg.postbuildcommands > 0 then _p('\t@echo Running post-build commands') _p('\t%s', table.implode(cfg.postbuildcommands, "", "", "\n\t")) end _p(' endef') make.settings(cfg, cc) _p('endif') _p('') end function cpp.platformtools(cfg, cc) local platform = cc.platforms[cfg.platform] if platform.cc then _p(' CC = %s', platform.cc) end if platform.cxx then _p(' CXX = %s', platform.cxx) end if platform.ar then _p(' AR = %s', platform.ar) end end function cpp.flags(cfg, cc) if cfg.pchheader and not cfg.flags.NoPCH then _p(' FORCE_INCLUDE += -include $(OBJDIR)/$(notdir $(PCH))') _p(' FORCE_INCLUDE_OBJC += -include $(OBJDIR)/$(notdir $(PCH))_objc') end if #cfg.forcedincludes > 0 then _p(' FORCE_INCLUDE += -include %s' ,_MAKE.esc(table.concat(cfg.forcedincludes, ";"))) end _p(' ALL_CPPFLAGS += $(CPPFLAGS) %s $(DEFINES) $(INCLUDES)', table.concat(cc.getcppflags(cfg), " ")) _p(' ALL_ASMFLAGS += $(ASMFLAGS) $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH)%s', make.list(table.join(cc.getcflags(cfg), cfg.buildoptions, cfg.buildoptions_asm))) _p(' ALL_CFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH)%s', make.list(table.join(cc.getcflags(cfg), cfg.buildoptions, cfg.buildoptions_c))) _p(' ALL_CXXFLAGS += $(CXXFLAGS) $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH)%s', make.list(table.join(cc.getcflags(cfg), cc.getcxxflags(cfg), cfg.buildoptions, cfg.buildoptions_cpp))) _p(' ALL_OBJCFLAGS += $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH)%s', make.list(table.join(cc.getcflags(cfg), cc.getobjcflags(cfg), cfg.buildoptions, cfg.buildoptions_objc))) _p(' ALL_OBJCPPFLAGS += $(CXXFLAGS) $(CFLAGS) $(ALL_CPPFLAGS) $(ARCH)%s', make.list(table.join(cc.getcflags(cfg), cc.getcxxflags(cfg), cc.getobjcflags(cfg), cfg.buildoptions, cfg.buildoptions_objcpp))) _p(' ALL_RESFLAGS += $(RESFLAGS) $(DEFINES) $(INCLUDES)%s', make.list(table.join(cc.getdefines(cfg.resdefines), cc.getincludedirs(cfg.resincludedirs), cfg.resoptions))) end function cpp.linker(prj, cfg, cc) local libdeps local lddeps if #cfg.wholearchive > 0 then libdeps = {} lddeps = {} for _, linkcfg in ipairs(premake.getlinks(cfg, "siblings", "object")) do local linkpath = path.rebase(linkcfg.linktarget.fullpath, linkcfg.location, cfg.location) if table.icontains(cfg.wholearchive, linkcfg.project.name) then lddeps = table.join(lddeps, cc.wholearchive(linkpath)) else table.insert(lddeps, linkpath) end table.insert(libdeps, linkpath) end libdeps = make.list(_MAKE.esc(libdeps)) lddeps = make.list(_MAKE.esc(lddeps)) else libdeps = make.list(_MAKE.esc(premake.getlinks(cfg, "siblings", "fullpath"))) lddeps = libdeps end _p(' ALL_LDFLAGS += $(LDFLAGS)%s', make.list(table.join(cc.getlibdirflags(cfg), cc.getldflags(cfg), cfg.linkoptions))) _p(' LIBDEPS +=%s', libdeps) _p(' LDDEPS +=%s', lddeps) if cfg.flags.UseLDResponseFile then _p(' LDRESP = $(OBJDIR)/%s_libs', prj.name) _p(' LIBS += @$(LDRESP)%s', make.list(cc.getlinkflags(cfg))) else _p(' LDRESP =') _p(' LIBS += $(LDDEPS)%s', make.list(cc.getlinkflags(cfg))) end _p(' EXTERNAL_LIBS +=%s', make.list(cc.getlibfiles(cfg))) _p(' LINKOBJS = %s', (cfg.flags.UseObjectResponseFile and "@$(OBJRESP)" or "$(OBJECTS)")) if cfg.kind == "StaticLib" then if (not prj.options.ArchiveSplit) then _p(' LINKCMD = $(AR) %s $(TARGET)', make.list(cc.getarchiveflags(prj, cfg, false))) else _p(' LINKCMD = $(AR) %s $(TARGET)', make.list(cc.getarchiveflags(prj, cfg, false))) _p(' LINKCMD_NDX = $(AR) %s $(TARGET)', make.list(cc.getarchiveflags(prj, cfg, true))) end else local tool = iif(cfg.language == "C", "CC", "CXX") local startgroup = '' local endgroup = '' if (cfg.flags.LinkSupportCircularDependencies) then startgroup = '-Wl,--start-group ' endgroup = ' -Wl,--end-group' end _p(' LINKCMD = $(%s) -o $(TARGET) $(LINKOBJS) $(RESOURCES) $(ARCH) $(ALL_LDFLAGS) %s$(LIBS)%s', tool, startgroup, endgroup) end end function cpp.pchconfig(cfg) if not cfg.pchheader or cfg.flags.NoPCH then return end local pch = cfg.pchheader for _, incdir in ipairs(cfg.includedirs) do local abspath = path.getabsolute(path.join(cfg.project.location, incdir)) local testname = path.join(abspath, pch) if os.isfile(testname) then pch = path.getrelative(cfg.location, testname) break end end _p(' PCH = %s', _MAKE.esc(pch)) _p(' GCH = $(OBJDIR)/$(notdir $(PCH)).gch') _p(' GCH_OBJC = $(OBJDIR)/$(notdir $(PCH))_objc.gch') end function cpp.pchrules(prj) _p('ifneq (,$(PCH))') _p('$(GCH): $(PCH) $(MAKEFILE) | $(OBJDIR)') if prj.msgprecompile then _p('\t@echo ' .. prj.msgprecompile) else _p('\t@echo $(notdir $<)') end local cmd = iif(prj.language == "C", "$(CC) $(ALL_CFLAGS) -x c-header", "$(CXX) $(ALL_CXXFLAGS) -x c++-header") _p('\t$(SILENT) %s $(DEFINES) $(INCLUDES) -o "$@" -c "$<"', cmd) _p('') _p('$(GCH_OBJC): $(PCH) $(MAKEFILE) | $(OBJDIR)') if prj.msgprecompile then _p('\t@echo ' .. prj.msgprecompile) else _p('\t@echo $(notdir $<)') end local cmd = iif(prj.language == "C", "$(CC) $(ALL_OBJCFLAGS) -x objective-c-header", "$(CXX) $(ALL_OBJCPPFLAGS) -x objective-c++-header") _p('\t$(SILENT) %s $(DEFINES) $(INCLUDES) -o "$@" -c "$<"', cmd) _p('endif') _p('') end function cpp.fileRules(prj, cc) local platforms = premake.filterplatforms(prj.solution, cc.platforms, "Native") _p('ifneq (,$(OBJRESP))') _p('$(OBJRESP): $(OBJECTS) | $(TARGETDIR) $(OBJDIRS)') _p('\t$(SILENT) echo $^') _p('\t$(SILENT) echo $^ > $@') _p('endif') _p('') _p('ifneq (,$(LDRESP))') _p('$(LDRESP): $(LDDEPS) | $(TARGETDIR) $(OBJDIRS)') _p('\t$(SILENT) echo $^') _p('\t$(SILENT) echo $^ > $@') _p('endif') _p('') table.sort(prj.allfiles) for _, file in ipairs(prj.allfiles or {}) do if path.issourcefile(file) then if (path.isobjcfile(file)) then _p('$(OBJDIR)/%s.o: %s $(GCH_OBJC) $(MAKEFILE) | $(OBJDIR)/%s' , _MAKE.esc(path.trimdots(path.removeext(file))) , _MAKE.esc(file) , _MAKE.esc(path.getdirectory(path.trimdots(file))) ) else _p('$(OBJDIR)/%s.o: %s $(GCH) $(MAKEFILE) | $(OBJDIR)/%s' , _MAKE.esc(path.trimdots(path.removeext(file))) , _MAKE.esc(file) , _MAKE.esc(path.getdirectory(path.trimdots(file))) ) end if (path.isobjcfile(file) and prj.msgcompile_objc) then _p('\t@echo ' .. prj.msgcompile_objc) elseif prj.msgcompile then _p('\t@echo ' .. prj.msgcompile) else _p('\t@echo $(notdir $<)') end if (path.isobjcfile(file)) then if (path.iscfile(file)) then _p('\t$(SILENT) $(CXX) $(ALL_OBJCFLAGS) $(FORCE_INCLUDE_OBJC) -o "$@" -c "$<"') else _p('\t$(SILENT) $(CXX) $(ALL_OBJCPPFLAGS) $(FORCE_INCLUDE_OBJC) -o "$@" -c "$<"') end elseif (path.isasmfile(file)) then _p('\t$(SILENT) $(CC) $(ALL_ASMFLAGS) -o "$@" -c "$<"') else cpp.buildcommand(path.iscfile(file) and not prj.options.ForceCPP, "o") end for _, task in ipairs(prj.postcompiletasks or {}) do _p('\t$(SILENT) %s', task) _p('') end _p('') elseif (path.getextension(file) == ".rc") then _p('$(OBJDIR)/%s.res: %s', _MAKE.esc(path.getbasename(file)), _MAKE.esc(file)) if prj.msgresource then _p('\t@echo ' .. prj.msgresource) else _p('\t@echo $(notdir $<)') end _p('\t$(SILENT) $(RESCOMP) $< -O coff -o "$@" $(ALL_RESFLAGS)') _p('') end end end function cpp.dependencyRules(prj) for _, dependency in ipairs(prj.dependency or {}) do for _, dep in ipairs(dependency or {}) do if (dep[3]==nil or dep[3]==false) then _p('$(OBJDIR)/%s.o: %s' , _MAKE.esc(path.trimdots(path.removeext(path.getrelative(prj.location, dep[1])))) , _MAKE.esc(path.getrelative(prj.location, dep[2])) ) else _p('%s: %s' , _MAKE.esc(dep[1]) , _MAKE.esc(path.getrelative(prj.location, dep[2])) ) end _p('') end end end function cpp.buildcommand(iscfile, objext) local flags = iif(iscfile, '$(CC) $(ALL_CFLAGS)', '$(CXX) $(ALL_CXXFLAGS)') _p('\t$(SILENT) %s $(FORCE_INCLUDE) -o "$@" -c "$<"', flags, objext) end local function getresourcefilename(cfg, fname) if path.getextension(fname) == ".resx" then local name = cfg.buildtarget.basename .. "." local dir = path.getdirectory(fname) if dir ~= "." then name = name .. path.translate(dir, ".") .. "." end return "$(OBJDIR)/" .. _MAKE.esc(name .. path.getbasename(fname)) .. ".resources" else return fname end end function premake.make_csharp(prj) local csc = premake.dotnet local cfglibs = { } local cfgpairs = { } local anycfg for cfg in premake.eachconfig(prj) do anycfg = cfg cfglibs[cfg] = premake.getlinks(cfg, "siblings", "fullpath") cfgpairs[cfg] = { } for _, fname in ipairs(cfglibs[cfg]) do if path.getdirectory(fname) ~= cfg.buildtarget.directory then cfgpairs[cfg]["$(TARGETDIR)/" .. _MAKE.esc(path.getname(fname))] = _MAKE.esc(fname) end end end local sources = {} local embedded = { } local copypairs = { } for fcfg in premake.project.eachfile(prj) do local action = csc.getbuildaction(fcfg) if action == "Compile" then table.insert(sources, fcfg.name) elseif action == "EmbeddedResource" then table.insert(embedded, fcfg.name) elseif action == "Content" then copypairs["$(TARGETDIR)/" .. _MAKE.esc(path.getname(fcfg.name))] = _MAKE.esc(fcfg.name) elseif path.getname(fcfg.name):lower() == "app.config" then copypairs["$(TARGET).config"] = _MAKE.esc(fcfg.name) end end local paths = table.translate(prj.libdirs, function(v) return path.join(prj.basedir, v) end) paths = table.join({prj.basedir}, paths) for _, libname in ipairs(premake.getlinks(prj, "system", "fullpath")) do local libdir = os.pathsearch(libname..".dll", unpack(paths)) if (libdir) then local target = "$(TARGETDIR)/" .. _MAKE.esc(path.getname(libname)) local source = path.getrelative(prj.basedir, path.join(libdir, libname))..".dll" copypairs[target] = _MAKE.esc(source) end end _p('# %s project makefile autogenerated by GENie', premake.action.current().shortname) _p('') _p('.SUFFIXES:') -- Delete the default suffix rules. _p('') _p('ifndef config') _p(' config=%s', _MAKE.esc(prj.configurations[1]:lower())) _p('endif') _p('') _p('ifndef verbose') _p(' SILENT = @') _p('endif') _p('') _p('SHELLTYPE := msdos') _p('ifeq (,$(ComSpec)$(COMSPEC))') _p(' SHELLTYPE := posix') _p('endif') _p('ifeq (/bin,$(findstring /bin,$(SHELL)))') _p(' SHELLTYPE := posix') _p('endif') _p('ifeq (/bin,$(findstring /bin,$(MAKESHELL)))') _p(' SHELLTYPE := posix') _p('endif') _p('') _p('ifeq (posix,$(SHELLTYPE))') _p(' MKDIR = $(SILENT) mkdir -p "$(1)"') _p(' COPY = $(SILENT) cp -fR "$(1)" "$(2)"') _p('else') _p(' MKDIR = $(SILENT) mkdir "$(subst /,\\\\,$(1))" 2> nul') _p(' COPY = $(SILENT) copy /Y "$(subst /,\\\\,$(1))" "$(subst /,\\\\,$(2))"') _p('endif') _p('') _p('ifndef CSC') _p(' CSC=%s', csc.getcompilervar(prj)) _p('endif') _p('') _p('ifndef RESGEN') _p(' RESGEN=resgen') _p('endif') _p('') local platforms = premake.filterplatforms(prj.solution, premake[_OPTIONS.cc].platforms) table.insert(platforms, 1, "") for cfg in premake.eachconfig(prj) do premake.gmake_cs_config(cfg, csc, cfglibs) end _p('# To maintain compatibility with VS.NET, these values must be set at the project level') _p('TARGET := $(TARGETDIR)/%s', _MAKE.esc(prj.buildtarget.name)) _p('FLAGS += /t:%s %s', csc.getkind(prj):lower(), table.implode(_MAKE.esc(prj.libdirs), "/lib:", "", " ")) _p('REFERENCES += %s', table.implode(_MAKE.esc(premake.getlinks(prj, "system", "basename")), "/r:", ".dll", " ")) _p('') _p('SOURCES := \\') for _, fname in ipairs(sources) do _p('\t%s \\', _MAKE.esc(path.translate(fname))) end _p('') _p('EMBEDFILES := \\') for _, fname in ipairs(embedded) do _p('\t%s \\', getresourcefilename(prj, fname)) end _p('') _p('COPYFILES += \\') for target, source in pairs(cfgpairs[anycfg]) do _p('\t%s \\', target) end for target, source in pairs(copypairs) do _p('\t%s \\', target) end _p('') _p('SHELLTYPE := msdos') _p('ifeq (,$(ComSpec)$(COMSPEC))') _p(' SHELLTYPE := posix') _p('endif') _p('ifeq (/bin,$(findstring /bin,$(SHELL)))') _p(' SHELLTYPE := posix') _p('endif') _p('ifeq (/bin,$(findstring /bin,$(MAKESHELL)))') _p(' SHELLTYPE := posix') _p('endif') _p('') _p('.PHONY: clean prebuild prelink') _p('') _p('all: $(TARGETDIR) $(OBJDIR) prebuild $(EMBEDFILES) $(COPYFILES) prelink $(TARGET)') _p('') _p('$(TARGET): $(SOURCES) $(EMBEDFILES) $(DEPENDS)') _p('\t$(SILENT) $(CSC) /nologo /out:$@ $(FLAGS) $(REFERENCES) $(SOURCES) $(patsubst %%,/resource:%%,$(EMBEDFILES))') _p('\t$(POSTBUILDCMDS)') _p('') _p('$(TARGETDIR):') premake.make_mkdirrule("$(TARGETDIR)") _p('$(OBJDIR):') premake.make_mkdirrule("$(OBJDIR)") _p('clean:') _p('\t@echo Cleaning %s', prj.name) _p('ifeq (posix,$(SHELLTYPE))') _p('\t$(SILENT) rm -f $(TARGET) $(COPYFILES)') _p('\t$(SILENT) rm -rf $(OBJDIR)') _p('else') _p('\t$(SILENT) if exist $(subst /,\\\\,$(TARGETDIR)/%s.*) del $(subst /,\\\\,$(TARGETDIR)/%s.*)', prj.buildtarget.basename, prj.buildtarget.basename) for target, source in pairs(cfgpairs[anycfg]) do _p('\t$(SILENT) if exist $(subst /,\\\\,%s) del $(subst /,\\\\,%s)', target, target) end for target, source in pairs(copypairs) do _p('\t$(SILENT) if exist $(subst /,\\\\,%s) del $(subst /,\\\\,%s)', target, target) end _p('\t$(SILENT) if exist $(subst /,\\\\,$(OBJDIR)) rmdir /s /q $(subst /,\\\\,$(OBJDIR))') _p('endif') _p('') _p('prebuild:') _p('\t$(PREBUILDCMDS)') _p('') _p('prelink:') _p('\t$(PRELINKCMDS)') _p('') _p('# Per-configuration copied file rules') for cfg in premake.eachconfig(prj) do _p('ifneq (,$(findstring %s,$(config)))', _MAKE.esc(cfg.name:lower())) for target, source in pairs(cfgpairs[cfg]) do premake.make_copyrule(source, target) end _p('endif') _p('') end _p('# Copied file rules') for target, source in pairs(copypairs) do premake.make_copyrule(source, target) end _p('# Embedded file rules') for _, fname in ipairs(embedded) do if path.getextension(fname) == ".resx" then _p('%s: %s', getresourcefilename(prj, fname), _MAKE.esc(fname)) _p('\t$(SILENT) $(RESGEN) $^ $@') end _p('') end end function premake.gmake_cs_config(cfg, csc, cfglibs) local targetDir = _MAKE.esc(cfg.buildtarget.directory) _p('ifneq (,$(findstring %s,$(config)))', _MAKE.esc(cfg.name:lower())) _p(' TARGETDIR := %s', iif(targetDir == "", ".", targetDir)) _p(' OBJDIR := %s', _MAKE.esc(cfg.objectsdir)) _p(' DEPENDS := %s', table.concat(_MAKE.esc(premake.getlinks(cfg, "dependencies", "fullpath")), " ")) _p(' REFERENCES := %s', table.implode(_MAKE.esc(cfglibs[cfg]), "/r:", "", " ")) _p(' FLAGS += %s %s', table.implode(cfg.defines, "/d:", "", " "), table.concat(table.join(csc.getflags(cfg), cfg.buildoptions), " ")) _p(' define PREBUILDCMDS') if #cfg.prebuildcommands > 0 then _p('\t@echo Running pre-build commands') _p('\t%s', table.implode(cfg.prebuildcommands, "", "", "\n\t")) end _p(' endef') _p(' define PRELINKCMDS') if #cfg.prelinkcommands > 0 then _p('\t@echo Running pre-link commands') _p('\t%s', table.implode(cfg.prelinkcommands, "", "", "\n\t")) end _p(' endef') _p(' define POSTBUILDCMDS') if #cfg.postbuildcommands > 0 then _p('\t@echo Running post-build commands') _p('\t%s', table.implode(cfg.postbuildcommands, "", "", "\n\t")) end _p(' endef') _p('endif') _p('') end premake.make.vala = { } premake.make.makefile_ignore = false local vala = premake.make.vala local make = premake.make function premake.make_vala(prj) local valac = premake.gettool(prj) local platforms = premake.filterplatforms(prj.solution, valac.platforms, "Native") premake.gmake_vala_header(prj, valac, platforms) for _, platform in ipairs(platforms) do for cfg in premake.eachconfig(prj, platform) do premake.gmake_valac_config(prj, cfg, valac) end end local objdirs = {} local additionalobjdirs = {} for _, file in ipairs(prj.allfiles) do if path.issourcefile(file) or path.isgresource(file) then objdirs[_MAKE.esc(path.getdirectory(path.trimdots(file)))] = 1 end end _p('OBJDIRS := \\') _p('\t$(OBJDIR) \\') for dir, _ in iter.sortByKeys(objdirs) do _p('\t$(OBJDIR)/%s \\', dir) end for dir, _ in iter.sortByKeys(additionalobjdirs) do _p('\t%s \\', dir) end _p('') _p('.PHONY: clean prebuild prelink') _p('') _p('all: $(OBJDIRS) $(TARGETDIR) prebuild prelink $(TARGET)') _p('\t@:') _p('') _p('$(TARGET): $(OBJECTS) | $(TARGETDIR)') _p('\t@echo Linking %s', prj.name) _p('\t$(SILENT) $(LINKCMD)') _p('\t$(POSTBUILDCMDS)') _p('') _p('$(TARGETDIR):') premake.make_mkdirrule("$(TARGETDIR)") _p('$(OBJDIRS):') if (not prj.solution.messageskip) or (not table.contains(prj.solution.messageskip, "SkipCreatingMessage")) then _p('\t@echo Creating $(@)') end _p('\t-$(call MKDIR,$@)') _p('') _p('clean:') if (not prj.solution.messageskip) or (not table.contains(prj.solution.messageskip, "SkipCleaningMessage")) then _p('\t@echo Cleaning %s', prj.name) end _p('ifeq (posix,$(SHELLTYPE))') _p('\t$(SILENT) rm -f $(TARGET)') _p('else') _p('\t$(SILENT) if exist $(subst /,\\\\,$(TARGET)) del $(subst /,\\\\,$(TARGET))') _p('endif') _p('') _p('prebuild:') _p('\t$(PREBUILDCMDS)') _p('') _p('prelink:') _p('\t$(PRELINKCMDS)') _p('') vala.fileRules(prj, valac) end function premake.gmake_vala_header(prj, valac, platforms) _p('# %s project makefile autogenerated by GENie', premake.action.current().shortname) _p('') _p('.SUFFIXES:') -- Delete the default suffix rules. _p('') _p('ifndef config') _p(' config=%s', _MAKE.esc(premake.getconfigname(prj.solution.configurations[1], platforms[1], true))) _p('endif') _p('') _p('ifndef verbose') _p(' SILENT = @') _p('endif') _p('') _p('SHELLTYPE := msdos') _p('ifeq (,$(ComSpec)$(COMSPEC))') _p(' SHELLTYPE := posix') _p('endif') _p('ifeq (/bin,$(findstring /bin,$(SHELL)))') _p(' SHELLTYPE := posix') _p('endif') _p('ifeq (/bin,$(findstring /bin,$(MAKESHELL)))') _p(' SHELLTYPE := posix') _p('endif') _p('') _p('ifeq (posix,$(SHELLTYPE))') _p(' MKDIR = $(SILENT) mkdir -p "$(1)"') _p(' COPY = $(SILENT) cp -fR "$(1)" "$(2)"') _p(' RM = $(SILENT) rm -f "$(1)"') _p('else') _p(' MKDIR = $(SILENT) mkdir "$(subst /,\\\\,$(1))" 2> nul || exit 0') _p(' COPY = $(SILENT) copy /Y "$(subst /,\\\\,$(1))" "$(subst /,\\\\,$(2))"') _p(' RM = $(SILENT) del /F "$(subst /,\\\\,$(1))" 2> nul || exit 0') _p('endif') _p('') _p('VALAC = %s', valac.valac) _p('CC = %s', valac.cc) _p('GLIBRC = %s', valac.glibrc) _p('') if (not premake.make.makefile_ignore) then _p('MAKEFILE = %s', _MAKE.getmakefilename(prj, true)) _p('') end end local function is_excluded(prj, cfg, file) if table.icontains(prj.excludes, file) then return true end if table.icontains(cfg.excludes, file) then return true end return false end function premake.gmake_valac_config(prj, cfg, valac) _p('ifeq ($(config),%s)', _MAKE.esc(cfg.shortname)) _p(' BASEDIR = %s', _MAKE.esc(path.getrelative(cfg.location, _WORKING_DIR))) _p(' OBJDIR = %s', _MAKE.esc(cfg.objectsdir)) _p(' TARGETDIR = %s', _MAKE.esc(cfg.buildtarget.directory)) _p(' TARGET = $(TARGETDIR)/%s', _MAKE.esc(cfg.buildtarget.name)) _p(' DEFINES +=%s', make.list(valac.getdefines(cfg.defines))) _p(' VAPIDIRS +=%s', make.list(valac.getvapidirs(cfg.vapidirs))) _p(' PKGS +=%s', make.list(valac.getlinks(cfg.links))) _p(' FLAGS += $(DEFINES) $(VAPIDIRS) $(PKGS)%s', make.list(table.join(valac.getvalaflags(cfg), cfg.buildoptions_vala))) _p(' ALL_LDFLAGS+= $(LDFLAGS)%s', make.list(table.join(cfg.linkoptions))) _p(' LINKOBJS = %s', "$(OBJECTS)") _p(' ALL_CFLAGS += $(CFLAGS) $(ARCH)%s', make.list(table.join(cfg.buildoptions, cfg.buildoptions_c, valac.getvalaccflags(cfg)))) _p(' LINKCMD = $(CC) -o $(TARGET) $(LINKOBJS) $(ARCH) $(ALL_LDFLAGS)'); table.sort(cfg.files) _p(' OBJECTS := \\') for _, file in ipairs(cfg.files) do if path.issourcefile(file) or path.isgresource(file) then if not is_excluded(prj, cfg, file) then _p('\t$(OBJDIR)/%s.o \\' , _MAKE.esc(path.trimdots(path.removeext(file))) ) end end end _p('') _p(' SOURCES := \\') for _, file in ipairs(cfg.files) do if path.issourcefile(file) and path.isvalafile(file) then if not is_excluded(prj, cfg, file) then _p('\t%s \\', _MAKE.esc(file)) end end end _p('') _p(' GRESOURCES := \\') for _, file in ipairs(cfg.files) do if path.isgresource(file) then if not is_excluded(prj, cfg, file) then _p('\t%s \\', _MAKE.esc(file)) end end end _p('') _p(' define PREBUILDCMDS') if #cfg.prebuildcommands > 0 then _p('\t@echo Running pre-build commands') _p('\t%s', table.implode(cfg.prebuildcommands, "", "", "\n\t")) end _p(' endef') _p(' define PRELINKCMDS') if #cfg.prelinkcommands > 0 then _p('\t@echo Running pre-link commands') _p('\t%s', table.implode(cfg.prelinkcommands, "", "", "\n\t")) end _p(' endef') _p(' define POSTBUILDCMDS') if #cfg.postbuildcommands > 0 then _p('\t@echo Running post-build commands') _p('\t%s', table.implode(cfg.postbuildcommands, "", "", "\n\t")) end _p(' endef') _p('endif') _p('') end function vala.fileRules(prj, cc) local platforms = premake.filterplatforms(prj.solution, cc.platforms, "Native") _p('ifneq (,$(OBJRESP))') _p('$(OBJRESP): $(OBJECTS) | $(TARGETDIR) $(OBJDIRS)') _p('\t$(SILENT) echo $^') _p('\t$(SILENT) echo $^ > $@') _p('endif') _p('') _p('ifneq (,$(LDRESP))') _p('$(LDRESP): $(LDDEPS) | $(TARGETDIR) $(OBJDIRS)') _p('\t$(SILENT) echo $^') _p('\t$(SILENT) echo $^ > $@') _p('endif') _p('') local pattern_targets = "" table.sort(prj.allfiles) for _, file in ipairs(prj.allfiles or {}) do if path.issourcefile(file) or path.isgresource(file) then if path.isvalafile(file) or path.iscfile(file) or path.isgresource(file) then if path.isvalafile(file) or path.isgresource(file) then _p('$(OBJDIR)/%s.o: $(OBJDIR)/%s.c $(GCH) $(MAKEFILE) | $(OBJDIR)/%s' , _MAKE.esc(path.trimdots(path.removeext(file))) , _MAKE.esc(path.trimdots(path.removeext(file))) , _MAKE.esc(path.getdirectory(path.trimdots(file))) ) if not path.isgresource(file) then pattern_targets = pattern_targets .. "$(OBJDIR)/" .. _MAKE.esc(path.trimdots(path.removeext(file))) .. ".% \\\n" -- Pattern rule: https://stackoverflow.com/a/3077254 end else _p('$(OBJDIR)/%s.o: %s $(GCH) $(MAKEFILE) | $(OBJDIR)/%s' , _MAKE.esc(path.trimdots(path.removeext(file))) , file , _MAKE.esc(path.getdirectory(path.trimdots(file))) ) end if prj.msgcompile then _p('\t@echo ' .. prj.msgcompile) else _p('\t@echo $(notdir $<)') end _p('\t$(SILENT) %s $(FORCE_INCLUDE) -o "$@" -c "$<"' , "$(CC) $(ALL_CFLAGS)" , _MAKE.esc(path.getbasename(file)) ) for _, task in ipairs(prj.postcompiletasks or {}) do _p('\t$(SILENT) %s', task) _p('') end _p('') if path.isgresource(file) then _p('$(OBJDIR)/%s.c: %s $(GCH) $(MAKEFILE) | $(OBJDIR)/%s' , _MAKE.esc(path.trimdots(path.removeext(file))) , _MAKE.esc(file) , _MAKE.esc(path.getdirectory(path.trimdots(file))) ) if prj.msgcompile then _p('\t@echo ' .. prj.msgcompile) else _p('\t@echo $(notdir $<)') end _p('\t$(SILENT) %s "$<" --target="$@" --sourcedir="%s" --generate' , "$(GLIBRC)" , _MAKE.esc(path.getdirectory(file)) ) for _, task in ipairs(prj.postcompiletasks or {}) do _p('\t$(SILENT) %s', task) _p('') end end _p('') end end end if pattern_targets ~= "" then _p('%s: $(SOURCES) $(GRESOURCES) $(GCH) $(MAKEFILE)', pattern_targets) if prj.msgcompile then _p('\t@echo ' .. prj.msgcompile) else _p('\t@echo [GEN] valac') end _p('\t$(SILENT) %s $(SOURCES) --directory $(OBJDIR) --basedir $(BASEDIR) --gresources=$(GRESOURCES) -C > /dev/null' , "$(VALAC) $(FLAGS)" ) for _, task in ipairs(prj.postcompiletasks or {}) do _p('\t$(SILENT) %s', task) _p('') end end end local make = premake.make local swift = { } function premake.make_swift(prj) local tool = premake.gettool(prj) local platforms = premake.filterplatforms(prj.solution, tool.platforms, "Native") _p('# %s project makefile autogenerated by GENie', premake.action.current().shortname) _p('') _p('.SUFFIXES:') -- Delete the default suffix rules. _p('') _p('ifndef config') _p(1, 'config=%s', _MAKE.esc(premake.getconfigname(prj.solution.configurations[1], platforms[1], true))) _p('endif') _p('') _p('ifndef verbose') _p(1, 'SILENT = @') _p('endif') _p('') _p('SHELLTYPE := msdos') _p('ifeq (,$(ComSpec)$(COMSPEC))') _p(1, 'SHELLTYPE := posix') _p('endif') _p('ifeq (/bin,$(findstring /bin,$(SHELL)))') _p(1, 'SHELLTYPE := posix') _p('endif') _p('ifeq (/bin,$(findstring /bin,$(MAKESHELL)))') _p(1, 'SHELLTYPE := posix') _p('endif') _p('') _p('ifeq (posix,$(SHELLTYPE))') _p(1, 'MKDIR = $(SILENT) mkdir -p "$(1)"') _p(1, 'COPY = $(SILENT) cp -fR "$(1)" "$(2)"') _p(1, 'RM = $(SILENT) rm -f "$(1)"') _p('else') _p(1, 'MKDIR = $(SILENT) mkdir "$(subst /,\\\\,$(1))" 2> nul || exit 0') _p(1, 'COPY = $(SILENT) copy /Y "$(subst /,\\\\,$(1))" "$(subst /,\\\\,$(2))"') _p(1, 'RM = $(SILENT) del /F "$(subst /,\\\\,$(1))" 2> nul || exit 0') _p('endif') _p('') _p('SWIFTC = %s', tool.swift) _p('SWIFTLINK = %s', tool.swiftc) _p('DSYMUTIL = %s', tool.dsymutil) _p('AR = %s', tool.ar) _p('') for _, platform in ipairs(platforms) do for cfg in premake.eachconfig(prj, platform) do swift.generate_config(prj, cfg, tool) end end _p('.PHONY: ') _p('') _p('all: $(WORK_DIRS) $(TARGET)') _p('') _p('$(WORK_DIRS):') _p(1, '$(SILENT) $(call MKDIR,$@)') _p('') _p('SOURCES := \\') for _, file in ipairs(prj.files) do if path.isswiftfile(file) then _p(1, '%s \\', _MAKE.esc(file)) end end _p('') local objfiles = {} _p('OBJECTS_WITNESS := $(OBJDIR)/build.stamp') _p('OBJECTS := \\') for _, file in ipairs(prj.files) do if path.isswiftfile(file) then local objname = _MAKE.esc(swift.objectname(file)) table.insert(objfiles, objname) _p(1, '%s \\', objname) end end _p('') swift.file_rules(prj, objfiles) swift.linker(prj, tool) swift.generate_clean(prj) end function swift.objectname(file) return path.join("$(OBJDIR)", path.getname(file)..".o") end function swift.file_rules(prj, objfiles) _p('$(OBJECTS_WITNESS): $(SOURCES)') _p(1, "@rm -f $(OBJDIR)/data.tmp") _p(1, "@touch $(OBJDIR)/data.tmp") _p(1, "$(SILENT) $(SWIFTC) -frontend -c $(SOURCES) -enable-objc-interop $(SDK) -I $(OUT_DIR) $(SWIFTC_FLAGS) -module-cache-path $(MODULECACHE_DIR) -D SWIFT_PACKAGE $(MODULE_MAPS) -emit-module-doc-path $(OUT_DIR)/$(MODULE_NAME).swiftdoc -module-name $(MODULE_NAME) -emit-module-path $(OUT_DIR)/$(MODULE_NAME).swiftmodule -num-threads 8 %s", table.arglist("-o", objfiles)) _p(1, "@mv -f $(OBJDIR)/data.tmp $(OBJECTS_WITNESS)") _p('') _p('$(OBJECTS): $(OBJECTS_WITNESS)') _p(1, '@if test -f $@; then :; else \\') _p(2, 'rm -f $(OBJECTS_WITNESS); \\') _p(2, '$(MAKE) $(AM_MAKEFLAGS) $(OBJECTS_WITNESS); \\') _p(1, 'fi') _p('') end function swift.linker(prj, tool) local lddeps = make.list(premake.getlinks(prj, "siblings", "fullpath")) if prj.kind == "StaticLib" then _p("$(TARGET): $(OBJECTS) %s ", lddeps) _p(1, "$(SILENT) $(AR) cr $(AR_FLAGS) $@ $(OBJECTS) %s", (os.is("MacOSX") and " 2>&1 > /dev/null | sed -e '/.o) has no symbols$$/d'" or "")) else _p("$(TARGET): $(OBJECTS) $(LDDEPS)", lddeps) _p(1, "$(SILENT) $(SWIFTLINK) $(SDK) -L $(OUT_DIR) -o $@ $(SWIFTLINK_FLAGS) $(LD_FLAGS) $(OBJECTS)") _p("ifdef SYMBOLS") _p(1, "$(SILENT) $(DSYMUTIL) $(TARGET) -o $(SYMBOLS)") _p("endif") end _p('') end function swift.generate_clean(prj) _p('clean:') if (not prj.solution.messageskip) or (not table.contains(prj.solution.messageskip, "SkipCleaningMessage")) then _p('\t@echo Cleaning %s', prj.name) end _p('ifeq (posix,$(SHELLTYPE))') _p('\t$(SILENT) rm -f $(TARGET)') _p('\t$(SILENT) rm -rf $(OBJDIR)') _p('\t$(SILENT) rm -rf $(SYMBOLS)') _p('\t$(SILENT) rm -rf $(MODULECACHE_DIR)') _p('else') _p('\t$(SILENT) if exist $(subst /,\\\\,$(TARGET)) del $(subst /,\\\\,$(TARGET))') _p('\t$(SILENT) if exist $(subst /,\\\\,$(OBJDIR)) rmdir /s /q $(subst /,\\\\,$(OBJDIR))') _p('\t$(SILENT) if exist $(subst /,\\\\,$(SYMBOLS)) rmdir /s /q $(subst /,\\\\,$(SYMBOLS))') _p('\t$(SILENT) if exist $(subst /,\\\\,$(MODULECACHE_DIR)) rmdir /s /q $(subst /,\\\\,$(MODULECACHE_DIR))') _p('endif') _p('') end function swift.generate_config(prj, cfg, tool) _p('ifeq ($(config),%s)', _MAKE.esc(cfg.shortname)) _p(1, "OUT_DIR = %s", cfg.buildtarget.directory) _p(1, "MODULECACHE_DIR = $(OUT_DIR)/ModuleCache") _p(1, "TARGET = $(OUT_DIR)/%s", _MAKE.esc(cfg.buildtarget.name)) local objdir = path.join(cfg.objectsdir, prj.name .. ".build") _p(1, "OBJDIR = %s", objdir) _p(1, "MODULE_NAME = %s", prj.name) _p(1, "MODULE_MAPS = %s", make.list(tool.getmodulemaps(cfg))) _p(1, "SWIFTC_FLAGS = %s", make.list(tool.getswiftcflags(cfg))) _p(1, "SWIFTLINK_FLAGS = %s", make.list(tool.getswiftlinkflags(cfg))) _p(1, "AR_FLAGS = %s", make.list(tool.getarchiveflags(cfg, cfg, false))) _p(1, "LD_FLAGS = %s", make.list(tool.getldflags(cfg))) _p(1, "LDDEPS = %s", make.list(premake.getlinks(cfg, "siblings", "fullpath"))) if cfg.flags.Symbols then _p(1, "SYMBOLS = $(TARGET).dSYM") end local sdk = tool.get_sdk_path(cfg) if sdk then _p(1, "TOOLCHAIN_PATH = %s", tool.get_toolchain_path(cfg)) _p(1, "SDK_PATH = %s", sdk) _p(1, "PLATFORM_PATH = %s", tool.get_sdk_platform_path(cfg)) _p(1, "SDK = -sdk $(SDK_PATH)") else _p(1, "SDK_PATH =") _p(1, "SDK =") end _p(1,'WORK_DIRS = $(OUT_DIR) $(OBJDIR)') _p('endif') _p('') end premake.vstudio = { } local toolsets = { vs2010 = "v100", vs2012 = "v110", vs2013 = "v120", vs2015 = "v140", vs2017 = "v141", vs2019 = "v142", vs2022 = "v143", } premake.vstudio.toolset = toolsets[_ACTION] or "unknown?" premake.vstudio.splashpath = '' premake.vstudio.xpwarning = true local vstudio = premake.vstudio vstudio.platforms = { any = "Any CPU", mixed = "Mixed Platforms", Native = "Win32", x86 = "x86", x32 = "Win32", x64 = "x64", PS3 = "PS3", Xbox360 = "Xbox 360", ARM = "ARM", ARM64 = "ARM64", Orbis = "ORBIS", Durango = "Durango", TegraAndroid = "Tegra-Android", NX32 = "NX32", NX64 = "NX64", Emscripten = "Emscripten", } function vstudio.arch(prj) if (prj.language == "C#") then return "Any CPU" else return "Win32" end end function vstudio.iswinrt() return vstudio.storeapp ~= nil and vstudio.storeapp ~= '' end function vstudio.buildconfigs(sln) local cfgs = { } local platforms = premake.filterplatforms(sln, vstudio.platforms, "Native") local hascpp = premake.hascppproject(sln) local hasdotnet = premake.hasdotnetproject(sln) if hasdotnet and (_ACTION > "vs2008" or hascpp) then table.insert(platforms, 1, "mixed") end if hasdotnet and (_ACTION < "vs2010" or not hascpp) then table.insert(platforms, 1, "any") end if _ACTION > "vs2008" then local platforms2010 = { } for _, platform in ipairs(platforms) do if vstudio.platforms[platform] == "Win32" then if hascpp then table.insert(platforms2010, platform) end if hasdotnet then table.insert(platforms2010, "x86") end else table.insert(platforms2010, platform) end end platforms = platforms2010 end for _, buildcfg in ipairs(sln.configurations) do for _, platform in ipairs(platforms) do local entry = { } entry.src_buildcfg = buildcfg entry.src_platform = platform if platform ~= "PS3" or _ACTION > "vs2008" then entry.buildcfg = buildcfg entry.platform = vstudio.platforms[platform] else entry.buildcfg = platform .. " " .. buildcfg entry.platform = "Win32" end entry.name = entry.buildcfg .. "|" .. entry.platform entry.isreal = (platform ~= "any" and platform ~= "mixed") table.insert(cfgs, entry) end end return cfgs end function premake.vstudio.bakeimports(sln) for _,iprj in ipairs(sln.importedprojects) do if string.find(iprj.location, ".csproj") ~= nil then iprj.language = "C#" else iprj.language = "C++" end local f, err = io.open(iprj.location, "r") if (not f) then error(err, 1) end local projcontents = f:read("*all") f:close() local found, _, uuid = string.find(projcontents, "{([%w%-]+)}") if not found then error("Could not find ProjectGuid element in project " .. iprj.location, 1) end iprj.uuid = uuid if iprj.language == "C++" and string.find(projcontents, "true") then iprj.flags.Managed = true end iprj.relpath = path.getrelative(sln.location, iprj.location) end end function premake.vstudio.getimportprj(prjpath, sln) for _,iprj in ipairs(sln.importedprojects) do if prjpath == iprj.relpath then return iprj end end error("Could not find reference import project " .. prjpath, 1) end function vstudio.cleansolution(sln) premake.clean.file(sln, "%%.sln") premake.clean.file(sln, "%%.suo") premake.clean.file(sln, "%%.ncb") premake.clean.file(sln, "%%.userprefs") premake.clean.file(sln, "%%.usertasks") end function vstudio.cleanproject(prj) local fname = premake.project.getfilename(prj, "%%") os.remove(fname .. ".vcproj") os.remove(fname .. ".vcproj.user") os.remove(fname .. ".vcxproj") os.remove(fname .. ".vcxproj.user") os.remove(fname .. ".vcxproj.filters") os.remove(fname .. ".csproj") os.remove(fname .. ".csproj.user") os.remove(fname .. ".pidb") os.remove(fname .. ".sdf") end function vstudio.cleantarget(name) os.remove(name .. ".pdb") os.remove(name .. ".idb") os.remove(name .. ".ilk") os.remove(name .. ".vshost.exe") os.remove(name .. ".exe.manifest") end function vstudio.projectfile(prj) local pattern if prj.language == "C#" then pattern = "%%.csproj" else pattern = iif(_ACTION > "vs2008", "%%.vcxproj", "%%.vcproj") end local fname = premake.project.getbasename(prj.name, pattern) fname = path.join(prj.location, fname) return fname end function vstudio.tool(prj) if (prj.language == "C#") then return "FAE04EC0-301F-11D3-BF4B-00C04F79EFBC" else return "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942" end end premake.vstudio.sln2005 = { } local vstudio = premake.vstudio local sln2005 = premake.vstudio.sln2005 function sln2005.generate(sln) io.eol = '\r\n' sln.vstudio_configs = premake.vstudio.buildconfigs(sln) premake.vstudio.bakeimports(sln) _p('\239\187\191') sln2005.reorderProjects(sln) sln2005.header(sln) for grp in premake.solution.eachgroup(sln) do sln2005.group(grp) end for prj in premake.solution.eachproject(sln) do sln2005.project(prj) end for _,iprj in ipairs(sln.importedprojects) do sln2005.importproject(iprj) end _p('Global') sln2005.platforms(sln) sln2005.project_platforms(sln) sln2005.properties(sln) sln2005.project_groups(sln) _p('EndGlobal') end function sln2005.reorderProjects(sln) if sln.startproject then for i, prj in ipairs(sln.projects) do if sln.startproject == prj.name then local cur = prj.group while cur ~= nil do for j, group in ipairs(sln.groups) do if group == cur then table.remove(sln.groups, j) break end end table.insert(sln.groups, 1, cur) cur = cur.parent end table.remove(sln.projects, i) table.insert(sln.projects, 1, prj) break end end end end function sln2005.header(sln) local action = premake.action.current() _p('Microsoft Visual Studio Solution File, Format Version %d.00', action.vstudio.solutionVersion) if(_ACTION:sub(3) == "2015" or _ACTION:sub(3) == "2017") then _p('# Visual Studio %s', action.vstudio.toolsVersion:sub(1,2)) elseif(_ACTION:sub(3) == "2019") then _p('# Visual Studio Version %s', action.vstudio.toolsVersion:sub(1,2)) else _p('# Visual Studio %s', _ACTION:sub(3)) end end function sln2005.project(prj) local projpath = path.translate(path.getrelative(prj.solution.location, vstudio.projectfile(prj)), "\\") _p('Project("{%s}") = "%s", "%s", "{%s}"', vstudio.tool(prj), prj.name, projpath, prj.uuid) sln2005.projectdependencies(prj) _p('EndProject') end function sln2005.group(grp) _p('Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "%s", "%s", "{%s}"', grp.name, grp.name, grp.uuid) _p('EndProject') end function sln2005.importproject(iprj) _p('Project("{%s}") = "%s", "%s", "{%s}"', vstudio.tool(iprj), path.getbasename(iprj.location), iprj.relpath, iprj.uuid) _p('EndProject') end function sln2005.projectdependencies(prj) local deps = premake.getdependencies(prj) if #deps > 0 then local function compareuuid(a, b) return a.uuid < b.uuid end table.sort(deps, compareuuid) _p('\tProjectSection(ProjectDependencies) = postProject') for _, dep in ipairs(deps) do _p('\t\t{%s} = {%s}', dep.uuid, dep.uuid) end _p('\tEndProjectSection') end end function sln2005.platforms(sln) _p('\tGlobalSection(SolutionConfigurationPlatforms) = preSolution') for _, cfg in ipairs(sln.vstudio_configs) do _p('\t\t%s = %s', cfg.name, cfg.name) end _p('\tEndGlobalSection') end function sln2005.project_platform(prj, sln) for _, cfg in ipairs(sln.vstudio_configs) do local mapped local buildfor if premake.isdotnetproject(prj) then buildfor = "x64" mapped = "Any CPU" elseif prj.flags and prj.flags.Managed then mapped = "x64" else if cfg.platform == "Any CPU" or cfg.platform == "Mixed Platforms" then mapped = sln.vstudio_configs[3].platform else mapped = cfg.platform end end local build_project = true if prj.solution ~= nil then build_project = premake.getconfig(prj, cfg.src_buildcfg, cfg.src_platform).build end _p('\t\t{%s}.%s.ActiveCfg = %s|%s', prj.uuid, cfg.name, cfg.buildcfg, mapped) if build_project then if mapped == cfg.platform or cfg.platform == "Mixed Platforms" or buildfor == cfg.platform then _p('\t\t{%s}.%s.Build.0 = %s|%s', prj.uuid, cfg.name, cfg.buildcfg, mapped) end if premake.vstudio.iswinrt() and prj.kind == "WindowedApp" then _p('\t\t{%s}.%s.Deploy.0 = %s|%s', prj.uuid, cfg.name, cfg.buildcfg, mapped) end end end end function sln2005.project_platforms(sln) _p('\tGlobalSection(ProjectConfigurationPlatforms) = postSolution') for prj in premake.solution.eachproject(sln) do sln2005.project_platform(prj, sln) end for _,iprj in ipairs(sln.importedprojects) do sln2005.project_platform(iprj, sln) end _p('\tEndGlobalSection') end function sln2005.properties(sln) _p('\tGlobalSection(SolutionProperties) = preSolution') _p('\t\tHideSolutionNode = FALSE') _p('\tEndGlobalSection') end function sln2005.project_groups(sln) _p('\tGlobalSection(NestedProjects) = preSolution') for grp in premake.solution.eachgroup(sln) do if grp.parent ~= nil then _p('\t\t{%s} = {%s}', grp.uuid, grp.parent.uuid) end end for prj in premake.solution.eachproject(sln) do if prj.group ~= nil then _p('\t\t{%s} = {%s}', prj.uuid, prj.group.uuid) end end for _,iprj in ipairs(sln.importedprojects) do if iprj.group ~= nil then _p('\t\t{%s} = {%s}', iprj.uuid, iprj.group.uuid) end end _p('\tEndGlobalSection') endpremake.vstudio.vc2010 = { } local vc2010 = premake.vstudio.vc2010 local vstudio = premake.vstudio local function vs2010_config(prj) for _, cfginfo in ipairs(prj.solution.vstudio_configs) do if cfginfo.src_platform == "TegraAndroid" then _p(1,'') _p(2,'11') _p(1,'') break end end _p(1,'') for _, cfginfo in ipairs(prj.solution.vstudio_configs) do _p(2,'', premake.esc(cfginfo.name)) _p(3,'%s',cfginfo.buildcfg) _p(3,'%s',cfginfo.platform) _p(2,'') end _p(1,'') end local function vs2010_globals(prj) local action = premake.action.current() _p(1,'') _p(2, '{%s}',prj.uuid) _p(2, '%s',prj.name) if vstudio.storeapp ~= "durango" then local windowsTargetPlatformVersion = prj.windowstargetplatformversion or action.vstudio.windowsTargetPlatformVersion if windowsTargetPlatformVersion ~= nil then _p(2,'%s',windowsTargetPlatformVersion) if windowsTargetPlatformVersion and string.startswith(windowsTargetPlatformVersion, "10.") then _p(2,'%s', prj.windowstargetplatformminversion or "10.0.10240.0") end end end if prj.flags and prj.flags.Managed then local frameworkVersion = prj.framework or "4.0" _p(2, 'v%s', frameworkVersion) _p(2, 'ManagedCProj') elseif vstudio.iswinrt() then _p(2, 'en-US') if vstudio.storeapp == "durango" then _p(2, 'Win32Proj') _p(2, 'title') _p(2, '14.0') _p(2, 'Native') else _p(2, 'true') _p(2, '12.0') _p(2, 'Windows Store') _p(2, '%s', vstudio.storeapp) end else _p(2, 'Win32Proj') end if not vstudio.xpwarning then _p(2, 'false') end _p(1,'') end function vc2010.config_type(config) local t = { SharedLib = "DynamicLibrary", StaticLib = "StaticLibrary", ConsoleApp = "Application", WindowedApp = "Application" } return t[config.kind] end local function if_config_and_platform() return 'Condition="\'$(Configuration)|$(Platform)\'==\'%s\'"' end local function optimisation(cfg) local result = "Disabled" for _, value in ipairs(cfg.flags) do if (value == "Optimize") then result = "Full" elseif (value == "OptimizeSize") then result = "MinSpace" elseif (value == "OptimizeSpeed") then result = "MaxSpeed" end end return result end function vc2010.configurationPropertyGroup(cfg, cfginfo) _p(1, '' , premake.esc(cfginfo.name)) local is2019 = premake.action.current() == premake.action.get("vs2019") local is2022 = premake.action.current() == premake.action.get("vs2022") if is2019 or is2022 then _p(2, '%s', action.vstudio.toolsVersion) if cfg.flags.UnitySupport then _p(2, 'true') end end _p(2, '%s', vc2010.config_type(cfg)) _p(2, '%s', iif(optimisation(cfg) == "Disabled","true","false")) _p(2, '%s', premake.vstudio.toolset) if os.is64bit() then _p(2, 'x64') end if cfg.flags.Unicode then _p(2,'Unicode') end if cfg.flags.Managed then _p(2,'true') end if cfg.platform == "TegraAndroid" then if cfg.androidtargetapi then _p(2,'android-%s', cfg.androidtargetapi) end if cfg.androidminapi then _p(2,'android-%s', cfg.androidminapi) end if cfg.androidarch then _p(2,'%s', cfg.androidarch) end if cfg.androidndktoolchainversion then _p(2,'%s', cfg.androidndktoolchainversion) end if cfg.androidstltype then _p(2,'%s', cfg.androidstltype) end end if cfg.platform == "NX32" or cfg.platform == "NX64" then _p(2,'$(NINTENDO_SDK_ROOT)\\') _p(2,'NX') if premake.config.isdebugbuild(cfg) then _p(2,'Debug') else _p(2,'Release') end end if cfg.flags.Symbols and (premake.action.current() == premake.action.get("vs2017") or is2019) then _p(2, 'true') end _p(1,'') end local function import_props(prj) for _, cfginfo in ipairs(prj.solution.vstudio_configs) do local cfg = premake.getconfig(prj, cfginfo.src_buildcfg, cfginfo.src_platform) _p(1,'' ,premake.esc(cfginfo.name)) _p(2,'') if #cfg.propertysheets > 0 then local dirs = cfg.propertysheets for _, dir in ipairs(dirs) do local translated = path.translate(dir) _p(2,'', translated, translated) end end _p(1,'') end end local function add_trailing_backslash(dir) if dir:len() > 0 and dir:sub(-1) ~= "\\" then return dir.."\\" end return dir end function vc2010.outputProperties(prj) for _, cfginfo in ipairs(prj.solution.vstudio_configs) do local cfg = premake.getconfig(prj, cfginfo.src_buildcfg, cfginfo.src_platform) local target = cfg.buildtarget local outdir = add_trailing_backslash(target.directory) local intdir = add_trailing_backslash(iif(action.vstudio.intDirAbsolute , path.translate( path.join(prj.solution.location, cfg.objectsdir) , '\\') , cfg.objectsdir )) _p(1,'', premake.esc(cfginfo.name)) _p(2,'%s', iif(outdir:len() > 0, premake.esc(outdir), ".\\")) if cfg.platform == "Xbox360" then _p(2,'$(OutDir)%s', premake.esc(target.name)) end _p(2,'%s', premake.esc(intdir)) _p(2,'%s', premake.esc(path.getbasename(target.name))) _p(2,'%s', premake.esc(path.getextension(target.name))) if cfg.kind == "SharedLib" then local ignore = (cfg.flags.NoImportLib ~= nil) _p(2,'%s', tostring(ignore)) end if cfg.platform == "NX32" or cfg.platform == "NX64" then if cfg.flags.Cpp17 then _p(2,'Gnu++17') elseif cfg.flags.Cpp20 then _p(2,'Gnu++20') end end if cfg.platform == "Durango" then _p(2, '$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)') _p(2, '$(Console_SdkLibPath)') _p(2, '$(Console_SdkLibPath);$(Console_SdkWindowsMetadataPath)') _p(2, '$(Console_SdkIncludeRoot)') _p(2, '$(Console_SdkRoot)bin;$(VCInstallDir)bin\\x86_amd64;$(VCInstallDir)bin;$(WindowsSDK_ExecutablePath_x86);$(VSInstallDir)Common7\\Tools\\bin;$(VSInstallDir)Common7\\tools;$(VSInstallDir)Common7\\ide;$(ProgramFiles)\\HTML Help Workshop;$(MSBuildToolsPath32);$(FxCopDir);$(PATH);') if cfg.imagepath then _p(2, '%s', cfg.imagepath) else _p(2, '%s', prj.name) end if cfg.pullmappingfile ~= nil then _p(2,'%s', premake.esc(cfg.pullmappingfile)) end _p(2, '*.pdb;*.ilk;*.exp;*.lib;*.winmd;*.appxrecipe;*.pri;*.idb') _p(2, 'true') end if cfg.kind ~= "StaticLib" then _p(2,'%s', tostring(premake.config.isincrementallink(cfg))) end if cfg.applicationdatadir ~= nil then _p(2,'%s', premake.esc(cfg.applicationdatadir)) end if cfg.flags.NoManifest then _p(2,'false') end _p(1,'') end end local function runtime(cfg) local runtime local flags = cfg.flags if premake.config.isdebugbuild(cfg) then runtime = iif(flags.StaticRuntime and not flags.Managed, "MultiThreadedDebug", "MultiThreadedDebugDLL") else runtime = iif(flags.StaticRuntime and not flags.Managed, "MultiThreaded", "MultiThreadedDLL") end return runtime end local function precompiled_header(cfg) if not cfg.flags.NoPCH and cfg.pchheader then _p(3,'Use') _p(3,'%s', cfg.pchheader) else _p(3,'') end end local function preprocessor(indent,cfg,escape) if #cfg.defines > 0 then local defines = table.concat(cfg.defines, ";") if escape then defines = defines:gsub('"', '\\"') end local isPreprocessorDefinitionPresent = string.find(defines, "%%%(PreprocessorDefinitions%)") if isPreprocessorDefinitionPresent then _p(indent,'%s' ,premake.esc(defines)) else _p(indent,'%s;%%(PreprocessorDefinitions)' ,premake.esc(defines)) end else _p(indent,'') end end local function include_dirs(indent,cfg) local includedirs = table.join(cfg.userincludedirs, cfg.includedirs, cfg.systemincludedirs) if #includedirs> 0 then _p(indent,'%s;%%(AdditionalIncludeDirectories)' ,premake.esc(path.translate(table.concat(includedirs, ";"), '\\'))) end end local function using_dirs(indent,cfg) if #cfg.usingdirs > 0 then _p(indent,'%s;%%(AdditionalUsingDirectories)' ,premake.esc(path.translate(table.concat(cfg.usingdirs, ";"), '\\'))) end end local function resource_compile(cfg) _p(2,'') preprocessor(3,cfg,true) include_dirs(3,cfg) _p(2,'') end local function cppstandard(cfg) if cfg.flags.CppLatest then _p(3, 'stdcpplatest') _p(3, 'true') elseif cfg.flags.Cpp20 then _p(3, 'stdcpp20') elseif cfg.flags.Cpp17 then _p(3, 'stdcpp17') elseif cfg.flags.Cpp14 then _p(3, 'stdcpp14') end end local function exceptions(cfg) if cfg.platform == "Orbis" then if cfg.flags.NoExceptions then _p(3, 'false') end elseif cfg.platform == "TegraAndroid" then if cfg.flags.NoExceptions then _p(3, 'false') end elseif cfg.platform == "NX32" or cfg.platform == "NX64" then if cfg.flags.NoExceptions then _p(3, 'false') else _p(3, 'true') end else if cfg.flags.NoExceptions then _p(3, 'false') elseif cfg.flags.SEH then _p(3, 'Async') end end end local function rtti(cfg) if cfg.flags.NoRTTI and not cfg.flags.Managed then _p(3,'false') end end local function calling_convention(cfg) if cfg.flags.FastCall then _p(3,'FastCall') elseif cfg.flags.StdCall then _p(3,'StdCall') end end local function wchar_t_builtin(cfg) if cfg.flags.NativeWChar then _p(3,'true') elseif cfg.flags.NoNativeWChar then _p(3,'false') end end local function sse(cfg) if cfg.flags.EnableSSE then _p(3, 'StreamingSIMDExtensions') elseif cfg.flags.EnableSSE2 then _p(3, 'StreamingSIMDExtensions2') elseif cfg.flags.EnableAVX then _p(3, 'AdvancedVectorExtensions') elseif cfg.flags.EnableAVX2 then _p(3, 'AdvancedVectorExtensions2') end end local function floating_point(cfg) if cfg.platform == "Orbis" then if cfg.flags.FloatFast then _p(3,'true') end elseif cfg.platform == "TegraAndroid" then elseif cfg.platform == "NX32" or cfg.platform == "NX64" then if cfg.flags.FloatFast then _p(3, 'true') end else if cfg.flags.FloatFast then _p(3,'Fast') elseif cfg.flags.FloatStrict and not cfg.flags.Managed then _p(3,'Strict') end end end local function debug_info(cfg) local debug_info = '' if cfg.flags.Symbols then if cfg.flags.C7DebugInfo then debug_info = "OldStyle" elseif (action.vstudio.supports64bitEditContinue == false and cfg.platform == "x64") or not premake.config.iseditandcontinue(cfg) then debug_info = "ProgramDatabase" else debug_info = "EditAndContinue" end end _p(3,'%s',debug_info) end local function minimal_build(cfg) if premake.config.isdebugbuild(cfg) and cfg.flags.EnableMinimalRebuild then _p(3,'true') else _p(3,'false') end end local function compile_language(cfg) if cfg.options.ForceCPP then _p(3,'CompileAsCpp') else if cfg.language == "C" then _p(3,'CompileAsC') end end end local function forcedinclude_files(indent,cfg) if #cfg.forcedincludes > 0 then _p(indent,'%s' ,premake.esc(path.translate(table.concat(cfg.forcedincludes, ";"), '\\'))) end end local function vs10_clcompile(cfg) _p(2,'') local unsignedChar = "/J " local buildoptions = cfg.buildoptions if cfg.platform == "Orbis" then unsignedChar = "-funsigned-char "; _p(3,'%s', tostring(cfg.flags.Symbols ~= nil)) end if cfg.platform == "NX32" or cfg.platform == "NX64" then unsignedChar = "-funsigned-char "; _p(3,'%s', tostring(cfg.flags.Symbols ~= nil)) end if cfg.language == "C" and not cfg.options.ForceCPP then buildoptions = table.join(buildoptions, cfg.buildoptions_c) else buildoptions = table.join(buildoptions, cfg.buildoptions_cpp) end _p(3,'%s %s%%(AdditionalOptions)' , table.concat(premake.esc(buildoptions), " ") , iif(cfg.flags.UnsignedChar and cfg.platform ~= "TegraAndroid", unsignedChar, " ") ) if cfg.platform == "TegraAndroid" then _p(3,'%s', tostring(cfg.flags.UnsignedChar == nil)) _p(3,'%s', tostring(cfg.flags.Symbols ~= nil)) if cfg.androidcppstandard then _p(3,'%s', cfg.androidcppstandard) end end if cfg.platform == "Orbis" then local opt = optimisation(cfg) if opt == "Disabled" then _p(3,'Level0') elseif opt == "MinSpace" then _p(3,'Levelz') -- Oz is more aggressive than Os elseif opt == "MaxSpeed" then _p(3,'Level3') else _p(3,'Level2') end elseif cfg.platform == "TegraAndroid" then local opt = optimisation(cfg) if opt == "Disabled" then _p(3,'O0') elseif opt == "MinSpace" then _p(3,'Os') elseif opt == "MaxSpeed" then _p(3,'O3') else _p(3,'O2') end elseif cfg.platform == "NX32" or cfg.platform == "NX64" then local opt = optimisation(cfg) if opt == "Disabled" then _p(3,'O0') elseif opt == "MinSpace" then _p(3,'Os') elseif opt == "MaxSpeed" then _p(3,'O3') else _p(3,'O2') end else _p(3,'%s', optimisation(cfg)) end include_dirs(3, cfg) using_dirs(3, cfg) preprocessor(3, cfg) minimal_build(cfg) if premake.config.isoptimizedbuild(cfg.flags) then if cfg.flags.NoOptimizeLink and cfg.flags.NoEditAndContinue then _p(3, 'false') _p(3, 'false') else _p(3, 'true') _p(3, 'true') end else _p(3, 'true') if cfg.flags.NoRuntimeChecks then _p(3, 'Default') elseif not cfg.flags.Managed then _p(3, 'EnableFastChecks') end if cfg.flags.ExtraWarnings then end end if cfg.platform == "Durango" or cfg.flags.NoWinRT then _p(3, 'false') end _p(3, '%s', runtime(cfg)) if cfg.flags.NoBufferSecurityCheck then _p(3, 'false') end if not cfg.flags.NoMultiProcessorCompilation and not cfg.flags.EnableMinimalRebuild then _p(3, 'true') else _p(3, 'false') end precompiled_header(cfg) if cfg.platform == "Orbis" then if cfg.flags.PedanticWarnings then _p(3, 'MoreWarnings') _p(3, 'true') elseif cfg.flags.ExtraWarnings then _p(3, 'NormalWarnings') _p(3, 'true') elseif cfg.flags.MinimumWarnings then _p(3, 'WarningsOff') _p(3, 'false') else _p(3, 'NormalWarnings') _p(3, 'false') end if cfg.flags.FatalWarnings then _p(3, 'true') end elseif cfg.platform == "TegraAndroid" then if cfg.flags.PedanticWarnings or cfg.flags.ExtraWarnings then _p(3, 'AllWarnings') elseif cfg.flags.MinimumWarnings then _p(3, 'DisableAllWarnings') else _p(3, 'NormalWarnings') end if cfg.flags.FatalWarnings then _p(3, 'true') end elseif cfg.platform == "NX32" or cfg.platform == "NX64" then if cfg.flags.PedanticWarnings then _p(3, 'MoreWarnings') _p(3, 'true') elseif cfg.flags.ExtraWarnings then _p(3, 'NormalWarnings') _p(3, 'true') elseif cfg.flags.MinimumWarnings then _p(3, 'WarningsOff') _p(3, 'false') else _p(3, 'NormalWarnings') _p(3, 'false') end if cfg.flags.FatalWarnings then _p(3, 'true') end else if cfg.flags.PedanticWarnings then _p(3, 'EnableAllWarnings') elseif cfg.flags.ExtraWarnings then _p(3, 'Level4') elseif cfg.flags.MinimumWarnings then _p(3, 'Level1') else _p(3 ,'Level3') end end if cfg.flags.FatalWarnings then _p(3, 'true') end if premake.action.current() == premake.action.get("vs2017") or premake.action.current() == premake.action.get("vs2019") or premake.action.current() == premake.action.get("vs2022") then cppstandard(cfg) end exceptions(cfg) rtti(cfg) calling_convention(cfg) wchar_t_builtin(cfg) sse(cfg) floating_point(cfg) debug_info(cfg) if cfg.flags.Symbols then if cfg.kind == "StaticLib" then _p(3, '$(OutDir)%s.pdb' , path.getbasename(cfg.buildtarget.name) ) else _p(3, '$(IntDir)%s.compile.pdb' , path.getbasename(cfg.buildtarget.name) ) end end if cfg.flags.Hotpatchable then _p(3, 'true') end if cfg.flags.NoFramePointer then _p(3, 'true') end if cfg.flags.UseFullPaths then _p(3, 'true') end if cfg.flags.NoJMC then _p(3,'false' ) end compile_language(cfg) forcedinclude_files(3,cfg); if vstudio.diagformat then _p(3, '%s', vstudio.diagformat) else _p(3, 'Caret') end _p(2,'') end local function event_hooks(cfg) if #cfg.postbuildcommands> 0 then _p(2,'') _p(3,'%s',premake.esc(table.implode(cfg.postbuildcommands, "", "", "\r\n"))) _p(2,'') end if #cfg.prebuildcommands> 0 then _p(2,'') _p(3,'%s',premake.esc(table.implode(cfg.prebuildcommands, "", "", "\r\n"))) _p(2,'') end if #cfg.prelinkcommands> 0 then _p(2,'') _p(3,'%s',premake.esc(table.implode(cfg.prelinkcommands, "", "", "\r\n"))) _p(2,'') end end local function additional_options(indent,cfg) if #cfg.linkoptions > 0 then _p(indent,'%s %%(AdditionalOptions)', table.concat(premake.esc(cfg.linkoptions), " ")) end end local function link_target_machine(index,cfg) local platforms = {x32 = 'MachineX86', x64 = 'MachineX64'} if platforms[cfg.platform] then _p(index,'%s', platforms[cfg.platform]) end end local function item_def_lib(cfg) if cfg.kind == 'StaticLib' and cfg.platform ~= "Xbox360" then _p(1,'') _p(2,'$(OutDir)%s',cfg.buildtarget.name) additional_options(2,cfg) link_target_machine(2,cfg) _p(1,'') end end local function import_lib(cfg) if cfg.kind == "SharedLib" then local implibname = cfg.linktarget.fullpath _p(3,'%s',iif(cfg.flags.NoImportLib, cfg.objectsdir .. "\\" .. path.getname(implibname), implibname)) end end local function hasmasmfiles(prj) local files = vc2010.getfilegroup(prj, "MASM") return #files > 0 end local function ismanagedprj(prj, cfgname, pltname) local cfg = premake.getconfig(prj, cfgname, pltname) return cfg.flags.Managed == true end local function getcfglinks(cfg) local haswholearchive = #cfg.wholearchive > 0 local msvcnaming = premake.getnamestyle(cfg) == "windows" local iscppprj = premake.iscppproject(cfg) local isnetprj = premake.isdotnetproject(cfg) local linkobjs = {} local links = iif(haswholearchive , premake.getlinks(cfg, "all", "object") , premake.getlinks(cfg, "system", "fullpath") ) for _, link in ipairs(links) do local name = nil local directory = nil local whole = nil if type(link) == "table" then if not ismanagedprj(link.project, cfg.name, cfg.platform) then name = link.linktarget.basename directory = path.rebase(link.linktarget.directory, link.location, cfg.location) whole = table.icontains(cfg.wholearchive, link.project.name) end else name = link whole = table.icontains(cfg.wholearchive, link) end if name then if haswholearchive and msvcnaming then if iscppprj then name = name .. ".lib" elseif isnetprj then name = name .. ".dll" end end table.insert(linkobjs, {name=name, directory=directory, wholearchive=whole}) end end return linkobjs end local function vs10_masm(prj, cfg) if hasmasmfiles(prj) then _p(2, '') _p(3,'%s %%(AdditionalOptions)' , table.concat(premake.esc(table.join(cfg.buildoptions, cfg.buildoptions_asm)), " ") ) local includedirs = table.join(cfg.userincludedirs, cfg.includedirs, cfg.systemincludedirs) if #includedirs > 0 then _p(3, '%s;%%(IncludePaths)' , premake.esc(path.translate(table.concat(includedirs, ";"), '\\')) ) end local defines = table.join(cfg.defines) table.insertflat(defines, iif(premake.config.isdebugbuild(cfg), "_DEBUG", {})) table.insert(defines, iif(cfg.platform == "x64" or cfg.platform == "ARM64", "_WIN64", "_WIN32")) table.insert(defines, iif(prj.kind == "SharedLib", "_EXPORT=EXPORT", "_EXPORT=")) _p(3, '%s;%%(PreprocessorDefinitions)' , premake.esc(table.concat(defines, ";")) ) if cfg.flags.FatalWarnings then _p(3,'true') end if cfg.flags.MinimumWarnings then _p(3,'0') else _p(3,'3') end _p(2, '') end end local function additional_manifest(cfg) if(cfg.dpiawareness ~= nil) then _p(2,'') if(cfg.dpiawareness == "None") then _p(3, 'false') end if(cfg.dpiawareness == "High") then _p(3, 'true') end if(cfg.dpiawareness == "HighPerMonitor") then _p(3, 'PerMonitorHighDPIAware') end _p(2,'') end end function vc2010.link(cfg) local vs2017OrLater = premake.action.current() == premake.action.get("vs2017") or premake.action.current() == premake.action.get("vs2019") local links = getcfglinks(cfg) _p(2,'') _p(3,'%s', iif(cfg.kind == "ConsoleApp", "Console", "Windows")) if vs2017OrLater and cfg.flags.FullSymbols then _p(3,'DebugFull') else _p(3,'%s', tostring(cfg.flags.Symbols ~= nil)) end if cfg.flags.Symbols then _p(3, '$(OutDir)%s.pdb' , path.getbasename(cfg.buildtarget.name) ) end if premake.config.islinkeroptimizedbuild(cfg.flags) then if cfg.platform == "Orbis" then _p(3,'StripFuncsAndData') _p(3,'true') else _p(3,'true') _p(3,'true') end elseif cfg.platform == "Orbis" and premake.config.iseditandcontinue(cfg) then _p(3,'true') end if cfg.finalizemetasource ~= nil then _p(3,'%s', premake.esc(cfg.finalizemetasource)) end if cfg.kind ~= 'StaticLib' then vc2010.additionalDependencies(3, cfg, links) vc2010.additionalLibraryDirectories(3, cfg, links) _p(3,'$(OutDir)%s', cfg.buildtarget.name) if vc2010.config_type(cfg) == 'Application' and not cfg.flags.WinMain and not cfg.flags.Managed then if cfg.flags.Unicode then _p(3,'wmainCRTStartup') else _p(3,'mainCRTStartup') end end import_lib(cfg) local deffile = premake.findfile(cfg, ".def") if deffile then _p(3,'%s', deffile) end link_target_machine(3,cfg) additional_options(3,cfg) if cfg.flags.NoWinMD and vstudio.iswinrt() and prj.kind == "WindowedApp" then _p(3,'false' ) end end if cfg.platform == "TegraAndroid" then if cfg.androidlinker then _p(3,'%s',cfg.androidlinker) end end if cfg.flags.Hotpatchable then _p(3, 'Enabled') end if cfg.flags.GenerateMapFiles then _p(3, 'true') end _p(2,'') if #cfg.wholearchive > 0 then _p(2, '') _p(3, 'false') _p(2, '') end end function vc2010.additionalLibraryDirectories(tab, cfg, links) local dirs = cfg.libdirs for _, link in ipairs(links) do if link.directory and not table.icontains(dirs, link.directory) then table.insert(dirs, link.directory) end end _p(tab, '%s;%%(AdditionalLibraryDirectories)' , premake.esc(path.translate(table.concat(dirs, ';'), '\\')) ) end function vc2010.additionalDependencies(tab, cfg, links) if #links > 0 then local deps = "" if cfg.platform == "Orbis" then local iswhole = false for _, link in ipairs(links) do if link.wholearchive and not iswhole then deps = deps .. "--whole-archive;" iswhole = true elseif not link.wholearchive and iswhole then deps = deps .. "--no-whole-archive;" iswhole = false end deps = deps .. "-l" .. link.name .. ";" end else for _, link in ipairs(links) do if link.wholearchive then deps = deps .. "/WHOLEARCHIVE:" .. link.name .. ";" else deps = deps .. link.name .. ";" end end end if cfg.platform == "TegraAndroid" then deps = "-Wl,--start-group;" .. deps .. ";-Wl,--end-group" end _p(tab, '%s;%s' , deps , iif(cfg.platform == "Durango" , '%(XboxExtensionsDependencies)' , '%(AdditionalDependencies)' ) ) elseif cfg.platform == "Durango" then _p(tab, '%%(XboxExtensionsDependencies)') end end function ant_build(prj, cfg) if cfg.platform == "TegraAndroid" then local files = vc2010.getfilegroup(prj, "AndroidBuild") _p(2,'') if #files > 0 then _p(3,'%s',path.translate(files[1].name)) end local isdebugbuild = premake.config.isdebugbuild(cfg) _p(3,'%s',iif(isdebugbuild, 'Debug','Release')) _p(3,'%s',tostring(cfg.flags.AntBuildDebuggable ~= nil)) if #cfg.antbuildjavasourcedirs > 0 then local dirs = table.concat(cfg.antbuildjavasourcedirs,";") _p(3,'%s',dirs) end if #cfg.antbuildjardirs > 0 then local dirs = table.concat(cfg.antbuildjardirs,";") _p(3,'%s',dirs) end if #cfg.antbuildjardependencies > 0 then local dirs = table.concat(cfg.antbuildjardependencies,";") _p(3,'%s',dirs) end if #cfg.antbuildnativelibdirs > 0 then local dirs = table.concat(cfg.antbuildnativelibdirs,";") _p(3,'%s',dirs) end if #cfg.antbuildnativelibdependencies > 0 then local dirs = table.concat(cfg.antbuildnativelibdependencies,";") _p(3,'%s',dirs) end if #cfg.antbuildassetsdirs > 0 then local dirs = table.concat(cfg.antbuildassetsdirs,";") _p(3,'%s',dirs) end _p(2,'') end end local function item_definitions(prj) for _, cfginfo in ipairs(prj.solution.vstudio_configs) do local cfg = premake.getconfig(prj, cfginfo.src_buildcfg, cfginfo.src_platform) _p(1,'' ,premake.esc(cfginfo.name)) vs10_clcompile(cfg) resource_compile(cfg) item_def_lib(cfg) vc2010.link(cfg) ant_build(prj, cfg) event_hooks(cfg) vs10_masm(prj, cfg) additional_manifest(cfg) _p(1,'') end end function vc2010.getfilegroup(prj, group) local sortedfiles = prj.vc2010sortedfiles if not sortedfiles then sortedfiles = { ClCompile = {}, ClInclude = {}, MASM = {}, Object = {}, None = {}, ResourceCompile = {}, AppxManifest = {}, AndroidBuild = {}, Natvis = {}, Image = {}, DeploymentContent = {} } local foundAppxManifest = false for file in premake.project.eachfile(prj, true) do if path.issourcefilevs(file.name) then table.insert(sortedfiles.ClCompile, file) elseif path.iscppheader(file.name) then if not table.icontains(prj.removefiles, file) then table.insert(sortedfiles.ClInclude, file) end elseif path.isobjectfile(file.name) then table.insert(sortedfiles.Object, file) elseif path.isresourcefile(file.name) then table.insert(sortedfiles.ResourceCompile, file) elseif path.isimagefile(file.name) then table.insert(sortedfiles.Image, file) elseif path.isappxmanifest(file.name) then foundAppxManifest = true table.insert(sortedfiles.AppxManifest, file) elseif path.isandroidbuildfile(file.name) then table.insert(sortedfiles.AndroidBuild, file) elseif path.isnatvis(file.name) then table.insert(sortedfiles.Natvis, file) elseif path.isasmfile(file.name) then table.insert(sortedfiles.MASM, file) elseif file.flags and table.icontains(file.flags, "DeploymentContent") then table.insert(sortedfiles.DeploymentContent, file) else table.insert(sortedfiles.None, file) end end if vstudio.iswinrt() and prj.kind == "WindowedApp" and not foundAppxManifest then vstudio.needAppxManifest = true local fcfg = {} fcfg.name = prj.name .. "/Package.appxmanifest" fcfg.vpath = premake.project.getvpath(prj, fcfg.name) table.insert(sortedfiles.AppxManifest, fcfg) local logo = {} logo.name = prj.name .. "/Logo.png" logo.vpath = logo.name table.insert(sortedfiles.Image, logo) local smallLogo = {} smallLogo.name = prj.name .. "/SmallLogo.png" smallLogo.vpath = smallLogo.name table.insert(sortedfiles.Image, smallLogo) local storeLogo = {} storeLogo.name = prj.name .. "/StoreLogo.png" storeLogo.vpath = storeLogo.name table.insert(sortedfiles.Image, storeLogo) local splashScreen = {} splashScreen.name = prj.name .. "/SplashScreen.png" splashScreen.vpath = splashScreen.name table.insert(sortedfiles.Image, splashScreen) end prj.vc2010sortedfiles = sortedfiles end return sortedfiles[group] end function vc2010.files(prj) vc2010.simplefilesgroup(prj, "ClInclude") vc2010.compilerfilesgroup(prj) vc2010.simplefilesgroup(prj, "Object") vc2010.simplefilesgroup(prj, "None") vc2010.customtaskgroup(prj) vc2010.simplefilesgroup(prj, "ResourceCompile") vc2010.simplefilesgroup(prj, "AppxManifest") vc2010.simplefilesgroup(prj, "AndroidBuild") vc2010.simplefilesgroup(prj, "Natvis") vc2010.deploymentcontentgroup(prj, "Image") vc2010.deploymentcontentgroup(prj, "DeploymentContent", "None") end function vc2010.customtaskgroup(prj) local files = { } for _, custombuildtask in ipairs(prj.custombuildtask or {}) do for _, buildtask in ipairs(custombuildtask or {}) do local fcfg = { } fcfg.name = path.getrelative(prj.location,buildtask[1]) fcfg.vpath = path.trimdots(fcfg.name) table.insert(files, fcfg) end end if #files > 0 then _p(1,'') local groupedBuildTasks = {} local buildTaskNames = {} for _, custombuildtask in ipairs(prj.custombuildtask or {}) do for _, buildtask in ipairs(custombuildtask or {}) do if (groupedBuildTasks[buildtask[1]] == nil) then groupedBuildTasks[buildtask[1]] = {} table.insert(buildTaskNames, buildtask[1]) end table.insert(groupedBuildTasks[buildtask[1]], buildtask) end end for _, name in ipairs(buildTaskNames) do custombuildtask = groupedBuildTasks[name] _p(2,'', path.translate(path.getrelative(prj.location,name), "\\")) _p(3,'Text') local cmd = "" local outputs = "" for _, buildtask in ipairs(custombuildtask or {}) do for _, cmdline in ipairs(buildtask[4] or {}) do cmd = cmd .. cmdline local num = 1 for _, depdata in ipairs(buildtask[3] or {}) do cmd = string.gsub(cmd,"%$%(" .. num .."%)", string.format("%s ",path.getrelative(prj.location,depdata))) num = num + 1 end cmd = string.gsub(cmd, "%$%(<%)", string.format("%s ",path.getrelative(prj.location,buildtask[1]))) cmd = string.gsub(cmd, "%$%(@%)", string.format("%s ",path.getrelative(prj.location,buildtask[2]))) cmd = cmd .. "\r\n" end outputs = outputs .. path.getrelative(prj.location,buildtask[2]) .. ";" end _p(3,'%s',cmd) _p(3,'%s%%(Outputs)',outputs) _p(3,'Designer') _p(3,'') _p(2,'') end _p(1,'') end end function vc2010.simplefilesgroup(prj, section, subtype) local configs = prj.solution.vstudio_configs local files = vc2010.getfilegroup(prj, section) if #files > 0 then local config_mappings = {} for _, cfginfo in ipairs(configs) do local cfg = premake.getconfig(prj, cfginfo.src_buildcfg, cfginfo.src_platform) if cfg.pchheader and cfg.pchsource and not cfg.flags.NoPCH then config_mappings[cfginfo] = path.translate(cfg.pchsource, "\\") end end _p(1,'') for _, file in ipairs(files) do local prjexcluded = table.icontains(prj.excludes, file.name) local excludedcfgs = {} if not prjexcluded then for _, vsconfig in ipairs(configs) do local cfg = premake.getconfig(prj, vsconfig.src_buildcfg, vsconfig.src_platform) local fileincfg = table.icontains(cfg.files, file.name) local cfgexcluded = table.icontains(cfg.excludes, file.name) if not fileincfg or cfgexcluded then table.insert(excludedcfgs, vsconfig.name) end end end if subtype or prjexcluded or #excludedcfgs > 0 then _p(2, '<%s Include=\"%s\">', section, path.translate(file.name, "\\")) if prjexcluded then _p(3, 'true') else for _, cfgname in ipairs(excludedcfgs) do _p(3, 'true' , premake.esc(cfgname) ) end end if subtype then _p(3, '%s', subtype) end _p(2,'', section) else _p(2, '<%s Include=\"%s\" />', section, path.translate(file.name, "\\")) end end _p(1,'') end end function vc2010.deploymentcontentgroup(prj, section, filetype) if filetype == nil then filetype = section end local files = vc2010.getfilegroup(prj, section) if #files > 0 then _p(1,'') for _, file in ipairs(files) do _p(2,'<%s Include=\"%s\">', filetype, path.translate(file.name, "\\")) _p(3,'true') _p(3,'%s', path.translate(file.vpath, "\\")) _p(2,'', filetype) end _p(1,'') end end function vc2010.compilerfilesgroup(prj) local configs = prj.solution.vstudio_configs local files = vc2010.getfilegroup(prj, "ClCompile") if #files > 0 then local config_mappings = {} for _, cfginfo in ipairs(configs) do local cfg = premake.getconfig(prj, cfginfo.src_buildcfg, cfginfo.src_platform) if cfg.pchheader and cfg.pchsource and not cfg.flags.NoPCH then config_mappings[cfginfo] = path.translate(cfg.pchsource, "\\") end end _p(1,'') local existingBasenames = {}; for _, file in ipairs(files) do local filename = string.lower(path.getbasename(file.name)) local disambiguation = existingBasenames[filename] or 0; existingBasenames[filename] = disambiguation + 1 local translatedpath = path.translate(file.name, "\\") _p(2, '', translatedpath) for _, vsconfig in ipairs(configs) do local cfg = premake.getconfig(prj, vsconfig.src_buildcfg, vsconfig.src_platform) local namestyle = premake.getnamestyle(cfg) if namestyle == "TegraAndroid" or namestyle == "NX" then _p(3, '$(IntDir)%s.o', premake.esc(vsconfig.name), premake.esc(path.translate(path.trimdots(path.removeext(file.name)))) ) else if disambiguation > 0 then _p(3, '$(IntDir)%s\\', premake.esc(vsconfig.name), tostring(disambiguation)) end end end if path.iscxfile(file.name) then _p(3, 'true') _p(3, 'true') _p(3, 'NotUsing') end if vstudio.iswinrt() and string.len(file.name) > 2 and string.sub(file.name, -2) == ".c" then _p(3,'FALSE') end for _, cfginfo in ipairs(configs) do if config_mappings[cfginfo] and translatedpath == config_mappings[cfginfo] then _p(3,'Create', premake.esc(cfginfo.name)) config_mappings[cfginfo] = nil --only one source file per pch end end local nopch = table.icontains(prj.nopch, file.name) for _, vsconfig in ipairs(configs) do local cfg = premake.getconfig(prj, vsconfig.src_buildcfg, vsconfig.src_platform) if nopch or table.icontains(cfg.nopch, file.name) then _p(3,'NotUsing', premake.esc(vsconfig.name)) end end local excluded = table.icontains(prj.excludes, file.name) for _, vsconfig in ipairs(configs) do local cfg = premake.getconfig(prj, vsconfig.src_buildcfg, vsconfig.src_platform) local fileincfg = table.icontains(cfg.files, file.name) local cfgexcluded = table.icontains(cfg.excludes, file.name) if excluded or not fileincfg or cfgexcluded then _p(3, 'true' , premake.esc(vsconfig.name) ) end end if prj.flags and prj.flags.Managed then local prjforcenative = table.icontains(prj.forcenative, file.name) for _,vsconfig in ipairs(configs) do local cfg = premake.getconfig(prj, vsconfig.src_buildcfg, vsconfig.src_platform) if prjforcenative or table.icontains(cfg.forcenative, file.name) then _p(3, 'false', premake.esc(vsconfig.name)) end end end _p(2,'') end _p(1,'') end end function vc2010.masmfiles(prj) local configs = prj.solution.vstudio_configs local files = vc2010.getfilegroup(prj, "MASM") if #files > 0 then _p(1, '') for _, file in ipairs(files) do local translatedpath = path.translate(file.name, "\\") _p(2, '', translatedpath) local excluded = table.icontains(prj.excludes, file.name) for _, vsconfig in ipairs(configs) do local cfg = premake.getconfig(prj, vsconfig.src_buildcfg, vsconfig.src_platform) local fileincfg = table.icontains(cfg.files, file.name) local cfgexcluded = table.icontains(cfg.excludes, file.name) if excluded or not fileincfg or cfgexcluded then _p(3, 'true' , premake.esc(vsconfig.name) ) end end _p(2, '') end _p(1, '') end end function vc2010.header(targets) io.eol = "\r\n" _p('') local t = "" if targets then t = ' DefaultTargets="' .. targets .. '"' end _p('', t, action.vstudio.toolsVersion) end function premake.vs2010_vcxproj(prj) local usemasm = hasmasmfiles(prj) io.indent = " " vc2010.header("Build") vs2010_config(prj) vs2010_globals(prj) _p(1,'') for _, cfginfo in ipairs(prj.solution.vstudio_configs) do local cfg = premake.getconfig(prj, cfginfo.src_buildcfg, cfginfo.src_platform) vc2010.configurationPropertyGroup(cfg, cfginfo) end _p(1,'') _p(1,'') if usemasm then _p(2, '') end _p(1,'') import_props(prj) _p(1,'') vc2010.outputProperties(prj) item_definitions(prj) vc2010.files(prj) vc2010.clrReferences(prj) vc2010.projectReferences(prj) vc2010.sdkReferences(prj) vc2010.masmfiles(prj) _p(1,'') _p(1,'') if usemasm then _p(2, '') end _p(1,'') _p('') end function vc2010.clrReferences(prj) if #prj.clrreferences == 0 then return end _p(1,'') for _, ref in ipairs(prj.clrreferences) do if os.isfile(ref) then local assembly = path.getbasename(ref) _p(2,'', assembly) _p(3,'%s', path.getrelative(prj.location, ref)) _p(2,'') else _p(2,'', ref) end end _p(1,'') end function vc2010.projectReferences(prj) local deps = premake.getdependencies(prj) if #deps == 0 and #prj.vsimportreferences == 0 then return end local function compareuuid(a, b) return a.uuid < b.uuid end table.sort(deps, compareuuid) table.sort(table.join(prj.vsimportreferences), compareuuid) _p(1,'') for _, dep in ipairs(deps) do local deppath = path.getrelative(prj.location, vstudio.projectfile(dep)) _p(2,'', path.translate(deppath, "\\")) _p(3,'{%s}', dep.uuid) if vstudio.iswinrt() then _p(3,'false') end _p(2,'') end for _, ref in ipairs(prj.vsimportreferences) do local slnrelpath = path.rebase(ref, prj.location, sln.location) local iprj = premake.vstudio.getimportprj(slnrelpath, prj.solution) _p(2,'', ref) _p(3,'{%s}', iprj.uuid) _p(2,'') end _p(1,'') end function vc2010.sdkReferences(prj) local refs = prj.sdkreferences if #refs > 0 then _p(1,'') for _, ref in ipairs(refs) do _p(2,'', ref) end _p(1,'') end end function vc2010.debugdir(cfg) local isnx = (cfg.platform == "NX32" or cfg.platform == "NX64") local debuggerFlavor = iif(isnx, 'OasisNXDebugger' , iif(cfg.platform == "Orbis", 'ORBISDebugger' , iif(cfg.platform == "Durango", 'XboxOneVCppDebugger' , iif(cfg.platform == "TegraAndroid", 'AndroidDebugger' , iif(vstudio.iswinrt(), 'AppHostLocalDebugger' , 'WindowsLocalDebugger' ))))) _p(2, '%s', debuggerFlavor) if cfg.debugdir and not vstudio.iswinrt() then _p(2, '%s' , path.translate(cfg.debugdir, '\\') ) end if cfg.debugcmd then _p(2, '%s', cfg.debugcmd) end if cfg.debugargs then _p(2, '%s' , table.concat(cfg.debugargs, " ") ) end if cfg.debugenvs and #cfg.debugenvs > 0 then _p(2, '%s%s' , table.concat(cfg.debugenvs, "\n") , iif(cfg.flags.DebugEnvsInherit,'\n$(LocalDebuggerEnvironment)', '') ) if cfg.flags.DebugEnvsDontMerge then _p(2, 'false') end end if cfg.deploymode then _p(2, '%s', cfg.deploymode) end if cfg.platform == "TegraAndroid" then if cfg.androiddebugintentparams then _p(2, '%s' , table.concat(cfg.androiddebugintentparams, " ") ) end end end function premake.vs2010_vcxproj_user(prj) io.indent = " " vc2010.header() for _, cfginfo in ipairs(prj.solution.vstudio_configs) do local cfg = premake.getconfig(prj, cfginfo.src_buildcfg, cfginfo.src_platform) _p(' ', premake.esc(cfginfo.name)) vc2010.debugdir(cfg) _p(' ') end _p('') end local png1x1data = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, -- .PNG........IHDR 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x25, 0xdb, 0x56, -- .............%.V 0xca, 0x00, 0x00, 0x00, 0x03, 0x50, 0x4c, 0x54, 0x45, 0x00, 0x00, 0x00, 0xa7, 0x7a, 0x3d, 0xda, -- .....PLTE....z=. 0x00, 0x00, 0x00, 0x01, 0x74, 0x52, 0x4e, 0x53, 0x00, 0x40, 0xe6, 0xd8, 0x66, 0x00, 0x00, 0x00, -- ....tRNS.@..f... 0x0a, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0xe2, -- .IDAT..c`....... 0x21, 0xbc, 0x33, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82, -- !.3....IEND.B`. } function png1x1(obj, filename) filename = premake.project.getfilename(obj, filename) local f, err = io.open(filename, "wb") if f then for _, byte in ipairs(png1x1data) do f:write(string.char(byte)) end f:close() end end function premake.vs2010_appxmanifest(prj) io.indent = " " io.eol = "\r\n" _p('') if vstudio.storeapp == "10.0" then _p('') elseif vstudio.storeapp == "durango" then _p('') end _p(1, '') if vstudio.storeapp == "10.0" then _p(1, '') end _p(1, '') _p(2, '' .. prj.name .. '') _p(2, 'PublisherDisplayName') _p(2, '' .. prj.name .. '\\StoreLogo.png') png1x1(prj, "%%/StoreLogo.png") _p(2, '' .. prj.name .. '') _p(1,'') if vstudio.storeapp == "10.0" then _p(1, '') _p(2, '') _p(1, '') elseif vstudio.storeapp == "durango" then _p(1, '') _p(2, '6.2') _p(2, '6.2') _p(1, '') end _p(1, '') _p(2, '') _p(1, '') _p(1, '') _p(2, '') if vstudio.storeapp == "10.0" then _p(3, '') _p(4, '') png1x1(prj, "%%/SplashScreen.png") _p(3, '') elseif vstudio.storeapp == "durango" then _p(3, '') _p(5, '') png1x1(prj, "%%/SplashScreen.png") _p(3, '') _p(3, '') _p(4, '') _p(4, '') _p(4, '') _p(3, '') end _p(2, '') _p(1, '') _p('') end local vc2010 = premake.vstudio.vc2010 local project = premake.project function vc2010.filteridgroup(prj) local filters = { } local filterfound = false for file in premake.project.eachfile(prj, true) do local folders = string.explode(file.vpath, "/", true) local path = "" for i = 1, #folders - 1 do if not filterfound then filterfound = true _p(1,'') end path = path .. folders[i] if not filters[path] then filters[path] = true _p(2, '', path) _p(3, '{%s}', os.uuid(path)) _p(2, '') end path = path .. "\\" end end for _, custombuildtask in ipairs(prj.custombuildtask or {}) do for _, buildtask in ipairs(custombuildtask or {}) do local folders = string.explode(path.trimdots(path.getrelative(prj.location,buildtask[1])), "/", true) local path = "" for i = 1, #folders - 1 do if not filterfound then filterfound = true _p(1,'') end path = path .. folders[i] if not filters[path] then filters[path] = true _p(2, '', path) _p(3, '{%s}', os.uuid(path)) _p(2, '') end path = path .. "\\" end end end if filterfound then _p(1,'') end end function vc2010.filefiltergroup(prj, section, kind) local files = vc2010.getfilegroup(prj, section) or {} if kind == nill then kind = section end if (section == "CustomBuild") then for _, custombuildtask in ipairs(prj.custombuildtask or {}) do for _, buildtask in ipairs(custombuildtask or {}) do local fcfg = { } fcfg.name = path.getrelative(prj.location,buildtask[1]) fcfg.vpath = path.trimdots(fcfg.name) table.insert(files, fcfg) end end end if #files > 0 then _p(1,'') for _, file in ipairs(files) do local filter if file.name ~= file.vpath then filter = path.getdirectory(file.vpath) else filter = path.getdirectory(file.name) end if filter ~= "." then _p(2,'<%s Include=\"%s\">', kind, path.translate(file.name, "\\")) _p(3,'%s', path.translate(filter, "\\")) _p(2,'', kind) else _p(2,'<%s Include=\"%s\" />', kind, path.translate(file.name, "\\")) end end _p(1,'') end end function vc2010.generate_filters(prj) io.indent = " " vc2010.header() vc2010.filteridgroup(prj) vc2010.filefiltergroup(prj, "None") vc2010.filefiltergroup(prj, "ClInclude") vc2010.filefiltergroup(prj, "ClCompile") vc2010.filefiltergroup(prj, "Object") vc2010.filefiltergroup(prj, "ResourceCompile") vc2010.filefiltergroup(prj, "CustomBuild") vc2010.filefiltergroup(prj, "AppxManifest") vc2010.filefiltergroup(prj, "Natvis") vc2010.filefiltergroup(prj, "Image") vc2010.filefiltergroup(prj, "DeploymentContent", "None") vc2010.filefiltergroup(prj, "MASM") _p('') end local vc2010 = premake.vstudio.vc2010 local vstudio = premake.vstudio newaction { trigger = "vs2010", shortname = "Visual Studio 2010", description = "Generate Microsoft Visual Studio 2010 project files", os = "windows", valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle" }, valid_languages = { "C", "C++", "C#"}, valid_tools = { cc = { "msc" }, dotnet = { "msnet" }, }, onsolution = function(sln) premake.generate(sln, "%%.sln", vstudio.sln2005.generate) end, onproject = function(prj) if premake.isdotnetproject(prj) then premake.generate(prj, "%%.csproj", vstudio.cs2005.generate) premake.generate(prj, "%%.csproj.user", vstudio.cs2005.generate_user) else premake.generate(prj, "%%.vcxproj", premake.vs2010_vcxproj) premake.generate(prj, "%%.vcxproj.user", premake.vs2010_vcxproj_user) premake.generate(prj, "%%.vcxproj.filters", vstudio.vc2010.generate_filters) end end, oncleansolution = premake.vstudio.cleansolution, oncleanproject = premake.vstudio.cleanproject, oncleantarget = premake.vstudio.cleantarget, vstudio = { productVersion = "8.0.30703", solutionVersion = "11", targetFramework = "4.0", toolsVersion = "4.0", supports64bitEditContinue = false, intDirAbsolute = false, } } premake.vstudio.vc2012 = {} local vc2012 = premake.vstudio.vc2012 local vstudio = premake.vstudio newaction { trigger = "vs2012", shortname = "Visual Studio 2012", description = "Generate Microsoft Visual Studio 2012 project files", os = "windows", valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle" }, valid_languages = { "C", "C++", "C#"}, valid_tools = { cc = { "msc" }, dotnet = { "msnet" }, }, onsolution = function(sln) premake.generate(sln, "%%.sln", vstudio.sln2005.generate) end, onproject = function(prj) if premake.isdotnetproject(prj) then premake.generate(prj, "%%.csproj", vstudio.cs2005.generate) premake.generate(prj, "%%.csproj.user", vstudio.cs2005.generate_user) else premake.generate(prj, "%%.vcxproj", premake.vs2010_vcxproj) premake.generate(prj, "%%.vcxproj.user", premake.vs2010_vcxproj_user) premake.generate(prj, "%%.vcxproj.filters", vstudio.vc2010.generate_filters) end end, oncleansolution = premake.vstudio.cleansolution, oncleanproject = premake.vstudio.cleanproject, oncleantarget = premake.vstudio.cleantarget, vstudio = { solutionVersion = "12", targetFramework = "4.5", toolsVersion = "4.0", supports64bitEditContinue = false, intDirAbsolute = false, } } premake.vstudio.vc2013 = {} local vc2013 = premake.vstudio.vc2013 local vstudio = premake.vstudio newaction { trigger = "vs2013", shortname = "Visual Studio 2013", description = "Generate Microsoft Visual Studio 2013 project files", os = "windows", valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle" }, valid_languages = { "C", "C++", "C#"}, valid_tools = { cc = { "msc" }, dotnet = { "msnet" }, }, onsolution = function(sln) premake.generate(sln, "%%.sln", vstudio.sln2005.generate) end, onproject = function(prj) if premake.isdotnetproject(prj) then premake.generate(prj, "%%.csproj", vstudio.cs2005.generate) premake.generate(prj, "%%.csproj.user", vstudio.cs2005.generate_user) else premake.vstudio.needAppxManifest = false premake.generate(prj, "%%.vcxproj", premake.vs2010_vcxproj) premake.generate(prj, "%%.vcxproj.user", premake.vs2010_vcxproj_user) premake.generate(prj, "%%.vcxproj.filters", vstudio.vc2010.generate_filters) if premake.vstudio.needAppxManifest then premake.generate(prj, "%%/Package.appxmanifest", premake.vs2010_appxmanifest) end end end, oncleansolution = premake.vstudio.cleansolution, oncleanproject = premake.vstudio.cleanproject, oncleantarget = premake.vstudio.cleantarget, vstudio = { solutionVersion = "12", targetFramework = "4.5", toolsVersion = "12.0", supports64bitEditContinue = false, intDirAbsolute = false, } } premake.vstudio.vc2015 = {} local vc2015 = premake.vstudio.vc2015 local vstudio = premake.vstudio newaction { trigger = "vs2015", shortname = "Visual Studio 2015", description = "Generate Microsoft Visual Studio 2015 project files", os = "windows", valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle" }, valid_languages = { "C", "C++", "C#" }, valid_tools = { cc = { "msc" }, dotnet = { "msnet" }, }, onsolution = function(sln) premake.generate(sln, "%%.sln", vstudio.sln2005.generate) end, onproject = function(prj) if premake.isdotnetproject(prj) then premake.generate(prj, "%%.csproj", vstudio.cs2005.generate) premake.generate(prj, "%%.csproj.user", vstudio.cs2005.generate_user) else premake.vstudio.needAppxManifest = false premake.generate(prj, "%%.vcxproj", premake.vs2010_vcxproj) premake.generate(prj, "%%.vcxproj.user", premake.vs2010_vcxproj_user) premake.generate(prj, "%%.vcxproj.filters", vstudio.vc2010.generate_filters) if premake.vstudio.needAppxManifest then premake.generate(prj, "%%/Package.appxmanifest", premake.vs2010_appxmanifest) end end end, oncleansolution = premake.vstudio.cleansolution, oncleanproject = premake.vstudio.cleanproject, oncleantarget = premake.vstudio.cleantarget, vstudio = { solutionVersion = "12", targetFramework = "4.5", toolsVersion = "14.0", windowsTargetPlatformVersion = "8.1", supports64bitEditContinue = true, intDirAbsolute = false, } } premake.vstudio.vc2017 = {} local vc2017 = premake.vstudio.vc2017 local vstudio = premake.vstudio newaction { trigger = "vs2017", shortname = "Visual Studio 2017", description = "Generate Microsoft Visual Studio 2017 project files", os = "windows", valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle" }, valid_languages = { "C", "C++", "C#" }, valid_tools = { cc = { "msc" }, dotnet = { "msnet" }, }, onsolution = function(sln) premake.generate(sln, "%%.sln", vstudio.sln2005.generate) end, onproject = function(prj) if premake.isdotnetproject(prj) then premake.generate(prj, "%%.csproj", vstudio.cs2005.generate) premake.generate(prj, "%%.csproj.user", vstudio.cs2005.generate_user) else premake.vstudio.needAppxManifest = false premake.generate(prj, "%%.vcxproj", premake.vs2010_vcxproj) premake.generate(prj, "%%.vcxproj.user", premake.vs2010_vcxproj_user) premake.generate(prj, "%%.vcxproj.filters", vstudio.vc2010.generate_filters) if premake.vstudio.needAppxManifest then premake.generate(prj, "%%/Package.appxmanifest", premake.vs2010_appxmanifest) end end end, oncleansolution = premake.vstudio.cleansolution, oncleanproject = premake.vstudio.cleanproject, oncleantarget = premake.vstudio.cleantarget, vstudio = { solutionVersion = "12", targetFramework = "4.5.2", toolsVersion = "15.0", windowsTargetPlatformVersion = "8.1", supports64bitEditContinue = true, intDirAbsolute = false, } } premake.vstudio.vc2019 = {} local vc2019 = premake.vstudio.vc2019 local vstudio = premake.vstudio newaction { trigger = "vs2019", shortname = "Visual Studio 2019", description = "Generate Microsoft Visual Studio 2019 project files", os = "windows", valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle" }, valid_languages = { "C", "C++", "C#" }, valid_tools = { cc = { "msc" }, dotnet = { "msnet" }, }, onsolution = function(sln) premake.generate(sln, "%%.sln", vstudio.sln2005.generate) end, onproject = function(prj) if premake.isdotnetproject(prj) then premake.generate(prj, "%%.csproj", vstudio.cs2005.generate) premake.generate(prj, "%%.csproj.user", vstudio.cs2005.generate_user) else premake.vstudio.needAppxManifest = false premake.generate(prj, "%%.vcxproj", premake.vs2010_vcxproj) premake.generate(prj, "%%.vcxproj.user", premake.vs2010_vcxproj_user) premake.generate(prj, "%%.vcxproj.filters", vstudio.vc2010.generate_filters) if premake.vstudio.needAppxManifest then premake.generate(prj, "%%/Package.appxmanifest", premake.vs2010_appxmanifest) end end end, oncleansolution = premake.vstudio.cleansolution, oncleanproject = premake.vstudio.cleanproject, oncleantarget = premake.vstudio.cleantarget, vstudio = { solutionVersion = "12", targetFramework = "4.7.2", toolsVersion = "16.0", windowsTargetPlatformVersion = "10.0", supports64bitEditContinue = true, intDirAbsolute = false, } } premake.vstudio.vc2022 = {} local vc2022 = premake.vstudio.vc2022 local vstudio = premake.vstudio newaction { trigger = "vs2022", shortname = "Visual Studio 2022", description = "Generate Microsoft Visual Studio 2022 project files", os = "windows", valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle" }, valid_languages = { "C", "C++", "C#" }, valid_tools = { cc = { "msc" }, dotnet = { "msnet" }, }, onsolution = function(sln) premake.generate(sln, "%%.sln", vstudio.sln2005.generate) end, onproject = function(prj) if premake.isdotnetproject(prj) then premake.generate(prj, "%%.csproj", vstudio.cs2005.generate) premake.generate(prj, "%%.csproj.user", vstudio.cs2005.generate_user) else premake.vstudio.needAppxManifest = false premake.generate(prj, "%%.vcxproj", premake.vs2010_vcxproj) premake.generate(prj, "%%.vcxproj.user", premake.vs2010_vcxproj_user) premake.generate(prj, "%%.vcxproj.filters", vstudio.vc2010.generate_filters) if premake.vstudio.needAppxManifest then premake.generate(prj, "%%/Package.appxmanifest", premake.vs2010_appxmanifest) end end end, oncleansolution = premake.vstudio.cleansolution, oncleanproject = premake.vstudio.cleanproject, oncleantarget = premake.vstudio.cleantarget, vstudio = { solutionVersion = "12", targetFramework = "4.7.2", toolsVersion = "16.0", windowsTargetPlatformVersion = "10.0", supports64bitEditContinue = true, intDirAbsolute = false, } } premake.xcode = { } function premake.xcode.checkproject(prj) local last for cfg in premake.eachconfig(prj) do if last and last ~= cfg.kind then error("Project '" .. prj.name .. "' uses more than one target kind; not supported by Xcode", 0) end last = cfg.kind end end premake.xcode.toolset = "macosx" premake.xcode.parameters = { } local xcode = premake.xcode local tree = premake.tree function xcode.getbuildcategory(node) local categories = { [".a"] = "Frameworks", [".h"] = "Headers", [".hh"] = "Headers", [".hpp"] = "Headers", [".hxx"] = "Headers", [".inl"] = "Headers", [".c"] = "Sources", [".cc"] = "Sources", [".cpp"] = "Sources", [".cxx"] = "Sources", [".c++"] = "Sources", [".dylib"] = "Frameworks", [".bundle"] = "Frameworks", [".framework"] = "Frameworks", [".tbd"] = "Frameworks", [".m"] = "Sources", [".mm"] = "Sources", [".S"] = "Sources", [".strings"] = "Resources", [".nib"] = "Resources", [".xib"] = "Resources", [".icns"] = "Resources", [".bmp"] = "Resources", [".wav"] = "Resources", [".xcassets"] = "Resources", [".xcdatamodeld"] = "Sources", [".swift"] = "Sources", } return categories[path.getextension(node.name)] or categories[string.lower(path.getextension(node.name))] end function xcode.getconfigname(cfg) local name = cfg.name if #cfg.project.solution.xcode.platforms > 1 then name = name .. " " .. premake.action.current().valid_platforms[cfg.platform] end return name end function xcode.getfiletype(node) local types = { [".c"] = "sourcecode.c.c", [".cc"] = "sourcecode.cpp.cpp", [".cpp"] = "sourcecode.cpp.cpp", [".css"] = "text.css", [".cxx"] = "sourcecode.cpp.cpp", [".c++"] = "sourcecode.cpp.cpp", [".entitlements"] = "text.xml", [".bundle"] = "wrapper.cfbundle", [".framework"] = "wrapper.framework", [".tbd"] = "sourcecode.text-based-dylib-definition", [".gif"] = "image.gif", [".h"] = "sourcecode.c.h", [".hh"] = "sourcecode.cpp.h", [".hpp"] = "sourcecode.cpp.h", [".hxx"] = "sourcecode.cpp.h", [".inl"] = "sourcecode.cpp.h", [".html"] = "text.html", [".lua"] = "sourcecode.lua", [".m"] = "sourcecode.c.objc", [".mm"] = "sourcecode.cpp.objcpp", [".S"] = "sourcecode.asm", [".nib"] = "wrapper.nib", [".pch"] = "sourcecode.c.h", [".plist"] = "text.plist.xml", [".strings"] = "text.plist.strings", [".xib"] = "file.xib", [".icns"] = "image.icns", [".bmp"] = "image.bmp", [".wav"] = "audio.wav", [".xcassets"] = "folder.assetcatalog", [".xcdatamodeld"] = "wrapper.xcdatamodeld", [".swift"] = "sourcecode.swift", } return types[path.getextension(node.path)] or (types[string.lower(path.getextension(node.path))] or "text") end function xcode.getfiletypeForced(node) local types = { [".c"] = "sourcecode.cpp.cpp", [".cc"] = "sourcecode.cpp.cpp", [".cpp"] = "sourcecode.cpp.cpp", [".css"] = "text.css", [".cxx"] = "sourcecode.cpp.cpp", [".c++"] = "sourcecode.cpp.cpp", [".entitlements"] = "text.xml", [".bundle"] = "wrapper.cfbundle", [".framework"] = "wrapper.framework", [".tbd"] = "wrapper.framework", [".gif"] = "image.gif", [".h"] = "sourcecode.cpp.h", [".hh"] = "sourcecode.cpp.h", [".hpp"] = "sourcecode.cpp.h", [".hxx"] = "sourcecode.cpp.h", [".inl"] = "sourcecode.cpp.h", [".html"] = "text.html", [".lua"] = "sourcecode.lua", [".m"] = "sourcecode.cpp.objcpp", [".mm"] = "sourcecode.cpp.objcpp", [".nib"] = "wrapper.nib", [".pch"] = "sourcecode.cpp.h", [".plist"] = "text.plist.xml", [".strings"] = "text.plist.strings", [".xib"] = "file.xib", [".icns"] = "image.icns", [".bmp"] = "image.bmp", [".wav"] = "audio.wav", [".xcassets"] = "folder.assetcatalog", [".xcdatamodeld"] = "wrapper.xcdatamodeld", [".swift"] = "sourcecode.swift", } return types[path.getextension(node.path)] or (types[string.lower(path.getextension(node.path))] or "text") end function xcode.getproducttype(node) local types = { ConsoleApp = "com.apple.product-type.tool", WindowedApp = node.cfg.options.SkipBundling and "com.apple.product-type.tool" or "com.apple.product-type.application", StaticLib = "com.apple.product-type.library.static", SharedLib = "com.apple.product-type.library.dynamic", Bundle = node.cfg.options.SkipBundling and "com.apple.product-type.tool" or "com.apple.product-type.bundle", } return types[node.cfg.kind] end function xcode.gettargettype(node) local types = { ConsoleApp = "\"compiled.mach-o.executable\"", WindowedApp = node.cfg.options.SkipBundling and "\"compiled.mach-o.executable\"" or "wrapper.application", StaticLib = "archive.ar", SharedLib = "\"compiled.mach-o.dylib\"", Bundle = node.cfg.options.SkipBundling and "\"compiled.mach-o.bundle\"" or "wrapper.cfbundle", } return types[node.cfg.kind] end function xcode.getxcodeprojname(prj) local fname = premake.project.getfilename(prj, "%%.xcodeproj") return fname end function xcode.isframework(fname) return (path.getextension(fname) == ".framework" or path.getextension(fname) == ".tbd") end function xcode.uuid(param) return os.uuid(param):upper():gsub('-',''):sub(0,24) end function xcode.newid(node, usage) local base = '' local prj = node.project if prj == nil then local parent = node.parent while parent ~= nil do if parent.project ~= nil then prj = parent.project break end parent = parent.parent end end if prj ~= nil then prj.uuidcounter = (prj.uuidcounter or 0) + 1 base = base .. prj.name .. "$" .. prj.uuidcounter .. "$" end base = base .. "$" .. (node.path or node.name or "") base = base .. "$" .. (usage or "") return xcode.uuid(base) end function xcode.getscriptphaselabel(cmd, count, cfg) return string.format("\"Script Phase %s [%s] (%s)\"", count, cmd:match("(%w+)(.+)"), iif(cfg, xcode.getconfigname(cfg), "all")) end function xcode.getcopyphaselabel(type, count, target) return string.format("\"Copy %s %s [%s]\"", type, count, target) end function xcode.preparesolution(sln) sln.xcode = { } sln.xcode.platforms = premake.filterplatforms(sln, premake.action.current().valid_platforms, "Universal") for prj in premake.solution.eachproject(sln) do local cfg = premake.getconfig(prj, prj.configurations[1], sln.xcode.platforms[1]) local node = premake.tree.new(path.getname(cfg.buildtarget.bundlepath)) node.cfg = cfg node.id = premake.xcode.newid(node, "product") node.targetid = premake.xcode.newid(node, "target") prj.xcode = {} prj.xcode.projectnode = node end end function xcode.printlist(list, tag, sort) if #list > 0 then if sort ~= nil and sort == true then table.sort(list) end _p(4,'%s = (', tag) for _, item in ipairs(list) do local escaped_item = item:gsub("\"", "\\\\\\\""):gsub("'", "\\\\'") _p(5, '"%s",', escaped_item) end _p(4,');') end end function xcode.quotestr(str) if str:match("[^a-zA-Z0-9$._/]") == nil then return str end return "\"" .. str:gsub("[\"\\\"]", "\\%0") .. "\"" end function xcode.Header(tr, objversion) _p('// !$*UTF8*$!') _p('{') _p(1,'archiveVersion = 1;') _p(1,'classes = {') _p(1,'};') _p(1,'objectVersion = %d;', objversion) _p(1,'objects = {') _p('') end function xcode.PBXBuildFile(tr) local function gatherCopyFiles(which) local copyfiles = {} local targets = tr.project[which] if #targets > 0 then for _, t in ipairs(targets) do for __, tt in ipairs(t) do table.insertflat(copyfiles, tt[2]) end end end return table.translate(copyfiles, path.getname) end local function gatherCopyFrameworks(which) local copyfiles = {} local targets = tr.project[which] if #targets > 0 then table.insertflat(copyfiles, targets) end return table.translate(copyfiles, path.getname) end local copyfiles = table.flatten({ gatherCopyFiles('xcodecopyresources'), gatherCopyFrameworks('xcodecopyframeworks') }) _p('/* Begin PBXBuildFile section */') tree.traverse(tr, { onnode = function(node) if node.buildid then _p(2,'%s /* %s in %s */ = {isa = PBXBuildFile; fileRef = %s /* %s */; };', node.buildid, node.name, xcode.getbuildcategory(node), node.id, node.name) end if table.icontains(copyfiles, node.name) then _p(2,'%s /* %s in %s */ = {isa = PBXBuildFile; fileRef = %s /* %s */; %s };', xcode.uuid(node.name .. 'in CopyFiles'), node.name, 'CopyFiles', node.id, node.name, iif(xcode.isframework(node.name), "settings = {ATTRIBUTES = (CodeSignOnCopy, ); };", "") ) end end }) _p('/* End PBXBuildFile section */') _p('') end function xcode.PBXContainerItemProxy(tr) if #tr.projects.children > 0 then _p('/* Begin PBXContainerItemProxy section */') for _, node in ipairs(tr.projects.children) do _p(2,'%s /* PBXContainerItemProxy */ = {', node.productproxyid) _p(3,'isa = PBXContainerItemProxy;') _p(3,'containerPortal = %s /* %s */;', node.id, path.getname(node.path)) _p(3,'proxyType = 2;') _p(3,'remoteGlobalIDString = %s;', node.project.xcode.projectnode.id) _p(3,'remoteInfo = "%s";', node.project.xcode.projectnode.name) _p(2,'};') _p(2,'%s /* PBXContainerItemProxy */ = {', node.targetproxyid) _p(3,'isa = PBXContainerItemProxy;') _p(3,'containerPortal = %s /* %s */;', node.id, path.getname(node.path)) _p(3,'proxyType = 1;') _p(3,'remoteGlobalIDString = %s;', node.project.xcode.projectnode.targetid) _p(3,'remoteInfo = "%s";', node.project.xcode.projectnode.name) _p(2,'};') end _p('/* End PBXContainerItemProxy section */') _p('') end end function xcode.PBXFileReference(tr,prj) _p('/* Begin PBXFileReference section */') tree.traverse(tr, { onleaf = function(node) if not node.path then return end if node.kind == "product" then _p(2,'%s /* %s */ = {isa = PBXFileReference; explicitFileType = %s; includeInIndex = 0; name = "%s"; path = "%s"; sourceTree = BUILT_PRODUCTS_DIR; };', node.id, node.name, xcode.gettargettype(node), node.name, path.getname(node.cfg.buildtarget.bundlepath)) elseif node.parent.parent == tr.projects then local relpath = path.getrelative(tr.project.location, node.parent.project.location) _p(2,'%s /* %s */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "%s"; path = "%s"; sourceTree = SOURCE_ROOT; };', node.parent.id, node.parent.name, node.parent.name, path.join(relpath, node.parent.name)) else local pth, src if xcode.isframework(node.path) then local nodePath = node.path local _, matchEnd, variable = string.find(nodePath, "^%$%((.+)%)/") if variable then nodePath = string.sub(nodePath, matchEnd + 1) end if string.find(nodePath,'/') then if string.find(nodePath,'^%.')then nodePath = path.getabsolute(path.join(tr.project.location, nodePath)) end pth = nodePath elseif path.getextension(nodePath)=='.tbd' then pth = "/usr/lib/" .. nodePath else pth = "/System/Library/Frameworks/" .. nodePath end if variable then src = variable if string.find(pth, '^/') then pth = string.sub(pth, 2) end else src = "" end else src = "" if node.location then pth = node.location elseif node.parent.isvpath then pth = node.cfg.name else pth = tree.getlocalpath(node) end end if (not prj.options.ForceCPP) then _p(2,'%s /* %s */ = {isa = PBXFileReference; lastKnownFileType = %s; name = "%s"; path = "%s"; sourceTree = "%s"; };', node.id, node.name, xcode.getfiletype(node), node.name, pth, src) else _p(2,'%s /* %s */ = {isa = PBXFileReference; explicitFileType = %s; name = "%s"; path = "%s"; sourceTree = "%s"; };', node.id, node.name, xcode.getfiletypeForced(node), node.name, pth, src) end end end }) _p('/* End PBXFileReference section */') _p('') end function xcode.PBXFrameworksBuildPhase(tr) _p('/* Begin PBXFrameworksBuildPhase section */') _p(2,'%s /* Frameworks */ = {', tr.products.children[1].fxstageid) _p(3,'isa = PBXFrameworksBuildPhase;') _p(3,'buildActionMask = 2147483647;') _p(3,'files = (') tree.traverse(tr.frameworks, { onleaf = function(node) _p(4,'%s /* %s in Frameworks */,', node.buildid, node.name) end }) tree.traverse(tr.projects, { onleaf = function(node) _p(4,'%s /* %s in Frameworks */,', node.buildid, node.name) end }) _p(3,');') _p(3,'runOnlyForDeploymentPostprocessing = 0;') _p(2,'};') _p('/* End PBXFrameworksBuildPhase section */') _p('') end function xcode.PBXGroup(tr) _p('/* Begin PBXGroup section */') tree.traverse(tr, { onnode = function(node) if (node.path and #node.children == 0) or node.kind == "vgroup" then return end if node.parent == tr.projects then _p(2,'%s /* Products */ = {', node.productgroupid) else _p(2,'%s /* %s */ = {', node.id, node.name) end _p(3,'isa = PBXGroup;') _p(3,'children = (') for _, childnode in ipairs(node.children) do _p(4,'%s /* %s */,', childnode.id, childnode.name) end _p(3,');') if node.parent == tr.projects then _p(3,'name = Products;') else _p(3,'name = "%s";', node.name) if node.location then _p(3,'path = "%s";', node.location) elseif node.path and not node.isvpath then local p = node.path if node.parent.path then p = path.getrelative(node.parent.path, node.path) end _p(3,'path = "%s";', p) end end _p(3,'sourceTree = "";') _p(2,'};') end }, true) _p('/* End PBXGroup section */') _p('') end function xcode.PBXNativeTarget(tr) _p('/* Begin PBXNativeTarget section */') for _, node in ipairs(tr.products.children) do local name = tr.project.name local function hasBuildCommands(which) if #tr.project[which] > 0 then return true end for _, cfg in ipairs(tr.configs) do if #cfg[which] > 0 then return true end end end local function dobuildblock(id, label, which, action) if hasBuildCommands(which) then local commandcount = 0 for _, cfg in ipairs(tr.configs) do commandcount = commandcount + #cfg[which] end if commandcount > 0 then action(id, label) end end end local function doscriptphases(which, action) local i = 0 for _, cfg in ipairs(tr.configs) do local cfgcmds = cfg[which] if cfgcmds ~= nil then for __, scripts in ipairs(cfgcmds) do for ___, script in ipairs(scripts) do local cmd = script[1] local label = xcode.getscriptphaselabel(cmd, i, cfg) local id = xcode.uuid(label) action(id, label) i = i + 1 end end end end end local function docopyresources(which, action) if hasBuildCommands(which) then local targets = tr.project[which] if #targets > 0 then local i = 0 for _, t in ipairs(targets) do for __, tt in ipairs(t) do local label = xcode.getcopyphaselabel('Resources', i, tt[1]) local id = xcode.uuid(label) action(id, label) i = i + 1 end end end end end local function docopyframeworks(which, action) if hasBuildCommands(which) then local targets = tr.project[which] if #targets > 0 then local label = "Copy Frameworks" local id = xcode.uuid(label) action(id, label) end end end local function _p_label(id, label) _p(4, '%s /* %s */,', id, label) end _p(2,'%s /* %s */ = {', node.targetid, name) _p(3,'isa = PBXNativeTarget;') _p(3,'buildConfigurationList = %s /* Build configuration list for PBXNativeTarget "%s" */;', node.cfgsection, name) _p(3,'buildPhases = (') dobuildblock('9607AE1010C857E500CD1376', 'Prebuild', 'prebuildcommands', _p_label) _p(4,'%s /* Resources */,', node.resstageid) _p(4,'%s /* Sources */,', node.sourcesid) dobuildblock('9607AE3510C85E7E00CD1376', 'Prelink', 'prelinkcommands', _p_label) _p(4,'%s /* Frameworks */,', node.fxstageid) dobuildblock('9607AE3710C85E8F00CD1376', 'Postbuild', 'postbuildcommands', _p_label) doscriptphases("xcodescriptphases", _p_label) docopyresources("xcodecopyresources", _p_label) if tr.project.kind == "WindowedApp" then docopyframeworks("xcodecopyframeworks", _p_label) end _p(3,');') _p(3,'buildRules = (') _p(3,');') _p(3,'dependencies = (') for _, node in ipairs(tr.projects.children) do _p(4,'%s /* PBXTargetDependency */,', node.targetdependid) end _p(3,');') _p(3,'name = "%s";', name) local p if node.cfg.kind == "ConsoleApp" then p = "$(HOME)/bin" elseif node.cfg.kind == "WindowedApp" then p = "$(HOME)/Applications" end if p then _p(3,'productInstallPath = "%s";', p) end _p(3,'productName = "%s";', name) _p(3,'productReference = %s /* %s */;', node.id, node.name) _p(3,'productType = "%s";', xcode.getproducttype(node)) _p(2,'};') end _p('/* End PBXNativeTarget section */') _p('') end function xcode.PBXProject(tr, compatVersion) _p('/* Begin PBXProject section */') _p(2,'__RootObject_ /* Project object */ = {') _p(3,'isa = PBXProject;') _p(3,'buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "%s" */;', tr.name) _p(3,'compatibilityVersion = "Xcode %s";', compatVersion) _p(3,'hasScannedForEncodings = 1;') _p(3,'mainGroup = %s /* %s */;', tr.id, tr.name) _p(3,'projectDirPath = "";') if #tr.projects.children > 0 then _p(3,'projectReferences = (') for _, node in ipairs(tr.projects.children) do _p(4,'{') _p(5,'ProductGroup = %s /* Products */;', node.productgroupid) _p(5,'ProjectRef = %s /* %s */;', node.id, path.getname(node.path)) _p(4,'},') end _p(3,');') end _p(3,'projectRoot = "";') _p(3,'targets = (') for _, node in ipairs(tr.products.children) do _p(4,'%s /* %s */,', node.targetid, node.name) end _p(3,');') _p(2,'};') _p('/* End PBXProject section */') _p('') end function xcode.PBXReferenceProxy(tr) if #tr.projects.children > 0 then _p('/* Begin PBXReferenceProxy section */') tree.traverse(tr.projects, { onleaf = function(node) _p(2,'%s /* %s */ = {', node.id, node.name) _p(3,'isa = PBXReferenceProxy;') _p(3,'fileType = %s;', xcode.gettargettype(node)) _p(3,'path = "%s";', node.path) _p(3,'remoteRef = %s /* PBXContainerItemProxy */;', node.parent.productproxyid) _p(3,'sourceTree = BUILT_PRODUCTS_DIR;') _p(2,'};') end }) _p('/* End PBXReferenceProxy section */') _p('') end end function xcode.PBXResourcesBuildPhase(tr) _p('/* Begin PBXResourcesBuildPhase section */') for _, target in ipairs(tr.products.children) do _p(2,'%s /* Resources */ = {', target.resstageid) _p(3,'isa = PBXResourcesBuildPhase;') _p(3,'buildActionMask = 2147483647;') _p(3,'files = (') tree.traverse(tr, { onnode = function(node) if xcode.getbuildcategory(node) == "Resources" then _p(4,'%s /* %s in Resources */,', node.buildid, node.name) end end }) _p(3,');') _p(3,'runOnlyForDeploymentPostprocessing = 0;') _p(2,'};') end _p('/* End PBXResourcesBuildPhase section */') _p('') end function xcode.PBXShellScriptBuildPhase(tr) local wrapperWritten = false local function doblock(id, name, commands, files) if commands ~= nil then commands = table.flatten(commands) end if #commands > 0 then if not wrapperWritten then _p('/* Begin PBXShellScriptBuildPhase section */') wrapperWritten = true end _p(2,'%s /* %s */ = {', id, name) _p(3,'isa = PBXShellScriptBuildPhase;') _p(3,'buildActionMask = 2147483647;') _p(3,'files = (') _p(3,');') _p(3,'inputPaths = ('); if files ~= nil then files = table.flatten(files) if #files > 0 then for _, file in ipairs(files) do _p(4, '"%s",', file) end end end _p(3,');'); _p(3,'name = %s;', name); _p(3,'outputPaths = ('); _p(3,');'); _p(3,'runOnlyForDeploymentPostprocessing = 0;'); _p(3,'shellPath = /bin/sh;'); _p(3,'shellScript = "%s";', table.concat(commands, "\\n"):gsub('"', '\\"')) _p(2,'};') end end local function wrapcommands(cmds, cfg) local commands = {} if #cmds > 0 then table.insert(commands, 'if [ "${CONFIGURATION}" = "' .. xcode.getconfigname(cfg) .. '" ]; then') for i = 1, #cmds do local cmd = cmds[i] cmd = cmd:gsub('\\','\\\\') table.insert(commands, cmd) end table.insert(commands, 'fi') end return commands end local function dobuildblock(id, name, which) local commands = {} for _, cfg in ipairs(tr.configs) do local cfgcmds = wrapcommands(cfg[which], cfg) if #cfgcmds > 0 then for i, cmd in ipairs(cfgcmds) do table.insert(commands, cmd) end end end doblock(id, name, commands) end local function doscriptphases(which) local i = 0 for _, cfg in ipairs(tr.configs) do local cfgcmds = cfg[which] if cfgcmds ~= nil then for __, scripts in ipairs(cfgcmds) do for ___, script in ipairs(scripts) do local cmd = script[1] local files = script[2] local label = xcode.getscriptphaselabel(cmd, i, cfg) local id = xcode.uuid(label) doblock(id, label, wrapcommands({cmd}, cfg), files) i = i + 1 end end end end end dobuildblock("9607AE1010C857E500CD1376", "Prebuild", "prebuildcommands") dobuildblock("9607AE3510C85E7E00CD1376", "Prelink", "prelinkcommands") dobuildblock("9607AE3710C85E8F00CD1376", "Postbuild", "postbuildcommands") doscriptphases("xcodescriptphases") if wrapperWritten then _p('/* End PBXShellScriptBuildPhase section */') end end function xcode.PBXSourcesBuildPhase(tr,prj) _p('/* Begin PBXSourcesBuildPhase section */') for _, target in ipairs(tr.products.children) do _p(2,'%s /* Sources */ = {', target.sourcesid) _p(3,'isa = PBXSourcesBuildPhase;') _p(3,'buildActionMask = 2147483647;') _p(3,'files = (') tree.traverse(tr, { onleaf = function(node) if xcode.getbuildcategory(node) == "Sources" then if not table.icontains(prj.excludes, node.cfg.name) then -- if not excluded _p(4,'%s /* %s in Sources */,', node.buildid, node.name) end end end }) _p(3,');') _p(3,'runOnlyForDeploymentPostprocessing = 0;') _p(2,'};') end _p('/* End PBXSourcesBuildPhase section */') _p('') end function xcode.PBXCopyFilesBuildPhase(tr) local wrapperWritten = false local function doblock(id, name, folderSpec, path, files) if #files > 0 then if not wrapperWritten then _p('/* Begin PBXCopyFilesBuildPhase section */') wrapperWritten = true end _p(2,'%s /* %s */ = {', id, name) _p(3,'isa = PBXCopyFilesBuildPhase;') _p(3,'buildActionMask = 2147483647;') _p(3,'dstPath = \"%s\";', path) _p(3,'dstSubfolderSpec = \"%s\";', folderSpec) _p(3,'files = (') tree.traverse(tr, { onleaf = function(node) if table.icontains(files, node.name) then _p(4,'%s /* %s in %s */,', xcode.uuid(node.name .. 'in CopyFiles'), node.name, 'CopyFiles') end end }) _p(3,');') _p(3,'runOnlyForDeploymentPostprocessing = 0;'); _p(2,'};') end end local function docopyresources(which) local targets = tr.project[which] if #targets > 0 then local i = 0 for _, t in ipairs(targets) do for __, tt in ipairs(t) do local label = xcode.getcopyphaselabel('Resources', i, tt[1]) local id = xcode.uuid(label) local files = table.translate(table.flatten(tt[2]), path.getname) doblock(id, label, 7, tt[1], files) i = i + 1 end end end end local function docopyframeworks(which) local targets = tr.project[which] if #targets > 0 then local label = "Copy Frameworks" local id = xcode.uuid(label) local files = table.translate(table.flatten(targets), path.getname) doblock(id, label, 10, "", files) end end docopyresources("xcodecopyresources") if tr.project.kind == "WindowedApp" then docopyframeworks("xcodecopyframeworks") end if wrapperWritten then _p('/* End PBXCopyFilesBuildPhase section */') end end function xcode.PBXVariantGroup(tr) _p('/* Begin PBXVariantGroup section */') tree.traverse(tr, { onbranch = function(node) if node.kind == "vgroup" then _p(2,'%s /* %s */ = {', node.id, node.name) _p(3,'isa = PBXVariantGroup;') _p(3,'children = (') for _, lang in ipairs(node.children) do _p(4,'%s /* %s */,', lang.id, lang.name) end _p(3,');') _p(3,'name = %s;', node.name) _p(3,'sourceTree = "";') _p(2,'};') end end }) _p('/* End PBXVariantGroup section */') _p('') end function xcode.PBXTargetDependency(tr) if #tr.projects.children > 0 then _p('/* Begin PBXTargetDependency section */') tree.traverse(tr.projects, { onleaf = function(node) _p(2,'%s /* PBXTargetDependency */ = {', node.parent.targetdependid) _p(3,'isa = PBXTargetDependency;') _p(3,'name = "%s";', node.name) _p(3,'targetProxy = %s /* PBXContainerItemProxy */;', node.parent.targetproxyid) _p(2,'};') end }) _p('/* End PBXTargetDependency section */') _p('') end end function xcode.cfg_excluded_files(prj, cfg) local excluded = {} local function exclude_pattern(file) if path.isabsolute(file) then return file end local start, term = file:findlast("/%.%./") if term then return path.join("*", file:sub(term + 1)) end start, term = file:find("%.%./") if start == 1 then return path.join("*", file:sub(term + 1)) end return path.join("*", file) end local function add_file(file) local name = exclude_pattern(file) if not table.icontains(excluded, name) then table.insert(excluded, name) end end local function verify_file(file) local name = exclude_pattern(file) if table.icontains(excluded, name) then error("'" .. file .. "' would be excluded by the rule to exclude '" .. name .. "'") end end for _, file in ipairs(cfg.excludes) do add_file(file) end for _, file in ipairs(prj.allfiles) do if not table.icontains(prj.excludes, file) and not table.icontains(cfg.excludes, file) then if not table.icontains(cfg.files, file) then add_file(file) else verify_file(file) end end end table.sort(excluded) return excluded end function xcode.XCBuildConfiguration_Impl(tr, id, opts, cfg) local cfgname = xcode.getconfigname(cfg) _p(2,'%s /* %s */ = {', id, cfgname) _p(3,'isa = XCBuildConfiguration;') _p(3,'buildSettings = {') for k, v in table.sortedpairs(opts) do if type(v) == "table" then if #v > 0 then _p(4,'%s = (', k) for i, v2 in ipairs(v) do _p(5,'%s,', xcode.quotestr(tostring(v2))) end _p(4,');') end else _p(4,'%s = %s;', k, xcode.quotestr(tostring(v))) end end _p(3,'};') _p(3,'name = %s;', xcode.quotestr(cfgname)) _p(2,'};') end local function add_options(options, extras) for _, tbl in ipairs(extras) do for tkey, tval in pairs(tbl) do options[tkey] = tval end end end local function add_wholearchive_links(opts, cfg) if #cfg.wholearchive > 0 then local linkopts = {} for _, depcfg in ipairs(premake.getlinks(cfg, "siblings", "object")) do if table.icontains(cfg.wholearchive, depcfg.project.name) then local linkpath = path.rebase(depcfg.linktarget.fullpath, depcfg.location, cfg.location) table.insert(linkopts, "-force_load") table.insert(linkopts, linkpath) end end if opts.OTHER_LDFLAGS then linkopts = table.join(linkopts, opts.OTHER_LDFLAGS) end opts.OTHER_LDFLAGS = linkopts end end function xcode.XCBuildConfiguration(tr, prj, opts) _p('/* Begin XCBuildConfiguration section */') for _, target in ipairs(tr.products.children) do for _, cfg in ipairs(tr.configs) do local values = opts.ontarget(tr, target, cfg) add_options(values, cfg.xcodetargetopts) xcode.XCBuildConfiguration_Impl(tr, cfg.xcode.targetid, values, cfg) end end for _, cfg in ipairs(tr.configs) do local values = opts.onproject(tr, prj, cfg) add_options(values, cfg.xcodeprojectopts) add_wholearchive_links(values, cfg) xcode.XCBuildConfiguration_Impl(tr, cfg.xcode.projectid, values, cfg) end _p('/* End XCBuildConfiguration section */') _p('') end function xcode.XCBuildConfigurationList(tr) local sln = tr.project.solution _p('/* Begin XCConfigurationList section */') for _, target in ipairs(tr.products.children) do _p(2,'%s /* Build configuration list for PBXNativeTarget "%s" */ = {', target.cfgsection, target.name) _p(3,'isa = XCConfigurationList;') _p(3,'buildConfigurations = (') for _, cfg in ipairs(tr.configs) do _p(4,'%s /* %s */,', cfg.xcode.targetid, xcode.getconfigname(cfg)) end _p(3,');') _p(3,'defaultConfigurationIsVisible = 0;') _p(3,'defaultConfigurationName = "%s";', xcode.getconfigname(tr.configs[1])) _p(2,'};') end _p(2,'1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "%s" */ = {', tr.name) _p(3,'isa = XCConfigurationList;') _p(3,'buildConfigurations = (') for _, cfg in ipairs(tr.configs) do _p(4,'%s /* %s */,', cfg.xcode.projectid, xcode.getconfigname(cfg)) end _p(3,');') _p(3,'defaultConfigurationIsVisible = 0;') _p(3,'defaultConfigurationName = "%s";', xcode.getconfigname(tr.configs[1])) _p(2,'};') _p('/* End XCConfigurationList section */') _p('') end function xcode.Footer() _p(1,'};') _p('\trootObject = __RootObject_ /* Project object */;') _p('}') end local xcode = premake.xcode local tree = premake.tree function xcode.buildprjtree(prj) local tr = premake.project.buildsourcetree(prj, true) tr.configs = {} for _, cfgname in ipairs(prj.solution.configurations) do for _, platform in ipairs(prj.solution.xcode.platforms) do local cfg = premake.getconfig(prj, cfgname, platform) cfg.xcode = {} cfg.xcode.targetid = xcode.newid(prj.xcode.projectnode, "tgt:"..platform..cfgname) cfg.xcode.projectid = xcode.newid(tr, "prj:"..platform..cfgname) table.insert(tr.configs, cfg) end end tree.traverse(tr, { onbranch = function(node) if path.getextension(node.name) == ".lproj" then local lang = path.getbasename(node.name) -- "English", "French", etc. for _, filenode in ipairs(node.children) do local grpnode = node.parent.children[filenode.name] if not grpnode then grpnode = tree.insert(node.parent, tree.new(filenode.name)) grpnode.kind = "vgroup" end filenode.name = path.getbasename(lang) tree.insert(grpnode, filenode) end tree.remove(node) end end }) tree.traverse(tr, { onbranch = function(node) if path.getextension(node.name) == ".xcassets" then node.children = {} end end }) tr.frameworks = tree.new("Frameworks") for cfg in premake.eachconfig(prj) do for _, link in ipairs(premake.getlinks(cfg, "system", "fullpath")) do local name = path.getname(link) if xcode.isframework(name) and not tr.frameworks.children[name] then node = tree.insert(tr.frameworks, tree.new(name)) node.path = link end end end if #tr.frameworks.children > 0 then tree.insert(tr, tr.frameworks) end tr.products = tree.insert(tr, tree.new("Products")) tr.projects = tree.new("Projects") for _, dep in ipairs(premake.getdependencies(prj, "sibling", "object")) do local xcpath = xcode.getxcodeprojname(dep) local xcnode = tree.insert(tr.projects, tree.new(path.getname(xcpath))) xcnode.path = xcpath xcnode.project = dep xcnode.productgroupid = xcode.newid(xcnode, "prodgrp") xcnode.productproxyid = xcode.newid(xcnode, "prodprox") xcnode.targetproxyid = xcode.newid(xcnode, "targprox") xcnode.targetdependid = xcode.newid(xcnode, "targdep") local cfg = premake.getconfig(dep, prj.configurations[1]) node = tree.insert(xcnode, tree.new(cfg.linktarget.name)) node.path = cfg.linktarget.fullpath node.cfg = cfg end if #tr.projects.children > 0 then tree.insert(tr, tr.projects) end tree.traverse(tr, { onbranchexit = function(node) for _, child in ipairs(node.children) do if (child.location) then if (node.location) then while (not string.startswith(child.location, node.location)) do node.location = path.getdirectory(node.location) end else node.location = path.getdirectory(child.location) end end end end, onleaf = function(node) if (node.cfg) then node.location = node.cfg.name end end }, true) tree.traverse(tr, { onbranchexit = function(node, depth) if (node.location and node.parent and node.parent.location) then node.location = path.getrelative(node.parent.location, node.location) end end, onleaf = function(node, depth) if (node.location and node.parent and node.parent.location) then node.location = path.getrelative(node.parent.location, node.location) end end }, true) tree.traverse(tr, { onnode = function(node) node.id = xcode.newid(node) if xcode.getbuildcategory(node) then node.buildid = xcode.newid(node, "build") end if string.endswith(node.name, "Info.plist") then tr.infoplist = node end if string.endswith(node.name, ".entitlements") then tr.entitlements = node end end }, true) node = tree.insert(tr.products, prj.xcode.projectnode) node.kind = "product" node.path = node.cfg.buildtarget.fullpath node.cfgsection = xcode.newid(node, "cfg") node.resstageid = xcode.newid(node, "rez") node.sourcesid = xcode.newid(node, "src") node.fxstageid = xcode.newid(node, "fxs") return tr end local premake = premake local xcode = premake.xcode local function buildableref(indent, prj, cfg) cfg = cfg or premake.eachconfig(prj)() _p(indent + 0, '', prj.name) _p(indent + 0, '') end local function cmdlineargs(indent, cfg) if #cfg.debugargs > 0 then _p(indent, '') for _, arg in ipairs(cfg.debugargs) do _p(indent + 1, '') _p(indent + 1, '') end _p(indent, '') end end local function envvars(indent, cfg) if #cfg.debugenvs > 0 then _p(indent, '') for _, arg in ipairs(cfg.debugenvs) do local eq = arg:find("=") local k = arg:sub(1, eq) local v = arg:sub(eq + 1) _p(indent + 1, '') _p(indent + 1, '') end _p(indent, '') end end local function workingdir(dir) if not path.isabsolute(dir) then dir = "$PROJECT_DIR/" .. dir end return dir end local function bestconfig(prj, fordebug) local bestcfg = nil local bestscore = -1 for cfg in premake.eachconfig(prj) do local score = 0 if cfg.platform == "Native" then score = score + 10 end if fordebug and cfg.name == "Debug" then score = score + 1 end if not fordebug and cfg.name == "Release" then score = score + 1 end if score > bestscore then bestcfg = cfg bestscore = score end end return bestcfg end function xcode.scheme(tobuild, primary, schemecfg) _p('') _p('') _p(1, '') _p(2, '') for _, prj in ipairs(tobuild) do _p(3, '') buildableref(4, prj) _p(3, '') end local debugcfg = schemecfg or bestconfig(primary, true) local releasecfg = schemecfg or bestconfig(primary, false) local debugname = xcode.getconfigname(debugcfg) local releasename = xcode.getconfigname(releasecfg) _p(2, '') _p(1, '') _p(1, '') _p(2, '') _p(2, '') _p(2, '') buildableref(3, primary, debugcfg) _p(2, '') _p(2, '') _p(2, '') _p(1, '') _p(1, '') if debugcfg.debugcmd then _p(2, '', debugcfg.debugcmd) _p(2, '') else _p(2, '') buildableref(3, primary, debugcfg) _p(2, '') end cmdlineargs(2, debugcfg) envvars(2, debugcfg) _p(2, '') _p(2, '') _p(1, '') _p(1, '') _p(2, '') buildableref(3, primary, releasecfg) _p(2, '') cmdlineargs(2, releasecfg) envvars(2, releasecfg) _p(1, '') _p(1, '', debugname) _p(1, '') _p(1, '') _p(1, '') _p('') end function xcode.generate_schemes(prj, base_path) if (prj.kind == "ConsoleApp" or prj.kind == "WindowedApp") or (prj.options and prj.options.XcodeLibrarySchemes) then if prj.options and prj.options.XcodeSchemeNoConfigs then premake.generate(prj, path.join(base_path, "%%.xcscheme"), function(prj) xcode.scheme({prj}, prj) end) else for cfg in premake.eachconfig(prj) do premake.generate(prj, path.join(base_path, "%% " .. cfg.name .. ".xcscheme"), function(prj) xcode.scheme({prj}, prj, cfg) end) end end end end local premake = premake local xcode = premake.xcode xcode.allscheme = false function xcode.workspace_head() _p('') _p('') end function xcode.workspace_tail() _p('') end function xcode.workspace_file_ref(prj, indent) local projpath = path.getrelative(prj.solution.location, prj.location) if projpath == '.' then projpath = '' else projpath = projpath ..'/' end _p(indent, '', projpath .. prj.name .. '.xcodeproj') _p(indent, '') end function xcode.workspace_group(grp, indent) _p(indent, '', grp.name) local function comparenames(a, b) return a.name < b.name end local groups = table.join(grp.groups) local projects = table.join(grp.projects) table.sort(groups, comparenames) table.sort(projects, comparenames) for _, child in ipairs(groups) do xcode.workspace_group(child, indent + 1) end for _, prj in ipairs(projects) do xcode.workspace_file_ref(prj, indent + 1) end _p(indent, '') end function xcode.workspace_generate(sln) xcode.preparesolution(sln) xcode.workspace_head() xcode.reorderProjects(sln) for grp in premake.solution.eachgroup(sln) do if grp.parent == nil then xcode.workspace_group(grp, 1) end end for prj in premake.solution.eachproject(sln) do if prj.group == nil then xcode.workspace_file_ref(prj, 1) end end xcode.workspace_tail() end function xcode.workspace_scheme(sln) if not xcode.allscheme then return false end local projects = {} local primary = nil for prj in premake.solution.eachproject(sln) do if not primary or (sln.startproject == prj.name) then primary = prj end table.insert(projects, prj) end xcode.scheme(projects, primary) end function xcode.workspace_settings(sln) _p('') _p('') _p('') _p('') _p(1, 'IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded') _p(1, '') _p('') _p('') end function xcode.reorderProjects(sln) if sln.startproject then for i, prj in ipairs(sln.projects) do if sln.startproject == prj.name then local cur = prj.group while cur ~= nil do for j, group in ipairs(sln.groups) do if group == cur then table.remove(sln.groups, j) break end end table.insert(sln.groups, 1, cur) cur = cur.parent end table.remove(sln.projects, i) table.insert(sln.projects, 1, prj) break end end end end local premake = premake premake.xcode8 = { } local xcode = premake.xcode local xcode8 = premake.xcode8 function xcode8.XCBuildConfiguration_Target(tr, target, cfg) local cfgname = xcode.getconfigname(cfg) local installpaths = { ConsoleApp = "/usr/local/bin", WindowedApp = "$(HOME)/Applications", SharedLib = "/usr/local/lib", StaticLib = "/usr/local/lib", Bundle = "$(LOCAL_LIBRARY_DIR)/Bundles", } local options = { ALWAYS_SEARCH_USER_PATHS = "NO", GCC_DYNAMIC_NO_PIC = "NO", GCC_MODEL_TUNING = "G5", INSTALL_PATH = installpaths[cfg.kind], PRODUCT_NAME = cfg.buildtarget.basename, } if not cfg.flags.Symbols then options.DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym" end if cfg.kind ~= "StaticLib" and cfg.buildtarget.prefix ~= "" then options.EXECUTABLE_PREFIX = cfg.buildtarget.prefix end if cfg.targetextension then local ext = cfg.targetextension options.EXECUTABLE_EXTENSION = iif(ext:startswith("."), ext:sub(2), ext) end if cfg.flags.ObjcARC then options.CLANG_ENABLE_OBJC_ARC = "YES" end local outdir = path.getdirectory(cfg.buildtarget.bundlepath) if outdir ~= "." then options.CONFIGURATION_BUILD_DIR = outdir end if tr.infoplist then options.INFOPLIST_FILE = tr.infoplist.cfg.name end local infoplist_file = nil for _, v in ipairs(cfg.files) do if (string.find (string.lower (v), 'info.plist') ~= nil) then infoplist_file = string.format('$(SRCROOT)/%s', v) end end if infoplist_file ~= nil then options.INFOPLIST_FILE = infoplist_file end local action = premake.action.current() local get_opt = function(opt, def) return (opt and #opt > 0) and opt or def end local iosversion = get_opt(cfg.iostargetplatformversion, action.xcode.iOSTargetPlatformVersion) local macosversion = get_opt(cfg.macostargetplatformversion, action.xcode.macOSTargetPlatformVersion) local tvosversion = get_opt(cfg.tvostargetplatformversion, action.xcode.tvOSTargetPlatformVersion) if iosversion then options.IPHONEOS_DEPLOYMENT_TARGET = iosversion elseif macosversion then options.MACOSX_DEPLOYMENT_TARGET = macosversion elseif tvosversion then options.TVOS_DEPLOYMENT_TARGET = tvosversion end if cfg.kind == "Bundle" and not cfg.options.SkipBundling then options.PRODUCT_BUNDLE_IDENTIFIER = "genie." .. cfg.buildtarget.basename:gsub("%s+", ".") --replace spaces with . local ext = cfg.targetextension if ext then options.WRAPPER_EXTENSION = iif(ext:startswith("."), ext:sub(2), ext) else options.WRAPPER_EXTENSION = "bundle" end end return options end function xcode8.XCBuildConfiguration_Project(tr, prj, cfg) local cfgname = xcode.getconfigname(cfg) local archs = { Native = nil, x32 = "i386", x64 = "x86_64", Universal32 = "$(ARCHS_STANDARD_32_BIT)", Universal64 = "$(ARCHS_STANDARD_64_BIT)", Universal = "$(ARCHS_STANDARD_32_64_BIT)", } local checks = { ["-ffast-math"] = cfg.flags.FloatFast, ["-ffloat-store"] = cfg.flags.FloatStrict, ["-fomit-frame-pointer"] = cfg.flags.NoFramePointer, } local cflags = { } for flag, check in pairs(checks) do if check then table.insert(cflags, flag) end end local ldflags = { } for _, lib in ipairs(premake.getlinks(cfg, "system")) do if not xcode.isframework(lib) then table.insert(ldflags, "-l" .. lib) end end local options = { ARCHS = archs[cfg.platform], CLANG_WARN__DUPLICATE_METHOD_MATCH = "YES", CLANG_WARN_BOOL_CONVERSION = "YES", CLANG_WARN_CONSTANT_CONVERSION = "YES", CLANG_WARN_EMPTY_BODY = "YES", CLANG_WARN_ENUM_CONVERSION = "YES", CLANG_WARN_INFINITE_RECURSION = "YES", CLANG_WARN_INT_CONVERSION = "YES", CLANG_WARN_SUSPICIOUS_MOVE = "YES", CLANG_WARN_UNREACHABLE_CODE = "YES", CONFIGURATION_TEMP_DIR = "$(OBJROOT)", ENABLE_STRICT_OBJC_MSGSEND = "YES", ENABLE_TESTABILITY = "YES", GCC_C_LANGUAGE_STANDARD = "gnu99", GCC_NO_COMMON_BLOCKS = "YES", GCC_PREPROCESSOR_DEFINITIONS = cfg.defines, GCC_SYMBOLS_PRIVATE_EXTERN = "NO", GCC_WARN_64_TO_32_BIT_CONVERSION = "YES", GCC_WARN_ABOUT_RETURN_TYPE = "YES", GCC_WARN_UNDECLARED_SELECTOR = "YES", GCC_WARN_UNINITIALIZED_AUTOS = "YES", GCC_WARN_UNUSED_FUNCTION = "YES", GCC_WARN_UNUSED_VARIABLE = "YES", HEADER_SEARCH_PATHS = table.join(cfg.includedirs, cfg.systemincludedirs), LIBRARY_SEARCH_PATHS = cfg.libdirs, OBJROOT = cfg.objectsdir, ONLY_ACTIVE_ARCH = "YES", OTHER_CFLAGS = table.join(cflags, cfg.buildoptions, cfg.buildoptions_c), OTHER_CPLUSPLUSFLAGS = table.join(cflags, cfg.buildoptions, cfg.buildoptions_cpp), OTHER_LDFLAGS = table.join(ldflags, cfg.linkoptions), SDKROOT = xcode.toolset, USER_HEADER_SEARCH_PATHS = cfg.userincludedirs, } if tr.entitlements then options.CODE_SIGN_ENTITLEMENTS = tr.entitlements.cfg.name end local targetdir = path.getdirectory(cfg.buildtarget.bundlepath) if targetdir ~= "." then options.CONFIGURATION_BUILD_DIR = "$(SYMROOT)" options.SYMROOT = targetdir end if cfg.flags.Symbols then options.COPY_PHASE_STRIP = "NO" end local excluded = xcode.cfg_excluded_files(prj, cfg) if #excluded > 0 then options.EXCLUDED_SOURCE_FILE_NAMES = excluded end if cfg.flags.NoExceptions then options.GCC_ENABLE_CPP_EXCEPTIONS = "NO" end if cfg.flags.NoRTTI then options.GCC_ENABLE_CPP_RTTI = "NO" end if cfg.flags.Symbols and not cfg.flags.NoEditAndContinue then options.GCC_ENABLE_FIX_AND_CONTINUE = "YES" end if cfg.flags.NoExceptions then options.GCC_ENABLE_OBJC_EXCEPTIONS = "NO" end if cfg.flags.Optimize or cfg.flags.OptimizeSize then options.GCC_OPTIMIZATION_LEVEL = "s" elseif cfg.flags.OptimizeSpeed then options.GCC_OPTIMIZATION_LEVEL = 3 else options.GCC_OPTIMIZATION_LEVEL = 0 end if cfg.pchheader and not cfg.flags.NoPCH then options.GCC_PRECOMPILE_PREFIX_HEADER = "YES" local pch = cfg.pchheader for _, incdir in ipairs(cfg.includedirs) do local abspath = path.getabsolute(path.join(cfg.project.location, incdir)) local testname = path.join(abspath, pch) if os.isfile(testname) then pch = path.getrelative(cfg.location, testname) break end end options.GCC_PREFIX_HEADER = pch end if cfg.flags.FatalWarnings then options.GCC_TREAT_WARNINGS_AS_ERRORS = "YES" end if cfg.kind == "Bundle" then options.MACH_O_TYPE = "mh_bundle" end if cfg.flags.StaticRuntime then options.STANDARD_C_PLUS_PLUS_LIBRARY_TYPE = "static" end if cfg.flags.PedanticWarnings or cfg.flags.ExtraWarnings then options.WARNING_CFLAGS = "-Wall" end if cfg.flags.Cpp11 then options.CLANG_CXX_LANGUAGE_STANDARD = "c++11" elseif cfg.flags.Cpp14 or cfg.flags.CppLatest then options.CLANG_CXX_LANGUAGE_STANDARD = "c++14" elseif cfg.flags.Cpp17 then if premake.action.current() == premake.action.get("xcode8") then error("XCode8 does not support C++17.") end end for _, val in ipairs(premake.xcode.parameters) do local eqpos = string.find(val, "=") if eqpos ~= nil then local key = string.trim(string.sub(val, 1, eqpos - 1)) local value = string.trim(string.sub(val, eqpos + 1)) options[key] = value end end return options end function xcode8.project(prj) local tr = xcode.buildprjtree(prj) xcode.Header(tr, 48) xcode.PBXBuildFile(tr) xcode.PBXContainerItemProxy(tr) xcode.PBXFileReference(tr,prj) xcode.PBXFrameworksBuildPhase(tr) xcode.PBXGroup(tr) xcode.PBXNativeTarget(tr) xcode.PBXProject(tr, "8.0") xcode.PBXReferenceProxy(tr) xcode.PBXResourcesBuildPhase(tr) xcode.PBXShellScriptBuildPhase(tr) xcode.PBXCopyFilesBuildPhase(tr) xcode.PBXSourcesBuildPhase(tr,prj) xcode.PBXVariantGroup(tr) xcode.PBXTargetDependency(tr) xcode.XCBuildConfiguration(tr, prj, { ontarget = xcode8.XCBuildConfiguration_Target, onproject = xcode8.XCBuildConfiguration_Project, }) xcode.XCBuildConfigurationList(tr) xcode.Footer(tr) end newaction { trigger = "xcode8", shortname = "Xcode 8", description = "Generate Apple Xcode 8 project files", os = "macosx", valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle" }, valid_languages = { "C", "C++" }, valid_tools = { cc = { "gcc" }, }, valid_platforms = { Native = "Native", x32 = "Native 32-bit", x64 = "Native 64-bit", Universal = "Universal", }, default_platform = "Native", onsolution = function(sln) premake.generate(sln, "%%.xcworkspace/contents.xcworkspacedata", xcode.workspace_generate) premake.generate(sln, "%%.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings", xcode.workspace_settings) premake.generate(sln, "%%.xcworkspace/xcshareddata/xcschemes/-ALL-.xcscheme", xcode.workspace_scheme) end, onproject = function(prj) premake.generate(prj, "%%.xcodeproj/project.pbxproj", xcode8.project) xcode.generate_schemes(prj, "%%.xcodeproj/xcshareddata/xcschemes") end, oncleanproject = function(prj) premake.clean.directory(prj, "%%.xcodeproj") premake.clean.directory(prj, "%%.xcworkspace") end, oncheckproject = xcode.checkproject, xcode = { iOSTargetPlatformVersion = nil, macOSTargetPlatformVersion = nil, tvOSTargetPlatformVersion = nil, }, } local premake = premake premake.xcode9 = { } local xcode = premake.xcode local xcode8 = premake.xcode8 local xcode9 = premake.xcode9 function xcode9.XCBuildConfiguration_Project(tr, prj, cfg) local options = xcode8.XCBuildConfiguration_Project(tr, prj, cfg) if cfg.flags.Cpp17 then options.CLANG_CXX_LANGUAGE_STANDARD = "c++17" elseif cfg.flags.Cpp20 or cfg.flags.CppLatest then options.CLANG_CXX_LANGUAGE_STANDARD = "c++20" end return table.merge(options, { CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = "YES", CLANG_WARN_COMMA = "YES", CLANG_WARN_NON_LITERAL_NULL_CONVERSION = "YES", CLANG_WARN_OBJC_LITERAL_CONVERSION = "YES", CLANG_WARN_RANGE_LOOP_ANALYSIS = "YES", CLANG_WARN_STRICT_PROTOTYPES = "YES", }) end function xcode9.project(prj) local tr = xcode.buildprjtree(prj) xcode.Header(tr, 48) xcode.PBXBuildFile(tr) xcode.PBXContainerItemProxy(tr) xcode.PBXFileReference(tr,prj) xcode.PBXFrameworksBuildPhase(tr) xcode.PBXGroup(tr) xcode.PBXNativeTarget(tr) xcode.PBXProject(tr, "8.0") xcode.PBXReferenceProxy(tr) xcode.PBXResourcesBuildPhase(tr) xcode.PBXShellScriptBuildPhase(tr) xcode.PBXCopyFilesBuildPhase(tr) xcode.PBXSourcesBuildPhase(tr,prj) xcode.PBXVariantGroup(tr) xcode.PBXTargetDependency(tr) xcode.XCBuildConfiguration(tr, prj, { ontarget = xcode8.XCBuildConfiguration_Target, onproject = xcode9.XCBuildConfiguration_Project, }) xcode.XCBuildConfigurationList(tr) xcode.Footer(tr) end newaction { trigger = "xcode9", shortname = "Xcode 9", description = "Generate Apple Xcode 9 project files", os = "macosx", valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle" }, valid_languages = { "C", "C++" }, valid_tools = { cc = { "gcc" }, }, valid_platforms = { Native = "Native", x32 = "Native 32-bit", x64 = "Native 64-bit", Universal = "Universal", }, default_platform = "Native", onsolution = function(sln) premake.generate(sln, "%%.xcworkspace/contents.xcworkspacedata", xcode.workspace_generate) premake.generate(sln, "%%.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings", xcode.workspace_settings) premake.generate(sln, "%%.xcworkspace/xcshareddata/xcschemes/-ALL-.xcscheme", xcode.workspace_scheme) end, onproject = function(prj) premake.generate(prj, "%%.xcodeproj/project.pbxproj", xcode9.project) xcode.generate_schemes(prj, "%%.xcodeproj/xcshareddata/xcschemes") end, oncleanproject = function(prj) premake.clean.directory(prj, "%%.xcodeproj") premake.clean.directory(prj, "%%.xcworkspace") end, oncheckproject = xcode.checkproject, xcode = { iOSTargetPlatformVersion = nil, macOSTargetPlatformVersion = nil, tvOSTargetPlatformVersion = nil, }, } local premake = premake premake.xcode10 = { } local xcode = premake.xcode local xcode8 = premake.xcode8 local xcode9 = premake.xcode9 local xcode10 = premake.xcode10 function xcode10.XCBuildConfiguration_Project(tr, prj, cfg) local options = xcode9.XCBuildConfiguration_Project(tr, prj, cfg) return table.merge(options, { CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = "YES", CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = "YES", CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = "YES", CLANG_WARN_COMMA = "YES", CLANG_WARN_NON_LITERAL_NULL_CONVERSION = "YES", CLANG_WARN_OBJC_LITERAL_CONVERSION = "YES", CLANG_WARN_RANGE_LOOP_ANALYSIS = "YES", CLANG_WARN_STRICT_PROTOTYPES = "YES", }) end function xcode10.XCBuildConfiguration_Target(tr, target, cfg) local options = xcode8.XCBuildConfiguration_Target(tr, target, cfg) if not cfg.flags.ObjcARC then options.CLANG_ENABLE_OBJC_WEAK = "YES" end return options end function xcode10.project(prj) local tr = xcode.buildprjtree(prj) xcode.Header(tr, 48) xcode.PBXBuildFile(tr) xcode.PBXContainerItemProxy(tr) xcode.PBXFileReference(tr,prj) xcode.PBXFrameworksBuildPhase(tr) xcode.PBXGroup(tr) xcode.PBXNativeTarget(tr) xcode.PBXProject(tr, "8.0") xcode.PBXReferenceProxy(tr) xcode.PBXResourcesBuildPhase(tr) xcode.PBXShellScriptBuildPhase(tr) xcode.PBXCopyFilesBuildPhase(tr) xcode.PBXSourcesBuildPhase(tr,prj) xcode.PBXVariantGroup(tr) xcode.PBXTargetDependency(tr) xcode.XCBuildConfiguration(tr, prj, { ontarget = xcode10.XCBuildConfiguration_Target, onproject = xcode10.XCBuildConfiguration_Project, }) xcode.XCBuildConfigurationList(tr) xcode.Footer(tr) end newaction { trigger = "xcode10", shortname = "Xcode 10", description = "Generate Apple Xcode 10 project files", os = "macosx", valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle" }, valid_languages = { "C", "C++" }, valid_tools = { cc = { "gcc" }, }, valid_platforms = { Native = "Native", x32 = "Native 32-bit", x64 = "Native 64-bit", Universal = "Universal", }, default_platform = "Native", onsolution = function(sln) premake.generate(sln, "%%.xcworkspace/contents.xcworkspacedata", xcode.workspace_generate) premake.generate(sln, "%%.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings", xcode.workspace_settings) premake.generate(sln, "%%.xcworkspace/xcshareddata/xcschemes/-ALL-.xcscheme", xcode.workspace_scheme) end, onproject = function(prj) premake.generate(prj, "%%.xcodeproj/project.pbxproj", xcode10.project) xcode.generate_schemes(prj, "%%.xcodeproj/xcshareddata/xcschemes") end, oncleanproject = function(prj) premake.clean.directory(prj, "%%.xcodeproj") premake.clean.directory(prj, "%%.xcworkspace") end, oncheckproject = xcode.checkproject, xcode = { iOSTargetPlatformVersion = nil, macOSTargetPlatformVersion = nil, tvOSTargetPlatformVersion = nil, }, } local premake = premake premake.xcode11 = { } local xcode = premake.xcode local xcode10 = premake.xcode10 local xcode11 = premake.xcode11 function xcode11.XCBuildConfiguration_Target(tr, target, cfg) local options = xcode10.XCBuildConfiguration_Target(tr, target, cfg) options.CODE_SIGN_IDENTITY = "-" return options end function xcode11.project(prj) local tr = xcode.buildprjtree(prj) xcode.Header(tr, 48) xcode.PBXBuildFile(tr) xcode.PBXContainerItemProxy(tr) xcode.PBXFileReference(tr,prj) xcode.PBXFrameworksBuildPhase(tr) xcode.PBXGroup(tr) xcode.PBXNativeTarget(tr) xcode.PBXProject(tr, "8.0") xcode.PBXReferenceProxy(tr) xcode.PBXResourcesBuildPhase(tr) xcode.PBXShellScriptBuildPhase(tr) xcode.PBXCopyFilesBuildPhase(tr) xcode.PBXSourcesBuildPhase(tr,prj) xcode.PBXVariantGroup(tr) xcode.PBXTargetDependency(tr) xcode.XCBuildConfiguration(tr, prj, { ontarget = xcode11.XCBuildConfiguration_Target, onproject = xcode10.XCBuildConfiguration_Project, }) xcode.XCBuildConfigurationList(tr) xcode.Footer(tr) end newaction { trigger = "xcode11", shortname = "Xcode 11", description = "Generate Apple Xcode 11 project files", os = "macosx", valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle" }, valid_languages = { "C", "C++" }, valid_tools = { cc = { "gcc" }, }, valid_platforms = { Native = "Native" }, default_platform = "Native", onsolution = function(sln) premake.generate(sln, "%%.xcworkspace/contents.xcworkspacedata", xcode.workspace_generate) premake.generate(sln, "%%.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings", xcode.workspace_settings) premake.generate(sln, "%%.xcworkspace/xcshareddata/xcschemes/-ALL-.xcscheme", xcode.workspace_scheme) end, onproject = function(prj) premake.generate(prj, "%%.xcodeproj/project.pbxproj", xcode11.project) xcode.generate_schemes(prj, "%%.xcodeproj/xcshareddata/xcschemes") end, oncleanproject = function(prj) premake.clean.directory(prj, "%%.xcodeproj") premake.clean.directory(prj, "%%.xcworkspace") end, oncheckproject = xcode.checkproject, xcode = { iOSTargetPlatformVersion = nil, macOSTargetPlatformVersion = nil, tvOSTargetPlatformVersion = nil, }, } premake.ninja = { } local p = premake newaction { trigger = "ninja", shortname = "ninja", description = "Generate Ninja build files", module = "ninja", valid_kinds = {"ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle"}, valid_languages = {"C", "C++", "Swift"}, valid_tools = { cc = { "gcc" }, swift = { "swift" }, }, onsolution = function(sln) io.eol = "\r\n" io.indent = "\t" io.escaper(p.ninja.esc) p.generate(sln, "Makefile", p.ninja.generate_solution) io.indent = " " p.ninja.generate_ninja_builds(sln) end, onproject = function(prj) io.eol = "\r\n" io.indent = " " io.escaper(p.ninja.esc) p.ninja.generate_project(prj) end, oncleansolution = function(sln) for _,name in ipairs(sln.configurations) do premake.clean.file(sln, p.ninja.get_solution_name(sln, name)) end end, oncleanproject = function(prj) end, oncleantarget = function(prj) end, } local ninja = premake.ninja function ninja.esc(value) if value then value = string.gsub(value, "%$", "$$") -- TODO maybe there is better way value = string.gsub(value, ":", "$:") value = string.gsub(value, "\n", "$\n") value = string.gsub(value, " ", "$ ") end return value end function ninja.shesc(value) if type(value) == "table" then local result = {} local n = #value for i = 1, n do table.insert(result, ninja.shesc(value[i])) end return result end if value:find(" ") then return "\"" .. value .. "\"" end return value end function ninja.list(value) if #value > 0 then return " " .. table.concat(value, " ") else return "" end end function ninja.arglist(arg, value) if #value > 0 then local args = {} for _, val in ipairs(value) do table.insert(args, string.format("%s %s", arg, val)) end return table.concat(args, " ") else return "" end end function ninja.generate_project(prj) if prj.language == "Swift" then ninja.generate_swift(prj) else ninja.generate_cpp(prj) end end local function innerget(self, key) return rawget(getmetatable(self), key) or self.__inner[key] end local prj_proxy = { __index = innerget } local cfg_proxy = { __index = innerget } function new_prj_proxy(prj) prj = prj.project or prj local v = { __inner = prj } local __configs = {} for key, cfg in pairs(prj.__configs) do if key ~= "" then __configs[key] = ninja.get_proxy("cfg", cfg) else __configs[key] = cfg end end v.__configs = __configs return setmetatable(v, prj_proxy) end local function rebasekeys(t, keys, old, new) for _,key in ipairs(keys) do t[key] = path.rebase(t[key], old, new) end return t end local function rebasearray(t, old, new) local res = { } for _,f in ipairs(t) do table.insert(res, path.rebase(f, old, new)) end return res end function new_cfg_proxy(cfg) local keys = { "directory", "fullpath", "bundlepath" } local old = cfg.location local new = path.join(cfg.location, cfg.shortname) local v = { __inner = cfg, location = new, objectsdir = path.rebase(cfg.objectsdir, old, new), buildtarget = rebasekeys(table.deepcopy(cfg.buildtarget), keys, old, new), linktarget = rebasekeys(table.deepcopy(cfg.linktarget), keys, old, new), } v.files = rebasearray(cfg.files, old, new) v.includedirs = rebasearray(cfg.includedirs, old, new) v.libdirs = rebasearray(cfg.libdirs, old, new) v.userincludedirs = rebasearray(cfg.userincludedirs, old, new) v.systemincludedirs = rebasearray(cfg.systemincludedirs, old, new) v.swiftmodulemaps = rebasearray(cfg.swiftmodulemaps, old, new) return setmetatable(v, cfg_proxy) end function cfg_proxy:getprojectfilename(fullpath) local name = self.project.name .. ".ninja" if fullpath ~= nil then return path.join(self.location, name) end return name end function cfg_proxy:getoutputfilename() return path.join(self.buildtarget.directory, self.buildtarget.name) end local proxy_cache = { prj = { new = new_prj_proxy }, cfg = { new = new_cfg_proxy }, } function get_proxy(cache, obj) if not cache[obj] then cache[obj] = cache.new(obj) end return cache[obj] end function ninja.get_proxy(typ, obj) if not proxy_cache[typ] then error("invalid proxy type") end return get_proxy(proxy_cache[typ], obj) end local ninja = premake.ninja local p = premake local solution = p.solution function ninja.generate_solution(sln) local cc = premake[_OPTIONS.cc] local platforms = premake.filterplatforms(sln, cc.platforms, "Native") _p('# %s solution makefile autogenerated by GENie', premake.action.current().shortname) _p('# Type "make help" for usage help') _p('') _p('NINJA=ninja') _p('ifndef config') _p(' config=%s', _MAKE.esc(premake.getconfigname(sln.configurations[1], platforms[1], true))) _p('endif') _p('') local projects = table.extract(sln.projects, "name") table.sort(projects) _p('') _p('.PHONY: all clean help $(PROJECTS)') _p('') _p('all:') if (not sln.messageskip) or (not table.contains(sln.messageskip, "SkipBuildingMessage")) then _p(1, '@echo "==== Building all ($(config)) ===="') end _p(1, '@${NINJA} -C ${config} all') _p('') for _, prj in ipairs(sln.projects) do local prjx = ninja.get_proxy("prj", prj) _p('%s:', _MAKE.esc(prj.name)) if (not sln.messageskip) or (not table.contains(sln.messageskip, "SkipBuildingMessage")) then _p(1, '@echo "==== Building %s ($(config)) ===="', prj.name) end _p(1, '@${NINJA} -C ${config} %s', prj.name) _p('') end _p('clean:') _p(1, '@${NINJA} -C ${config} -t clean') _p('') _p('help:') _p(1,'@echo "Usage: make [config=name] [target]"') _p(1,'@echo ""') _p(1,'@echo "CONFIGURATIONS:"') local cfgpairs = { } for _, platform in ipairs(platforms) do for _, cfgname in ipairs(sln.configurations) do _p(1,'@echo " %s"', premake.getconfigname(cfgname, platform, true)) end end _p(1,'@echo ""') _p(1,'@echo "TARGETS:"') _p(1,'@echo " all (default)"') _p(1,'@echo " clean"') for _, prj in ipairs(sln.projects) do _p(1,'@echo " %s"', prj.name) end _p(1,'@echo ""') _p(1,'@echo "For more information, see https://github.com/bkaradzic/genie"') end local generate local function getconfigs(sln, name, plat) local cfgs = {} for prj in solution.eachproject(sln) do prj = ninja.get_proxy("prj", prj) for cfg in p.eachconfig(prj, plat) do if cfg.name == name then table.insert(cfgs, cfg) end end end return cfgs end function ninja.generate_ninja_builds(sln) local cc = premake[_OPTIONS.cc] sln.getlocation = function(cfg, plat) return path.join(sln.location, premake.getconfigname(cfg, plat, true)) end local platforms = premake.filterplatforms(sln, cc.platforms, "Native") for _,plat in ipairs(platforms) do for _,name in ipairs(sln.configurations) do p.generate(sln, ninja.get_solution_name(sln, name, plat), function(sln) generate(getconfigs(sln, name, plat)) end) end end end function ninja.get_solution_name(sln, cfg, plat) return path.join(sln.getlocation(cfg, plat), "build.ninja") end function generate(prjcfgs) local cfgs = {} local cfg_start = nil local cfg_first = nil local cfg_first_lib = nil _p("# solution build file") _p("# generated with GENie ninja") _p("") _p("# build projects") for _,cfg in ipairs(prjcfgs) do local key = cfg.project.name if not cfgs[key] then cfgs[key] = "" end cfgs[key] = cfg:getoutputfilename() .. " " if not cfgs["all"] then cfgs["all"] = "" end cfgs["all"] = cfgs["all"] .. cfg:getoutputfilename() .. " " if (cfg_start == nil) and (cfg.solution.startproject == key) then cfg_start = key end if (cfg_first == nil) and (cfg.kind == "ConsoleApp" or cfg.kind == "WindowedApp") then cfg_first = key end if (cfg_first_lib == nil) and (cfg.kind == "StaticLib" or cfg.kind == "SharedLib") then cfg_first_lib = key end _p("subninja " .. cfg:getprojectfilename()) end _p("") _p("# targets") for cfg, outputs in iter.sortByKeys(cfgs) do _p("build " .. cfg .. ": phony " .. outputs) end _p("") _p("# default target") _p("default " .. (cfg_start or cfg_first or cfg_first_lib)) _p("") end premake.ninja.cpp = { } local ninja = premake.ninja local cpp = premake.ninja.cpp local p = premake local function wrap_ninja_cmd(c) if os.is("windows") then return 'cmd /c "' .. c .. '"' else return c end end function ninja.generate_cpp(prj) local pxy = ninja.get_proxy("prj", prj) local tool = premake.gettool(prj) local platforms = premake.filterplatforms(prj.solution, tool.platforms, "Native") for _, platform in ipairs(platforms) do for cfg in p.eachconfig(pxy, platform) do p.generate(cfg, cfg:getprojectfilename(), function() cpp.generate_config(prj, cfg) end) end end end function cpp.generate_config(prj, cfg) local tool = premake.gettool(prj) _p('# Ninja build project file autogenerated by GENie') _p('# https://github.com/bkaradzic/GENie') _p("") _p("ninja_required_version = 1.7") _p("") local flags = { defines = ninja.list(tool.getdefines(cfg.defines)), includes = ninja.list(table.join(tool.getincludedirs(cfg.includedirs), tool.getquoteincludedirs(cfg.userincludedirs), tool.getsystemincludedirs(cfg.systemincludedirs))), cppflags = ninja.list(tool.getcppflags(cfg)), asmflags = ninja.list(table.join(tool.getcflags(cfg), cfg.buildoptions, cfg.buildoptions_asm)), cflags = ninja.list(table.join(tool.getcflags(cfg), cfg.buildoptions, cfg.buildoptions_c)), cxxflags = ninja.list(table.join(tool.getcflags(cfg), tool.getcxxflags(cfg), cfg.buildoptions, cfg.buildoptions_cpp)), objcflags = ninja.list(table.join(tool.getcflags(cfg), tool.getcxxflags(cfg), cfg.buildoptions, cfg.buildoptions_objc)), } _p("") _p("# core rules for " .. cfg.name) _p("rule cc") _p(" command = " .. wrap_ninja_cmd(tool.cc .. " $defines $includes $flags -MMD -MF $out.d -c -o $out $in")) _p(" description = cc $out") _p(" depfile = $out.d") _p(" deps = gcc") _p("") _p("rule cxx") _p(" command = " .. wrap_ninja_cmd(tool.cxx .. " $defines $includes $flags -MMD -MF $out.d -c -o $out $in")) _p(" description = cxx $out") _p(" depfile = $out.d") _p(" deps = gcc") _p("") if cfg.flags.UseObjectResponseFile then _p("rule ar") _p(" command = " .. wrap_ninja_cmd(tool.ar .. " $flags $out @$out.rsp " .. (os.is("MacOSX") and " 2>&1 > /dev/null | sed -e '/.o) has no symbols$$/d'" or ""))) _p(" description = ar $out") _p(" rspfile = $out.rsp") _p(" rspfile_content = $in $libs") _p("") else _p("rule ar") _p(" command = " .. wrap_ninja_cmd(tool.ar .. " $flags $out $in $libs" .. (os.is("MacOSX") and " 2>&1 > /dev/null | sed -e '/.o) has no symbols$$/d'" or ""))) _p(" description = ar $out") _p("") end local link = iif(cfg.language == "C", tool.cc, tool.cxx) _p("rule link") local startgroup = '' local endgroup = '' if (cfg.flags.LinkSupportCircularDependencies) then startgroup = '-Wl,--start-group' endgroup = '-Wl,--end-group' end local rspfile_content = "$all_outputfiles $walibs " .. string.format("%s $libs %s", startgroup, endgroup) if cfg.flags.UseLDResponseFile then _p(" command = " .. wrap_ninja_cmd("$pre_link " .. link .. " -o $out @$out.rsp $all_ldflags $post_build")) _p(" description = link $out") _p(" rspfile = $out.rsp") _p(" rspfile_content = %s", rspfile_content) _p("") else _p(" command = " .. wrap_ninja_cmd("$pre_link " .. link .. " -o $out " .. rspfile_content .. " $all_ldflags $post_build")) _p(" description = link $out") _p("") end _p("rule exec") _p(" command = " .. wrap_ninja_cmd("$command")) _p(" description = Run $type commands") _p("") if #cfg.prebuildcommands > 0 then _p("build __prebuildcommands_" .. premake.esc(prj.name) .. ": exec") _p(1, "command = " .. wrap_ninja_cmd("echo Running pre-build commands && " .. table.implode(cfg.prebuildcommands, "", "", " && "))) _p(1, "type = pre-build") _p("") end cfg.pchheader_full = cfg.pchheader for _, incdir in ipairs(cfg.includedirs) do local abspath = path.getabsolute(path.join(cfg.project.location, cfg.shortname, incdir)) local testname = path.join(abspath, cfg.pchheader_full) if os.isfile(testname) then cfg.pchheader_full = path.getrelative(cfg.location, testname) break end end cpp.custombuildtask(prj, cfg) cpp.dependencyRules(prj, cfg) cpp.file_rules(prj, cfg, flags) local objfiles = {} for _, file in ipairs(cfg.files) do if path.issourcefile(file) then table.insert(objfiles, cpp.objectname(cfg, file)) end end _p('') cpp.linker(prj, cfg, objfiles, tool, flags) _p("") end function cpp.custombuildtask(prj, cfg) local cmd_index = 1 local seen_commands = {} local command_by_name = {} local command_files = {} local prebuildsuffix = #cfg.prebuildcommands > 0 and "||__prebuildcommands_" .. premake.esc(prj.name) or "" for _, custombuildtask in ipairs(prj.custombuildtask or {}) do for _, buildtask in ipairs(custombuildtask or {}) do for _, cmd in ipairs(buildtask[4] or {}) do local num = 1 for _, depdata in ipairs(buildtask[3] or {}) do cmd = string.gsub(cmd,"%$%(" .. num .."%)", string.format("%s ", path.getrelative(cfg.location, depdata))) num = num + 1 end cmd = string.gsub(cmd, '%$%(<%)', '$in') cmd = string.gsub(cmd, '%$%(@%)', '$out') local cmd_name -- shortened command name if seen_commands[cmd] == nil then local _, _, name = string.find(cmd, '([.%w]+)%s') name = 'cmd' .. cmd_index .. '_' .. string.gsub(name, '[^%w]', '_') seen_commands[cmd] = { name = name, index = cmd_index, } cmd_index = cmd_index + 1 cmd_name = name else cmd_name = seen_commands[cmd].name end local index = seen_commands[cmd].index if command_files[index] == nil then command_files[index] = {} end local cmd_set = command_files[index] table.insert(cmd_set, { buildtask[1], buildtask[2], buildtask[3], seen_commands[cmd].name, }) command_files[index] = cmd_set command_by_name[cmd_name] = cmd end end end _p("# custom build rules") for command, details in pairs(seen_commands) do _p("rule " .. details.name) _p(1, "command = " .. wrap_ninja_cmd(command)) end for cmd_index, cmdsets in ipairs(command_files) do for _, cmdset in ipairs(cmdsets) do local file_in = path.getrelative(cfg.location, cmdset[1]) local file_out = path.getrelative(cfg.location, cmdset[2]) local deps = '' for i, dep in ipairs(cmdset[3]) do deps = deps .. path.getrelative(cfg.location, dep) .. ' ' end _p("build " .. file_out .. ': ' .. cmdset[4] .. ' ' .. file_in .. ' | ' .. deps .. prebuildsuffix) _p("") end end end function cpp.dependencyRules(prj, cfg) local extra_deps = {} local order_deps = {} local extra_flags = {} for _, dependency in ipairs(prj.dependency or {}) do for _, dep in ipairs(dependency or {}) do local objfilename = cpp.objectname(cfg, path.getrelative(prj.location, dep[1])) local dependency = path.getrelative(cfg.location, dep[2]) if extra_deps[objfilename] == nil then extra_deps[objfilename] = {} end table.insert(extra_deps[objfilename], dependency) end end local pchfilename = cfg.pchheader_full and cpp.pchname(cfg, cfg.pchheader_full) or '' for _, file in ipairs(cfg.files) do local objfilename = file == cfg.pchheader and cpp.pchname(cfg, file) or cpp.objectname(cfg, file) if path.issourcefile(file) or file == cfg.pchheader then if #cfg.prebuildcommands > 0 then if order_deps[objfilename] == nil then order_deps[objfilename] = {} end table.insert(order_deps[objfilename], '__prebuildcommands_' .. premake.esc(prj.name)) end end if path.issourcefile(file) then if cfg.pchheader_full and not cfg.flags.NoPCH then local nopch = table.icontains(prj.nopch, file) if not nopch then local suffix = path.isobjcfile(file) and '_objc' or '' if extra_deps[objfilename] == nil then extra_deps[objfilename] = {} end table.insert(extra_deps[objfilename], pchfilename .. suffix .. ".gch") if extra_flags[objfilename] == nil then extra_flags[objfilename] = {} end table.insert(extra_flags[objfilename], '-include ' .. pchfilename .. suffix) end end end end cfg.extra_deps = extra_deps cfg.order_deps = order_deps cfg.extra_flags = extra_flags end function cpp.objectname(cfg, file) return path.join(cfg.objectsdir, path.trimdots(path.removeext(file)) .. ".o") end function cpp.pchname(cfg, file) return path.join(cfg.objectsdir, path.trimdots(file)) end function cpp.file_rules(prj,cfg, flags) _p("# build files") for _, file in ipairs(cfg.files) do _p("# FILE: " .. file) if cfg.pchheader_full == file then local pchfilename = cpp.pchname(cfg, file) local extra_deps = #cfg.extra_deps and '| ' .. table.concat(cfg.extra_deps[pchfilename] or {}, ' ') or '' local order_deps = #cfg.order_deps and '|| ' .. table.concat(cfg.order_deps[pchfilename] or {}, ' ') or '' local extra_flags = #cfg.extra_flags and ' ' .. table.concat(cfg.extra_flags[pchfilename] or {}, ' ') or '' _p("build " .. pchfilename .. ".gch : cxx " .. file .. extra_deps .. order_deps) _p(1, "flags = " .. flags['cxxflags'] .. extra_flags .. iif(prj.language == "C", "-x c-header", "-x c++-header")) _p(1, "includes = " .. flags.includes) _p(1, "defines = " .. flags.defines) _p("build " .. pchfilename .. "_objc.gch : cxx " .. file .. extra_deps .. order_deps) _p(1, "flags = " .. flags['objcflags'] .. extra_flags .. iif(prj.language == "C", "-x objective-c-header", "-x objective-c++-header")) _p(1, "includes = " .. flags.includes) _p(1, "defines = " .. flags.defines) elseif path.issourcefile(file) then local objfilename = cpp.objectname(cfg, file) local extra_deps = #cfg.extra_deps and '| ' .. table.concat(cfg.extra_deps[objfilename] or {}, ' ') or '' local order_deps = #cfg.order_deps and '|| ' .. table.concat(cfg.order_deps[objfilename] or {}, ' ') or '' local extra_flags = #cfg.extra_flags and ' ' .. table.concat(cfg.extra_flags[objfilename] or {}, ' ') or '' local cflags = "cflags" if path.isobjcfile(file) then _p("build " .. objfilename .. ": cxx " .. file .. extra_deps .. order_deps) cflags = "objcflags" elseif path.isasmfile(file) then _p("build " .. objfilename .. ": cc " .. file .. extra_deps .. order_deps) cflags = "asmflags" elseif path.iscfile(file) and not cfg.options.ForceCPP then _p("build " .. objfilename .. ": cc " .. file .. extra_deps .. order_deps) else _p("build " .. objfilename .. ": cxx " .. file .. extra_deps .. order_deps) cflags = "cxxflags" end _p(1, "flags = " .. flags[cflags] .. extra_flags) _p(1, "includes = " .. flags.includes) _p(1, "defines = " .. flags.defines) elseif path.isresourcefile(file) then end end _p("") end function cpp.linker(prj, cfg, objfiles, tool) local all_ldflags = ninja.list(table.join(tool.getlibdirflags(cfg), tool.getldflags(cfg), cfg.linkoptions)) local prebuildsuffix = #cfg.prebuildcommands > 0 and ("||__prebuildcommands_" .. premake.esc(prj.name)) or "" local libs = {} local walibs = {} local lddeps = {} if #cfg.wholearchive > 0 then for _, linkcfg in ipairs(premake.getlinks(cfg, "siblings", "object")) do local linkpath = path.rebase(linkcfg.linktarget.fullpath, linkcfg.location, cfg.location) table.insert(lddeps, linkpath) if table.icontains(cfg.wholearchive, linkcfg.project.name) then table.insert(walibs, table.concat(tool.wholearchive(linkpath), ' ')) else table.insert(libs, linkpath) end end else lddeps = premake.getlinks(cfg, "siblings", "fullpath") libs = lddeps end lddeps = ninja.list(lddeps) libs = ninja.list(libs) .. " " .. ninja.list(tool.getlinkflags(cfg)) walibs = ninja.list(walibs) local function writevars() _p(1, "all_ldflags = " .. all_ldflags) _p(1, "libs = " .. libs) _p(1, "walibs = " .. walibs) _p(1, "all_outputfiles = " .. table.concat(objfiles, " ")) if #cfg.prelinkcommands > 0 then _p(1, 'pre_link = echo Running pre-link commands && ' .. table.implode(cfg.prelinkcommands, "", "", " && ") .. " && ") end if #cfg.postbuildcommands > 0 then _p(1, 'post_build = && echo Running post-build commands && ' .. table.implode(cfg.postbuildcommands, "", "", " && ")) end end if cfg.kind == "StaticLib" then local ar_flags = ninja.list(tool.getarchiveflags(cfg, cfg, false)) _p("# link static lib") _p("build " .. cfg:getoutputfilename() .. ": ar " .. table.concat(objfiles, " ") .. " | " .. lddeps .. prebuildsuffix) _p(1, "flags = " .. ninja.list(tool.getarchiveflags(cfg, cfg, false))) _p(1, "all_outputfiles = " .. table.concat(objfiles, " ")) elseif cfg.kind == "SharedLib" or cfg.kind == "Bundle" then local output = cfg:getoutputfilename() _p("# link shared lib") _p("build " .. output .. ": link " .. table.concat(objfiles, " ") .. " | " .. lddeps .. prebuildsuffix) writevars() elseif (cfg.kind == "ConsoleApp") or (cfg.kind == "WindowedApp") then _p("# link executable") _p("build " .. cfg:getoutputfilename() .. ": link " .. table.concat(objfiles, " ") .. " | " .. lddeps .. prebuildsuffix) writevars() else p.error("ninja action doesn't support this kind of target " .. cfg.kind) end end local ninja = premake.ninja local swift = {} local p = premake function ninja.generate_swift(prj) local pxy = ninja.get_proxy("prj", prj) local tool = premake.gettool(prj) local platforms = premake.filterplatforms(prj.solution, tool.platforms, "Native") for _, platform in ipairs(platforms) do for cfg in p.eachconfig(pxy, platform) do p.generate(cfg, cfg:getprojectfilename(), function() swift.generate_config(prj, cfg) end) end end end function swift.generate_config(prj, cfg) local tool = premake.gettool(prj) local flags = { swiftcflags = ninja.list(tool.getswiftcflags(cfg)), swiftlinkflags = ninja.list(tool.getswiftlinkflags(cfg)), } _p("# Swift project build file") _p("# generated with GENie ninja") _p("") _p("ninja_required_version = 1.7") _p("") _p("out_dir = %s", cfg.buildtarget.directory) _p("obj_dir = %s", path.join(cfg.objectsdir, prj.name .. ".build")) _p("target = $out_dir/%s", cfg.buildtarget.name) _p("module_name = %s", prj.name) _p("module_maps = %s", ninja.list(tool.getmodulemaps(cfg))) _p("swiftc_flags = %s", flags.swiftcflags) _p("swiftlink_flags = %s", flags.swiftlinkflags) _p("ar_flags = %s", ninja.list(tool.getarchiveflags(cfg, cfg, false))) _p("ld_flags = %s", ninja.list(tool.getldflags(cfg))) if cfg.flags.Symbols then _p("symbols = $target.dSYM") symbols_command = string.format("&& %s $target -o $symbols", tool.dsymutil) else _p("symbols = ") symbols_command = "" end local sdk = tool.get_sdk_path(cfg) if sdk then _p("toolchain_path = %s", tool.get_toolchain_path(cfg)) _p("sdk_path = %s", sdk) _p("platform_path = %s", tool.get_sdk_platform_path(cfg)) _p("sdk = -sdk $sdk_path") else _p("sdk_path =") _p("sdk =") end _p("") _p("# core rules for %s", cfg.name) _p("rule swiftc") _p(1, "command = %s -frontend -c $in -enable-objc-interop $sdk -I $out_dir $swiftc_flags -module-cache-path $out_dir/ModuleCache -D SWIFT_PACKAGE $module_maps -emit-module-doc-path $out_dir/$module_name.swiftdoc -module-name $module_name -emit-module-path $out_dir/$module_name.swiftmodule -num-threads 8 $obj_files", tool.swift) _p(1, "description = compile $out") _p("") _p("rule swiftlink") _p(1, "command = %s $sdk -L $out_dir -o $out $swiftlink_flags $ld_flags $in %s", tool.swiftc, symbols_command) _p(1, "description = create executable") _p("") _p("rule ar") _p(1, "command = %s cr $ar_flags $out $in %s", tool.ar, (os.is("MacOSX") and " 2>&1 > /dev/null | sed -e '/.o) has no symbols$$/d'" or "")) _p(1, "description = ar $out") _p("") local objfiles = {} for _, file in ipairs(cfg.files) do if path.isswiftfile(file) then table.insert(objfiles, swift.objectname(cfg, file)) end end swift.file_rules(cfg, objfiles) _p("") swift.linker(prj, cfg, objfiles, tool) end function swift.objectname(cfg, file) return path.join("$obj_dir", path.getname(file)..".o") end function swift.file_rules(cfg, objfiles) _p("build %s: swiftc %s", ninja.list(objfiles), ninja.list(cfg.files)) _p(1, "obj_files = %s", ninja.arglist("-o", objfiles)) end function swift.linker(prj, cfg, objfiles, tool) local lddeps = ninja.list(premake.getlinks(cfg, "siblings", "fullpath")) if cfg.kind == "StaticLib" then _p("build $target: ar %s | %s ", ninja.list(objfiles), lddeps) else local lddeps = ninja.list(premake.getlinks(cfg, "siblings", "fullpath")) _p("build $target: swiftlink %s | %s", ninja.list(objfiles), lddeps) end end local ninja = premake.ninja local swift = { } local p = premake function ninja.generate_swift_incremental(prj) local pxy = ninja.get_proxy("prj", prj) local tool = premake.gettool(prj) local platforms = premake.filterplatforms(prj.solution, tool.platforms, "Native") for _, platform in ipairs(platforms) do for cfg in p.eachconfig(pxy, platform) do p.generate(cfg, cfg:getprojectfilename(), function() swift.generate_config(prj, cfg) end) end end end function swift.generate_config(prj, cfg) local tool = premake.gettool(prj) local flags = { swiftcflags = ninja.list(table.join(tool.getswiftcflags(cfg), cfg.buildoptions_swiftc)), } _p("# Swift project build file") _p("# generated with GENie ninja") _p("") _p("ninja_required_version = 1.7") _p("") _p("out_dir = %s", cfg.buildtarget.directory) _p("obj_dir = %s", path.join(cfg.objectsdir, prj.name .. ".build")) _p("module_name = %s", prj.name) _p("module_maps = %s", ninja.list(tool.getmodulemaps(cfg))) _p("swiftc_flags = %s", flags.swiftcflags) _p("swiftlink_flags = %s", flags.swiftlinkflags) _p("ar_flags = %s", ninja.list(tool.getarchiveflags(cfg, cfg, false))) local sdk = tool.get_sdk_path(cfg) if sdk then _p("toolchain_path = %s", tool.get_toolchain_path(cfg)) _p("sdk_path = %s", sdk) _p("platform_path = %s", tool.get_sdk_platform_path(cfg)) _p("sdk = -sdk $sdk_path") _p("ld_baseflags = -force_load $toolchain_path/usr/lib/arc/libarclite_macosx.a -L $out_dir -F $platform_path/Developer/Library/Frameworks -syslibroot $sdk_path -lobjc -lSystem -L $toolchain_path/usr/lib/swift/macosx -rpath $toolchain_path/usr/lib/swift/macosx -macosx_version_min 10.10.0 -no_objc_category_merging") else _p("sdk_path =") _p("sdk =") _p("ld_baseflags =") end _p("") _p("# core rules for %s", cfg.name) _p("rule swiftc") _p(1, "command = %s -frontend -c -primary-file $in $files $target -enable-objc-interop $sdk -I $out_dir -enable-testing -module-cache-path $out_dir/ModuleCache -D SWIFT_PACKAGE $module_maps -emit-module-doc-path $out_doc_name swiftc_flags -module-name $module_name -emit-module-path $out_module_name -emit-dependencies-path $out.d -emit-reference-dependencies-path $obj_dir/$basename.swiftdeps -o $out", tool.swiftc) _p(1, "description = compile $out") _p("") _p("rule swiftm") _p(1, "command = %s -frontend -emit-module $in $parse_as_library swiftc_flags $target -enable-objc-interop $sdk -I $out_dir -F $platform_path/Developer/Library/Frameworks -enable-testing -module-cache-path $out_dir/ModuleCache -D SWIFT_PACKAGE $module_maps -emit-module-doc-path $out_dir/$module_name.swiftdoc -module-name $module_name -o $out", tool.swift) _p(1, "description = generate module") _p("") _p("rule swiftlink") _p(1, "command = %s $target $sdk $swiftlink_flags -L $out_dir -o $out_dir/$module_name -F $platform_path/Developer/Library/Frameworks $in", tool.swiftc) _p(1, "description = linking $target") _p("") _p("rule ar") _p(1, "command = %s cr $ar_flags $out $in $libs %s", tool.ar, (os.is("MacOSX") and " 2>&1 > /dev/null | sed -e '/.o) has no symbols$$/d'" or "")) _p(1, "description = ar $out") _p("") _p("rule link") _p(" command = %s $in $ld_baseflags $all_ldflags $libs -o $out", tool.ld) _p(" description = link $out") _p("") swift.file_rules(cfg, flags) local objfiles = {} local modfiles = {} local docfiles = {} for _, file in ipairs(cfg.files) do if path.issourcefile(file) then table.insert(objfiles, swift.objectname(cfg, file)) table.insert(modfiles, swift.modulename(cfg, file)) table.insert(docfiles, swift.docname(cfg, file)) end end _p("") swift.linker(prj, cfg, {objfiles, modfiles, docfiles}, tool, flags) _p("") end function swift.objectname(cfg, file) return path.join("$obj_dir", path.getname(file)..".o") end function swift.modulename(cfg, file) return path.join("$obj_dir", path.getname(file)..".o.swiftmodule") end function swift.docname(cfg, file) return path.join("$obj_dir", path.getname(file)..".o.swiftdoc") end function swift.file_rules(cfg, flags) _p("# build files") local sfiles = Set(cfg.files) for _, file in ipairs(cfg.files) do if path.issourcefile(file) then if path.isswiftfile(file) then local objn = swift.objectname(cfg, file) local modn = swift.modulename(cfg, file) local docn = swift.docname(cfg, file) _p("build %s | %s %s: swiftc %s", objn, modn, docn, file) _p(1, "out_module_name = %s", modn) _p(1, "out_doc_name = %s", docn) _p(1, "files = ".. ninja.list(sfiles - {file})) build_flags = "swiftcflags" end _p(1, "flags = " .. flags[build_flags]) elseif path.isresourcefile(file) then end end _p("") end function swift.linker(prj, cfg, depfiles, tool) local all_ldflags = ninja.list(table.join(tool.getlibdirflags(cfg), tool.getldflags(cfg), cfg.linkoptions)) local lddeps = ninja.list(premake.getlinks(cfg, "siblings", "fullpath")) local libs = lddeps .. " " .. ninja.list(tool.getlinkflags(cfg)) local function writevars() _p(1, "all_ldflags = " .. all_ldflags) _p(1, "libs = " .. libs) end local objfiles, modfiles, docfiles = table.unpack(depfiles) _p("build $out_dir/$module_name.swiftmodule | $out_dir/$module_name.swiftdoc: swiftm %s | %s", table.concat(modfiles, " "), table.concat(docfiles, " ")) _p("") local output = cfg:getoutputfilename() if cfg.kind == "StaticLib" then local ar_flags = ninja.list(tool.getarchiveflags(cfg, cfg, false)) _p("build %s: ar %s | %s $out_dir/$module_name.swiftmodule $out_dir/$module_name.swiftdoc", output, table.concat(objfiles, " "), lddeps) _p(1, "flags = %s", ninja.list(tool.getarchiveflags(cfg, cfg, false))) elseif cfg.kind == "SharedLib" then _p("build %s : swiftlink %s | %s $out_dir/$module_name.swiftmodule $out_dir/$module_name.swiftdoc", output, table.concat(objfiles, " "), libs) writevars() elseif (cfg.kind == "ConsoleApp") or (cfg.kind == "WindowedApp") then _p("build %s: swiftlink %s | %s $out_dir/$module_name.swiftmodule $out_dir/$module_name.swiftdoc", output, table.concat(objfiles, " "), lddeps) else p.error("ninja action doesn't support this kind of target " .. cfg.kind) end end newaction { trigger = "jcdb", shortname = "compile_commands.json", description = "Generate a compile_commands.json file.", valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Bundle" }, valid_languages = { "C", "C++" }, valid_tools = { cc = { "gcc" } }, onsolution = function(sln) local jsonpath = path.join(sln.location, "compile_commands.json") premake.generate(sln, jsonpath, premake.jcdb.generate) end, } premake.jcdb = {} local premake = premake local jcdb = premake.jcdb local encode_chars = { [0x22] = '\\"', [0x5c] = "\\\\", [0x08] = "\\b", [0x0c] = "\\f", [0x0a] = "\\n", [0x0d] = "\\r", [0x09] = "\\t", } local function encode_string(s) local res = '"' for _, cp in utf8.codes(s) do if encode_chars[cp] then res = res..encode_chars[cp] elseif cp < 32 then res = res..string.format("\\u%04x", cp) else res = res..utf8.char(cp) end end return res..'"' end local function escape_cmdline_arg(s) if s:find("%s") then s = s:gsub("\\", "\\\\") s = s:gsub('"', '\\"') s = '"'..s..'"' end return s end local function list(tbl) return iif(#tbl > 0, " "..table.concat(tbl, " "), "") end local function build_command(cfg, cc, file) local cmdline = "" local function app(s) cmdline = cmdline..s end if path.iscfile(file) or path.isasmfile(file) then app(cc.cc) else app(cc.cxx) end app(list(cc.getcppflags(cfg))) app(list(cc.getdefines(cfg.defines))) app(list(cc.getincludedirs(cfg.includedirs))) app(list(cc.getquoteincludedirs(cfg.userincludedirs))) app(list(cc.getsystemincludedirs(cfg.systemincludedirs))) app(list(cc.getcflags(cfg))) if path.iscppfile(file) then app(list(cc.getcxxflags(cfg))) end if path.isasmfile(file) then app(list(cfg.buildoptions)) app(list(cfg.buildoptions_asm)) elseif path.isobjcfile(file) then local opts = iif(path.iscfile(file), cfg.buildoptions_objc, cfg.buildoptions_objcpp) app(list(cc.getobjcflags(cfg))) app(list(cfg.buildoptions)) app(list(opts)) elseif path.iscfile(file) then app(list(cfg.buildoptions)) app(list(cfg.buildoptions_c)) else app(list(cfg.buildoptions)) app(list(cfg.buildoptions_cpp)) end if cfg.pchheader and not cfg.flags.NoPCH then app(" -include ") app(escape_cmdline_arg(cfg.pchheader)) end for _, i in ipairs(cfg.forcedincludes) do app(" -include ") app(escape_cmdline_arg(i)) end local base = path.trimdots(path.removeext(file))..".o" local output = path.join(cfg.objectsdir, base) app(" -o ") app(escape_cmdline_arg(output)) app(" -c ") app(escape_cmdline_arg(file)) return cmdline end function jcdb.generate_config(prj, cfg, cc) table.sort(cfg.files) local directory = path.getabsolute(prj.location) for _, file in ipairs(cfg.files) do if path.iscppfile(file) or path.isasmfile(file) then _p(' { "directory": %s,', encode_string(directory)) _p(' "command": %s,', encode_string(build_command(cfg, cc, file))) _p(' "file": %s },', encode_string(file)) end end end function jcdb.generate_project(prj) local cc = premake.gettool(prj) local platforms = premake.filterplatforms(prj.solution, cc.platforms, "Native") for _, platform in ipairs(platforms) do for cfg in premake.eachconfig(prj, platform) do jcdb.generate_config(prj, cfg, cc) end end end function jcdb.generate(sln) for _, prj in ipairs(sln.projects) do jcdb.generate_project(prj) end io.captured = io.captured:gsub(",%s$", "") io.captured = "["..io.eol..io.captured..io.eol.."]" end _WORKING_DIR = os.getcwd() local function injectplatform(platform) if not platform then return true end platform = premake.checkvalue(platform, premake.fields.platforms.allowed) for sln in premake.solution.each() do local platforms = sln.platforms or { } if #platforms == 0 then table.insert(platforms, "Native") end if not table.contains(platforms, "Native") then return false, sln.name .. " does not target native platform\nNative platform settings are required for the --platform feature." end if not table.contains(platforms, platform) then table.insert(platforms, platform) end sln.platforms = platforms end return true end function _premake_main(scriptpath) if (scriptpath) then local scripts = dofile(scriptpath .. "/_manifest.lua") for _,v in ipairs(scripts) do dofile(scriptpath .. "/" .. v) end end local profiler = newProfiler() if (nil ~= _OPTIONS["debug-profiler"]) then profiler:start() end _PREMAKE_COMMAND = path.getabsolute(_PREMAKE_COMMAND) premake.action.set(_ACTION) math.randomseed(os.time()) if (nil ~= _OPTIONS["file"]) then local fname = _OPTIONS["file"] if (os.isfile(fname)) then dofile(fname) else error("No genie script '" .. fname .. "' found!", 2) end else local dir, name = premake.findDefaultScript(path.getabsolute("./")) if dir ~= nil then local cwd = os.getcwd() os.chdir(dir) dofile(name) os.chdir(cwd) end end if (_OPTIONS["version"] or _OPTIONS["help"] or not _ACTION) then printf("GENie - Project generator tool %s", _GENIE_VERSION_STR) printf("https://github.com/bkaradzic/GENie") if (not _OPTIONS["version"]) then premake.showhelp() end return 1 end action = premake.action.current() if (not action) then error("Error: no such action '" .. _ACTION .. "'", 0) end ok, err = premake.option.validate(_OPTIONS) if (not ok) then error("Error: " .. err, 0) end ok, err = premake.checktools() if (not ok) then error("Error: " .. err, 0) end ok, err = injectplatform(_OPTIONS["platform"]) if (not ok) then error("Error: " .. err, 0) end print("Building configurations...") premake.bake.buildconfigs() ok, err = premake.checkprojects() if (not ok) then error("Error: " .. err, 0) end premake.stats = { } premake.stats.num_generated = 0 premake.stats.num_skipped = 0 printf("Running action '%s'...", action.trigger) premake.action.call(action.trigger) if (nil ~= _OPTIONS["debug-profiler"]) then profiler:stop() local filePath = path.getabsolute("GENie-profile.txt") print("Writing debug-profile report to ''" .. filePath .. "'.") local outfile = io.open(filePath, "w+") profiler:report(outfile, true) outfile:close() end printf("Done. Generated %d/%d projects." , premake.stats.num_generated , premake.stats.num_generated+premake.stats.num_skipped ) return 0 end 44Xa! LLL t<:AN-    '   4   `  #;lc!ccLs9 !!0"Y" ##<$$$-%x%%%?&&&'.(|(($)f)}*,,--?../113'44"6I7~77789|:0; <Z<<>r>Z?@AdBBEDEEEFHHHH!IIeJJ,L]LxLLMNNNOP6QQQRyTTDUUXVVW7ZZ0\\]]^`__L```Vaza){ 5kˑ"pߚF*!Cp C{өjɱkO۳":X%0N%c>ٻwڽ2=R]v+U ;<.R *K4a=OhPDwXaB<o\),b   g  1xHte,,,9.d..011622 33445S66888/9~:;H;;}>??{@@BBCEbFqFLMQQRR%TUCV__kghhhknLqqvv=wwx{}}Lonˇ<v/h?lh8d}â pI@ `qpgj-/.X-m[*3zRx $AC F$D AC $lFAC $AC $FC $&NC $ AC $4PAC $\AC I$zAC $mAC F$_$AC C$[!AC $$TAC $LAAC $t8AC $&.AC $,AC $ AC $YAC F$<HIAC B,diAC G$)AC B$QAC B$NAC B$ )AC ,4AC G$dv@AC $&AC $+AC $AC $tAC C$,AC $TAC $|AC $YAC F$fAC C$+>AC F$AAC J$DAC F$lGAC $>AC $/)AC ,0wAC G$w5AC B,<eAC G$lIAC C$6AC C$HAC F$RAC G$ 2qAC F$4{iAC B$\<AC B,sAC G$1AC B,fAC G$ RIAC C$4 slAC C$\ kAC F$ |AC I$ NAC F$ [AC B$ jAC C,$ 5AC M$T AC ,| AC K$ k,AC $ o AC , Q/AC G$, x AC $T YBAC B$| sbAC C$ )AC B$ AC $ AC $ GAC C$D VAC F$l AC , DAC M$ `AC F, AC JzRx ,pAC P,L@!AC N$|1AC L$AC F$AC J,AC G$$iAC F$LAC C$t0)AC B,1vAC G,w;AC G$AC F,$AC J,T\[AC G$FAC F$PAC C$KAC F$2AC C$$UAC I$L'@AC G,t?yAC K$?AC F,AC G$+8AC F$$;CAC F$LVNAC C$t|AC ,bAC J$AC $&AC $AC F$DQ\EC F,lAC P,YpAC G,AC J$UAC C$$F(AC $LF!AC $t?BAC G$YyAC F$dAC F$[AC F,4AC G$D4AC F,lAC J,AC J$9AC F,AC J,$uAC G,TSAC G,'AC P$ 5AC B$QC $ @AC C,, ##AC GzRx $AC C$D;AC B$lAC B$AC F$lAC C$pAC C$ NAC B$4BjAC C,\oAC G,AC K$SAC C$AC B$ hAC B,4B-AC J$d?HAC B$_SAC B$KAC B$XAC B,AC G$4LAC C,\AC M$.AC B$AC C$ AC $QAC F$,cAC F$TVxAC C$|AC C$>@AC CzRx $>AC zRx $AC A$DAC $lEAC F$AC $HAC $AC $  AC $4-AC $\AC ,w~AC J$NAC $JAC $ AC F$,`AC F$T1AC $|AC C$'AC ,@AC M$2AC $$AC B$LgSAC $tAC B$(VAC C,V0AC J$V_AC F$AC $D~AC $lnAC G,pAC G,AC G$uAC C$VAC $DAC F$lpAC C$3AC B$AC G,AC M$7QAC ,<`RAC G,lAC J$uAC $bAC F$AC $AC I$<8bAC $dr=AC C$MAC CzRx $GAC B$DKAC C$lxAC F$&$AC B$"AC J$.AC B$ "AC B$4$AC B$\8AC C$AC F$~AC CzRx $GAC B,DdAC P$t8AC B$)AC I,jAC P,X,AC N$$T AC $LA 8AC B$tQ AC $8 AC F$ >AC B$ KAC B, AC M,D AC P$tf VAC B$ #AC B, AC J$ CAC C$ AC C$Dj JAC C$l AC F, _AC GzRx $NAC $D& AC $l  AC $ AC $ NAC $ iAC B, ;AC J$<=AC B,d AC M$AAC F$AC H$AC G$  AC ,4LAC K$dSAC F$EAC $/\AC B$cAC I,?AC G,4AC J$d_AC BzRx $AC C$DB_AC C,ly~AC N,AC M$|AC B$AC F,mAC P,L1kAC J$|l AC F$ AC C,O!oAC J$"AC B$$Q#RAC C$L{#AC $tf#AC ,#AC M,0$AC K$$AC F$$]%6AC C$Lk%`AC B$t%WAC FzRx ,%AC M,Ly'AC J$|+AC GzRx $h,'AC B$Dg,SAC C$l,\AC F$,AC F$7-gAC C$v-@AC $ -AC C$4 .BAC zRx $ .)AC $D .AC C$l.AC $.'AC $.&AC $.:AC C$ ."AC ,4.AC G,d\/AC G,/nAC J$h1:AC F,z1VAC M,5#AC G$L6_AC F$t6AC F,7BAC M$8AC ,8AC J,$@>ZAC G$Tj>4AC C$|v>4AC C,>_AC J$?<AC B$?fAC F,$@AC M,T@AC GzRx $@GAC CzRx $AAC B,DAAC J$t&BgAC B$eB5AC B$rBAC $hBAC C, C AC J$DCAC ,lCAC G$SD+AC B$VDqAC F$DkAC B$D+AC B$<D>AC C$dDZAC F$-EAC F,EAC J$E:AC B$ FdAC F,4?FcAC K,drGAC P,&LtAC P,jMYAC G$M]AC B$M2AC B,DMAC J$tN.AC B$N$AC B$N$AC B$NAC F$OvAC F$<UO3AC C$d`O]AC B$OWAC B$OMAC BzRx ,OqAC J$LPRAC $t?P AC ,#PAC K$PAC F$QAC B$_QDAC B,D{Q AC M$tx\AC B$l\yAC F$\AC C$]AC F,]xAC G$D^=AC B,l^AC M$`SFC C$`_AC B$`UAC B$a2AC zRx $ aAC C$DaZAC B$la,AC B$a,AC B$aNAC B$bLAC B$ @b,AC B$4Db/AC B$\Kb,AC B$ObUAC G$|bLAC B$bAC G$Cc?AC C$$ZcAC E,LcAC G,|0dAC G$dAC E$d/AC B,d AC K$,e!AC $Te,AC B$|e+AC B$e,AC B$efAC B$,f-AC zRx $f_AC C,DPf}AC J$tfAC zRx $ofAC F,D`hAC J$tibAC C$RiAC F,iAC J$>jAC B,jZAC G,LkAC P$|m_AC C$Om^AC C$mqAC F$mAC F,nmAC G$LntAC F,t oAC G,oAC N,[qIAC PzRx $\s7AC $Dks!AC $lds9eC ,usAC M$5uoHC $uAC $tv#AC ,<ovAC K$lwhAC ,xAC K,xiAC M$|AC ,L}6AC JzRx $:~GAC B$DY~CAC B,lt~AC P$AAC C$EAC C$9hAC C$y4AC B$<8AC C$dIAC C$_AC C$AAC G$yAC E,WAC KzRx ,AC P,LVAC J$|#VAC F,QPAC G,qfAC G,; AC M$4RAC E,\2~AC J$,AC B,lAC G$AC , AC J,<+HAC M,lԚ"AC M,ƜAC M,8XAC M,`AC M$,<AC C$TOAC ,|8IAC J$Q+AC $TfAC I,8AC M,,AC K,\AC G$_AC F$QAC B,AC J, waAC G,<AC J$lKAC $3AC F$EAC G$2AC C, MAC M$<ۧAC F,dHAC MzRx $AC $D2AC B$l?AC C,ϩYAC G,AC G$AC B$DAC F$D8CAC B,lSAC M,AC M$AC C$CAC zRx $4AC $D$9AC ,l5AC J$9AC , AC M$'AC C$RAC BzRx $AC B,DLAC J,t6AC P,вAC N$jAC ,QAC P$,d[AC B,TAC P$8AC G,AC N$ AC ,yAC P$4ͿAC L$\LAC F,AC N,k2AC P,AC M,6)AC M$DTAC ,l<AC P,AC J,pAC J,vAC J$,AC F,TAC J$OAC $AC F$<AC F,UAC J,,%AC P,\AC M,~AC J$AC F$DjAC B, AC MzRx ,4AC J,LAC M,|AC J,\AC K$JAC F$'AC $,;AC $TcAC C,|*AC P$AC F$bAC $KAC ,$=AC K,TAC G$DAC BzRx $GAC B,D0AC P,tAC M$AC F,)AC M,AC M,,AC M$\AC G$pAC C$qAC F,dAC M$AC FzRx $IZAC F$D{/AC C$l\AC $AC F,GvAC J,AC K$ FAC BzRx $(AC I,DeAC J,tLAC M$.AC B,_AC K$-AC B$$AC GzRx $)oAC B,Dp}AC J,tSAC M,AC N,k(AC J$cIAC B$,AC $TPAC F$|AC IzRx $}AC I$D AC ,lAC M,uAC M,C`AC M$sAC F,$AC J$TwAC F,|=AC K,pAC M,WAC G$ BqC $4ESC $\ 1AC ,)_AC J,AC PzRx $&GAC B$D'AC ,l&AC G$P'@AC CzRx $P'mAC FzRx ,}'AC GzRx $'AC JzRx $(AC zRx $'hAC HzRx $(YAC J$DI(4AC zRx ,=(AC J$L)CAC B$t )/AC B$')AC L$)AC FzRx $)rAC FzRx ,*fAC JzRx $:+mAC FzRx $g+AC LzRx $),TAC GzRx ,=,AC PzRx $-sAC JzRx $*.AC LzRx $v.*AC $Dx.@IC F,l/AC PzRx $0@AC CzRx $0AC B,D12AC P$t4AC LzRx ,6pAC GzRx ,*6AC JzRx ${6tAC B$D6>AC 8@HP0x",6@JT^hr|&0:DNXblv  *4>HR\fpz$.8BLV`jt~ MtN"(O)O/P<RPCPL+QQRVjR\RbRShTqTxUeUU\VVY  L G Dt$ * - Z0 V7 3< : Fxj p v 2| P ( F%  j p  | 8%\gl tJy} ` f  [ $'*-0369?HRY f X4K&J"Co"< kP ~ #'+/37;@EINRVZ_cgnrux{) FU{}WXYZZiZ`aeeffhhi;jofpODVtg×]bf6fD8L0 $ 8SZ%%%'%%X%%%%i%h%%_%0%&&&$&b*&/&5&%:& ` ݭ0! y&6zI)LV \e^kox|KBu*CJe-~bZ$u,*(A0TqBF24TpL[,q<{  12 >"UFp`lA`+AppXB^B` B`B`B`BSASA`%A`/ApppWApTBTB`/A`B\B`"B^B[AVB`"BRB[C`D@__DefaultRuneLocaleQr0@___stack_chk_guard@___stderrp@___stdinp@___stdoutp@dyld_stub_binderrh@_CFBundleCopyExecutableURLrp@_CFBundleGetMainBundlerx@_CFStringGetCStringr@_CFURLCopyFileSystemPathr@___bzeror@___errorr@___maskruner@___memcpy_chkr@___sprintf_chkr@___srgetr@___stack_chk_failr@___strcpy_chkr@___strncpy_chkr@___tolowerr@___toupperr@__longjmpr@__setjmpr@_abortr@_acosr@_asinr@_atan2r@_ceilr@_chdirr@_clearerrr@_clockr@_closer@_closedirr@_cosr@_difftimer@_dlcloser@_dlerrorr@_dlopenr@_dlsymr@_exitr@_expr@_fcloser@_feofr@_ferrorr@_fflushr@_fgetsr@_flockfiler@_floorr@_fmodr@_fnmatchr@_fopenr@_fprintfr@_fputsr@_freadr@_freer@_freopenr@_frexpr@_fseekor@_ftellor@_funlockfiler@_fwriter@_getcr@_getcwdr@_getenvr@_gettimeofdayr@_gmtime_rr@_localeconvr@_localtime_rr@_logr@_log10r@_mallocr@_memchrr@_memcmpr@_memcpyr@_mkdirr@_mkstempr@_mktimer@_opendir$INODE64r@_pcloser@_popenr@_powr@_putsr@_randr@_randomr@_readdir$INODE64r@_reallocr@_remover@_renamer@_rmdirr@_setlocaler@_setvbufr@_sinr@_sprintfr@_srandomr@_stat$INODE64r@_strchrr@_strcmpr@_strcollr@_strcpyr@_strerrorr@_strftimer@_strlenr@_strncmpr@_strncpyr@_strpbrkr@_strrchrr@_strspnr@_strstrr@_strtodr@_systemr@_tanr@_timer@_tmpfiler@_ungetc_ start _wluaos_'do_)p*is_absolute_path*get_*main+string_+builtin_scripts,NXArg,environ,mh_execute_header_progname,'_L_ open_K_G_D_U_F_C_X_M_O_Y_parser!E_!S_"H_#T_$V_%Z_'i_ctype_,P_op,cxmoveaversiongsrptil dump error ne upvalue yieldkheckstackoreatetable allk lose"()tpanicbsindexrith***etc tglobal field i metatable u allocf hookstacklocalopable *ett tglobal field i metatable u allocf hooklocalopable +otateawesume+pymparencat .ushcallk vn integer l string fstring cclosure boolean thread aluefstring /ypeo/name/sdent+cfunctionintegernumberstringuserdatayieldable/0000equallen get set 112ringtonumberatus 3numberxintegerxbooleanlstring cfunction userdata thread pointer 345567777il umber 999string ightuserdata 9:;;=>>>??@AnfoAi p BBCDservalue pvalue EEFFGHi p HIJservalue pvalue LLMoad en OQQQTxt w TTUUVuserdata thread"state"VVXid join ZZt a e where fileresult new setcoppbuffinitreunreflgraceback estudataolstring\rgerror ddbrror xecresult dgijmetatablestatekmetatablefuncsllheckallmeta udataoptionlstringstacktypeanynumberintegerversion_motenliblstringnumberintegerpqqrrssturepbuffsizeushulstringstringvaluewwresultmodulexsizexyzsizezfquirefz|oadenfilexbufferxstring|etsubmetafieldsubtableֆs bcoroutinedebugiomathpackageos!string#table$utf8%aseit32 nilcjumpregpsindischargevarsexp2fixlineoheckstackdencatABkCxԹtserveregsetlabeloifatchrefixosfixlisttoherecloseɻݼĿteringKorevartKdexedfixtlfreturnsoneretlistnextreganyregvalRKuptruefalsemaskcountԒtrunerrorconcaterroroerrormsgypeerrorointerrorraceexecpinterrorrdererror¡throwrgrowstackshrinkstackhookpcallawrunprotectedeallocstackroscallcallecallotectedparserǿdumpundump%newinitupvalsfclosegetlocalnameCclosureLclosureprotoindupvalreeprotobarrierupvfnewobjcheckfinalizerruntilstatestep_back_albarrier_deccountixreeallobjectsullgcӏinittoken2strsnelookaheadĹyntaxerroretinputwstringxtʼнϾgrowaux_realloc_toobig int2fb fb2int c arith hexavalue str2num utf8esc tostring push!nilobject_,eillog2 hunkid!ŗĞԢvfstring!fstring!ڰs!extendCI!free!etdebt!hrinkCI"CI"thread"eqlngstr"hash"re"new"Ħsize"move"lstr""udata#ne#resize#set#free$get$xt#w#Őarray#int##ܖkey$int$str$$n$init$gettm$call$t%byobj$TM%binTM%orderTM%rybinTM%ypenames_, to&gettable&s&less&e&concat'objlen'div'mod'finishOp'number_&integer_&ettable&hiftl'than&equal&qualobj'xecute'fill'init'read'openspace' c(getcwd(is(m)pathsearch*rmdir*stat*ticks*uuid*hdir(opyfile(64bit(dir(file)isfile)hash+atch)kdir)start)done)n)isfile)ame)ext)ath_*remake_+get*isabsolute+absolute*relative*absolute_path+relative_path+init+execute+locate+endswith+hash+modes,names,c,v,ȬЬ'< F&Pzm$!.YI)QN)@&+Yf>)w5eI6HRqiKV#CJ_N Ni= A LSE\__~|R6`W 'S\g@B)'&:":_ Z44Z:d Y]2.$$v3]WPqR Dy=S_U2Z,,NL,/,UL?/!,+,f-_}b_^qmt7!9#hGCAEh48I_yVfR~,l ^m{J\k ck<26!-c)å4 BN`kw;s˽.bc G $.82BPLU(`Fjs[6 o*  8)\19DMS_tku{Un#M f  *X4>HT4`kKu&J"Co,` H  <& 1 o> J P\ j  v ~ Y  :     \     )!!!&!F4!=!I!_ S!"_!#i!)$u!y%!%!p1!1!@2!l2!2!2!4!t9!;!8>!?"]@ "@"@*"1B5"\B?"BI"CT"Db"~Ek"Ev".F"F"G"G"G"H"H"H"KJ"J"vN"@O#|Q #uR#W##X-#Y7#ZZA#iZM#`U#a_#eh#es#f~#f#h#h#i#;j#o#fp#s#s#{v#}z#z$c{${$$|1$|>$,O$Z$*f$Or$&{$Ƃ$D$$̉$$$D$t$g$$×$$f$%Û%4%ߟ#%1%$?%F%تR%7]%di%`u%ݭ%0%%%\%%7%%%8%` &&%&2&B&I&@^&p&z&&8&D&&& & `& & 0& @' ' ' P&' p;' H' Q' [' e' @' ' ' ' ' @' ' `' ' (X8 @P2 CLWH`Ps&dx;߱h%9KAVf5q})LLN#L1'M@׮L>\~l"h>#o&,6@FQ[hsj\E5$`\]_-]b2e?.ePeccuep]iqhPj/na\\]^ ]],n9jFU`Xu]bgm q{b bfp`;;<1=8=B)p987:K8^9p78%96G1254yB HJ&VC0ABu>R7Bc5vAKF:489:D&< t<^=(+I7HF(6YQ6iCy.>3Y5  $k  D 4  00 B !U gc Tr  @  p S DS wV T V sT }S n ' `& 2 C N ]  n y  h A    ]     [ Ⱦ* u; K V f Jv O   5   8    H   [&! 41 R< 9I [*U 2_ !p (z * ( * ,          " . < nH [+X "j u   . \ x s * ' O M+*&):L]n>%W !X!(F4$@$M$Zǟfr+d#"@#Tf%3#D,&(1@QHap -k-*L#[2DtEFxT`3nZzGV"Xih_0-;JTcbmv%'%Se+ ,CWp *5@JSZ`fmsz$-4;AJQYanv|!&,2:KT\dkv %*09A      !"#$%&'@(      !"#$%&' _NXArgc_NXArgv___progname__mh_execute_header_builtin_scripts_do_hash_do_isfile_environ_get_absolute_path_get_relative_path_is_absolute_path_luaC_barrier__luaC_barrierback__luaC_checkfinalizer_luaC_fix_luaC_freeallobjects_luaC_fullgc_luaC_newobj_luaC_runtilstate_luaC_step_luaC_upvalbarrier__luaC_upvdeccount_luaD_call_luaD_growstack_luaD_hook_luaD_pcall_luaD_poscall_luaD_precall_luaD_protectedparser_luaD_rawrunprotected_luaD_reallocstack_luaD_shrinkstack_luaD_throw_luaE_extendCI_luaE_freeCI_luaE_freethread_luaE_setdebt_luaE_shrinkCI_luaF_close_luaF_findupval_luaF_freeproto_luaF_getlocalname_luaF_initupvals_luaF_newCclosure_luaF_newLclosure_luaF_newproto_luaG_concaterror_luaG_errormsg_luaG_opinterror_luaG_ordererror_luaG_runerror_luaG_tointerror_luaG_traceexec_luaG_typeerror_luaH_free_luaH_get_luaH_getint_luaH_getn_luaH_getstr_luaH_new_luaH_newkey_luaH_next_luaH_resize_luaH_resizearray_luaH_set_luaH_setint_luaK_checkstack_luaK_codeABC_luaK_codeABx_luaK_codek_luaK_concat_luaK_dischargevars_luaK_exp2RK_luaK_exp2anyreg_luaK_exp2anyregup_luaK_exp2nextreg_luaK_exp2val_luaK_fixline_luaK_getlabel_luaK_goiffalse_luaK_goiftrue_luaK_indexed_luaK_infix_luaK_intK_luaK_jump_luaK_nil_luaK_patchclose_luaK_patchlist_luaK_patchtohere_luaK_posfix_luaK_prefix_luaK_reserveregs_luaK_ret_luaK_self_luaK_setlist_luaK_setoneret_luaK_setreturns_luaK_storevar_luaK_stringK_luaL_addlstring_luaL_addstring_luaL_addvalue_luaL_argerror_luaL_buffinit_luaL_buffinitsize_luaL_callmeta_luaL_checkany_luaL_checkinteger_luaL_checklstring_luaL_checknumber_luaL_checkoption_luaL_checkstack_luaL_checktype_luaL_checkudata_luaL_checkversion__luaL_error_luaL_execresult_luaL_fileresult_luaL_getmetafield_luaL_getsubtable_luaL_gsub_luaL_len_luaL_loadbufferx_luaL_loadfilex_luaL_loadstring_luaL_newmetatable_luaL_newstate_luaL_openlib_luaL_openlibs_luaL_optinteger_luaL_optlstring_luaL_optnumber_luaL_prepbuffsize_luaL_pushmodule_luaL_pushresult_luaL_pushresultsize_luaL_ref_luaL_requiref_luaL_setfuncs_luaL_setmetatable_luaL_testudata_luaL_tolstring_luaL_traceback_luaL_unref_luaL_where_luaM_growaux__luaM_realloc__luaM_toobig_luaO_arith_luaO_ceillog2_luaO_chunkid_luaO_fb2int_luaO_hexavalue_luaO_int2fb_luaO_nilobject__luaO_pushfstring_luaO_pushvfstring_luaO_str2num_luaO_tostring_luaO_utf8esc_luaP_opmodes_luaP_opnames_luaS_eqlngstr_luaS_hash_luaS_new_luaS_newlstr_luaS_newudata_luaS_remove_luaS_resize_luaT_callTM_luaT_callbinTM_luaT_callorderTM_luaT_gettm_luaT_gettmbyobj_luaT_init_luaT_trybinTM_luaT_typenames__luaU_dump_luaU_undump_luaV_concat_luaV_div_luaV_equalobj_luaV_execute_luaV_finishOp_luaV_gettable_luaV_lessequal_luaV_lessthan_luaV_mod_luaV_objlen_luaV_settable_luaV_shiftl_luaV_tointeger__luaV_tonumber__luaX_init_luaX_lookahead_luaX_newstring_luaX_next_luaX_setinput_luaX_syntaxerror_luaX_token2str_luaY_parser_luaZ_fill_luaZ_init_luaZ_openspace_luaZ_read_lua_absindex_lua_arith_lua_atpanic_lua_callk_lua_checkstack_lua_close_lua_compare_lua_concat_lua_copy_lua_createtable_lua_dump_lua_error_lua_gc_lua_getallocf_lua_getfield_lua_getglobal_lua_gethook_lua_gethookcount_lua_gethookmask_lua_geti_lua_getinfo_lua_getlocal_lua_getmetatable_lua_getstack_lua_gettable_lua_gettop_lua_getupvalue_lua_getuservalue_lua_ident_lua_iscfunction_lua_isinteger_lua_isnumber_lua_isstring_lua_isuserdata_lua_isyieldable_lua_len_lua_load_lua_newstate_lua_newthread_lua_newuserdata_lua_next_lua_pcallk_lua_pushboolean_lua_pushcclosure_lua_pushfstring_lua_pushinteger_lua_pushlightuserdata_lua_pushlstring_lua_pushnil_lua_pushnumber_lua_pushstring_lua_pushthread_lua_pushvalue_lua_pushvfstring_lua_rawequal_lua_rawget_lua_rawgeti_lua_rawgetp_lua_rawlen_lua_rawset_lua_rawseti_lua_rawsetp_lua_resume_lua_rotate_lua_setallocf_lua_setfield_lua_setglobal_lua_sethook_lua_seti_lua_setlocal_lua_setmetatable_lua_settable_lua_settop_lua_setupvalue_lua_setuservalue_lua_status_lua_stringtonumber_lua_toboolean_lua_tocfunction_lua_tointegerx_lua_tolstring_lua_tonumberx_lua_topointer_lua_tothread_lua_touserdata_lua_type_lua_typename_lua_upvalueid_lua_upvaluejoin_lua_version_lua_xmove_lua_yieldk_luai_ctype__luaopen_base_luaopen_bit32_luaopen_coroutine_luaopen_debug_luaopen_io_luaopen_math_luaopen_os_luaopen_package_luaopen_string_luaopen_table_luaopen_utf8_main_os_chdir_os_copyfile_os_getcwd_os_is64bit_os_isdir_os_isfile_os_matchdone_os_matchisfile_os_matchname_os_matchnext_os_matchstart_os_mkdir_os_pathsearch_os_rmdir_os_stat_os_ticks_os_uuid_path_getabsolute_path_getrelative_path_isabsolute_premake_execute_premake_init_premake_locate_string_endswith_string_hashstart_CFBundleCopyExecutableURL_CFBundleGetMainBundle_CFStringGetCString_CFURLCopyFileSystemPath__DefaultRuneLocale___bzero___error___maskrune___memcpy_chk___sprintf_chk___srget___stack_chk_fail___stack_chk_guard___stderrp___stdinp___stdoutp___strcpy_chk___strncpy_chk___tolower___toupper__longjmp__setjmp_abort_acos_asin_atan2_ceil_chdir_clearerr_clock_close_closedir_cos_difftime_dlclose_dlerror_dlopen_dlsym_exit_exp_fclose_feof_ferror_fflush_fgets_flockfile_floor_fmod_fnmatch_fopen_fprintf_fputs_fread_free_freopen_frexp_fseeko_ftello_funlockfile_fwrite_getc_getcwd_getenv_gettimeofday_gmtime_r_localeconv_localtime_r_log_log10_malloc_memchr_memcmp_memcpy_mkdir_mkstemp_mktime_opendir$INODE64_pclose_popen_pow_puts_rand_random_readdir$INODE64_realloc_remove_rename_rmdir_setlocale_setvbuf_sin_sprintf_srandom_stat$INODE64_strchr_strcmp_strcoll_strcpy_strerror_strftime_strlen_strncmp_strncpy_strpbrk_strrchr_strspn_strstr_strtod_system_tan_time_tmpfile_ungetcdyld_stub_binder_growstack_index2addr_f_call_aux_upvalue_pushglobalfuncname_typeerror_errfile_skipcomment_getF_getS_luaL_findtable_l_alloc_panic_findfield_luaB_type_luaB_assert_luaB_collectgarbage_luaB_dofile_luaB_error_luaB_getmetatable_luaB_ipairs_luaB_loadfile_luaB_load_luaB_next_luaB_pairs_luaB_pcall_luaB_print_luaB_rawequal_luaB_rawlen_luaB_rawget_luaB_rawset_luaB_select_luaB_setmetatable_luaB_tonumber_luaB_tostring_luaB_xpcall_dofilecont_ipairsaux_ipairsaux_raw_load_aux_generic_reader_finishpcall_patchlistaux_fixjump_luaK_code_addk_exp2reg_invertjump_jumponcond_codeexpval_codecomp_patchtestreg_discharge2reg_need_value_discharge2anyreg_removevalues_luaB_cocreate_luaB_coresume_luaB_corunning_luaB_costatus_luaB_cowrap_luaB_yield_luaB_yieldable_getco_auxresume_luaB_auxwrap_db_debug_db_getuservalue_db_gethook_db_getinfo_db_getlocal_db_getregistry_db_getmetatable_db_getupvalue_db_upvaluejoin_db_upvalueid_db_setuservalue_db_sethook_db_setlocal_db_setmetatable_db_setupvalue_db_traceback_getthread_hookf_treatstackoption_auxupvalue_checkupval_findlocal_varinfo_addinfo_getobjname_kname_seterrorobj_resume_unroll_f_parser_resume_error_finishCcall_checkmode_DumpFunction_DumpString_reallymarkobject_sweeplist_singlestep_runafewfinalizers_GCTM_dothecall_propagatemark_sweepstep_markmt_markbeingfnz_traverseephemeron_iscleared_convergeephemerons_clearvalues_clearkeys_createstdfile_io_close_io_flush_io_input_io_lines_io_open_io_output_io_popen_io_read_io_tmpfile_io_type_io_write_tofile_getiofile_g_iofile_opencheck_io_fclose_aux_lines_io_readline_g_read_read_line_readdigits_nextc_io_pclose_g_write_f_flush_f_lines_f_read_f_seek_f_setvbuf_f_write_f_gc_f_tostring_io_noclose_lexerror_llex_save_inclinenumber_skip_sep_read_long_string_check_next1_read_numeral_esccheck_gethexa_check_next2_buffreplace_math_abs_math_acos_math_asin_math_atan_math_ceil_math_cos_math_deg_math_exp_math_toint_math_floor_math_fmod_math_ult_math_log_math_max_math_min_math_modf_math_rad_math_random_math_randomseed_math_sin_math_sqrt_math_tan_math_type_pushnumint_setpath_gctm_ll_loadlib_ll_searchpath_ll_seeall_lookforfunc_searchpath_searcher_preload_searcher_Lua_searcher_C_searcher_Croot_findfile_checkload_loadfunc_ll_module_ll_require_intarith_numarith_os_clock_os_date_os_difftime_os_execute_os_exit_os_getenv_os_remove_os_rename_os_setlocale_os_time_os_tmpname_getfield_newupvalue_statlist_close_func_errorlimit_statement_block_check_match_str_checkname_gotostat_checknext_leaveblock_subexpr_constructor_body_suffixedexp_recfield_yindex_adjustlocalvars_new_localvar_getlocvar_fieldsel_funcargs_singlevar_singlevaraux_explist_undefgoto_newlabelentry_findgotos_closegoto_semerror_findlabel_cond_error_expected_forbody_adjust_assign_assignment_stack_init_freestack_f_luaopen_close_state_str_byte_str_char_str_dump_str_find_str_format_gmatch_str_gsub_str_len_str_lower_str_match_str_rep_str_reverse_str_sub_str_upper_str_pack_str_packsize_str_unpack_writer_str_find_aux_match_push_captures_start_capture_classend_matchbracketclass_singlematch_match_class_push_onecapture_addlenmod_gmatch_aux_getdetails_packint_getoption_getnumlimit_unpackint_setnodevector_mainposition_countint_tconcat_tinsert_pack_unpack_tremove_tmove_sort_checktab_addfield_auxsort_sort_comp_LoadFunction_checkliteral_error_fchecksize_LoadBlock_LoadString_byteoffset_codepoint_utfchar_utflen_iter_codes_utf8_decode_pushutfchar_iter_aux_tointeger_aux_l_strcmp_lua_version.version_luaB_collectgarbage.optsnum_HOOKKEY_reltable.hookf_f_seek.mode_f_setvbuf.mode_CLIBS_luaO_ceillog2.log_2_os_setlocale.cat_priority_dummynode__udatatypename_reltable.luaT_init_utf8_decode.limits_pvars_base_funcs_luaB_collectgarbage.opts_co_funcs_dblib_loadedlibs_iolib_flib_f_seek.modenames_f_setvbuf.modenames_luaX_tokens_mathlib_pk_funcs_ll_funcs_createsearcherstable.searchers_syslib_checkoption.options_os_setlocale.catnames_strlib_tab_funcs_path_functions_os_functions_string_functions_funcs_scripts_path