diff -Nru zyn-1+git.20100609/debian/changelog zyn-1+git.20100609+dfsg0/debian/changelog --- zyn-1+git.20100609/debian/changelog 2010-07-06 22:38:55.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/debian/changelog 2012-01-09 19:40:36.000000000 +0000 @@ -1,3 +1,11 @@ +zyn (1+git.20100609+dfsg0-1) unstable; urgency=low + + * Get rid of the waf blob (Closes: #654513). + * Adjust clean target to work properly with unpacked waf. + * Bump Standards. + + -- Alessio Treglia Mon, 09 Jan 2012 20:40:23 +0100 + zyn (1+git.20100609-2) unstable; urgency=low * Add Vcs tags. diff -Nru zyn-1+git.20100609/debian/control zyn-1+git.20100609+dfsg0/debian/control --- zyn-1+git.20100609/debian/control 2010-07-06 22:31:35.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/debian/control 2012-01-09 19:30:44.000000000 +0000 @@ -10,7 +10,7 @@ libfftw3-dev, liblv2dynparam1-dev, lv2core -Standards-Version: 3.9.0 +Standards-Version: 3.9.2 Homepage: http://home.gna.org/zyn/ Vcs-Git: git://git.debian.org/pkg-multimedia/zyn.git Vcs-Browser: http://git.debian.org/?p=pkg-multimedia/zyn.git diff -Nru zyn-1+git.20100609/debian/gbp.conf zyn-1+git.20100609+dfsg0/debian/gbp.conf --- zyn-1+git.20100609/debian/gbp.conf 2010-07-06 22:30:12.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/debian/gbp.conf 2012-01-09 19:30:44.000000000 +0000 @@ -1,2 +1,2 @@ -[git-buildpackage] +[DEFAULT] pristine-tar = True diff -Nru zyn-1+git.20100609/debian/rules zyn-1+git.20100609+dfsg0/debian/rules --- zyn-1+git.20100609/debian/rules 2010-07-06 22:35:25.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/debian/rules 2012-01-09 19:39:59.000000000 +0000 @@ -14,7 +14,9 @@ $(WAF) override_dh_auto_clean: - $(WAF) distclean + $(WAF) clean || true + find -name "*.pyc" -delete + dh_auto_clean override_dh_auto_install: $(WAF) install diff -Nru zyn-1+git.20100609/waf zyn-1+git.20100609+dfsg0/waf --- zyn-1+git.20100609/waf 2009-04-26 17:49:53.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/waf 2012-01-09 19:37:06.000000000 +0000 @@ -138,6 +138,3 @@ err('Version mismatch: waf %s <> wafadmin %s (wafdir %s)' % (VERSION, Params.g_version, wafdir)) Scripting.prepare() -#==> -#6<\%_0gSqh;d";[#W2]HrI=kIrp8qMs8W-!s8W-!s8W*97DqHE!/L\R&-*:K#p<>Z*M2rYmIpjY:]LIqzzz!!!^>kDMd/54)NhXgNnq2qnqqoledOm5T33?uF853fkQ=-Du&Mc_jRG5-qMPM:g@oD5aW"S^N_U&>dq.lpYNVHqLFfaV2Zq$,cW>W;L?LDif8D=L+Hf!plqMaR?eN?*1k6nUX5guVW*/t+%eMb=C$/QOr%[_HUlW[u)H_5`GT_(!c`6cj2Ct&K'pA"E$ZC^5sh-W[bZ+fsTkA>,)q;0j&meZgmhd_p8ZXi*ENpj0SQd]:kpY3FM?/+h?!qt]LJ5b^E*8&CH!,-K"_n58B*T_%$Z2f+$#Y5@\%h7\1(?2$,::OT-WIF!.RMg]W[hN*((>?s8G]i3g,Nq^9^5+d7Gmp5YKmHun0f'dtBpT38#gf%!s2f3O.Qb0lUHbFUFhgN694n#QB\?h&@lZ[B-YQidYV`rE@q`[/+?[]Z_4M<9%cbK&[^\\,K?Da!Q:]_^LAh;7V4k53DGc(qP0cIk._+YIpJm,r@oh=nATI$^b[NBCFcYhKm5G4)[3/S(77=GC+$7-(]iOp(*LnCf5n6h0<6fmeb^D?%mW+.ZI&sQ1"A6paGl^pD`CAhX>Ds*UIs%*h#]sYW%VEbs$RAme$h)qH^U@3'%2fcu2"Wp$V!":t+jL:>^K_X53%75(3-Yb4F5kf%Y#,p>oriZ_)IPGMM-N*gM.L[M<0PkYnoGGB_lGH?UWC7cnou^1BK`/qj,U@8:(^>1[UW=h;4kF'e<.Xk5/cT%i.K_s^oMDm+M9hAG\8mdM9Y^@-!Ro=i^m?2&PLK`FsoKg?KgHf"?mjjAEMpH@;P!'[>Zp;e7%f:a8_j'I7n-9]^^^:i4o0=GOL]0!7"7mYRuGMV@^5[RlBX()Onh0WFKHgaV)[sYpH]7'Ajm,%R,EVFfcgKf#OhEGfN@r?Jm1[hfgXmjm7++k:9L'pu9g]hRWdh"C;q'62T9VOeC49+2dXIE84[9%@!,0^Z!!":o6kBn2!"gq?9JmZd[8!s)l%5ht:LZlgVPi[Y4XQbn%0K'cTE"s&&c_NRGRt5i+8@Uh+^B[KV)&X`5VjVDaru\AJ4l+q5u\st>#c8c5?91`g%,&"gL"Q7D62'mFrJW[^RtCc2c`d2@G_Wj@I^'68i_JV&Ls)"/7[81X=K`JQlln%BD`kp,AF=m$mfRPQlJHq$n;es_$U41#`+@kO@WeP'p:hY!euCU5bMd[+eT*pTF+\REZC/HL1/.sOiK/K#_nXqWYgUmU];jhG\TLjJfCrkJ4_,$:Fle5E)b.TLG<*WJEh%b%.NJLhe.4raDOpVLYHL.#B>jBS%Z].3]sLVJ)h0+K-\,VLYKk.[h-,.O6L+@ONY#WWIbqWfi18.&)TfM5#QqRS'<:Q<8[)JgOA^7YmNO.WJDrN@&aL,JtS!7.]I#(,a&Hn"PJmrF4BI8N@W0ed/.UnL-BI[JW@$iBHJk;&e=B_FI.>!GQMIn?:Jt]3=(l0VM.#''_,"R7DJtc]e.3PDagt\>dVJ6s)+JL'C.O^F8.RFE7JgsBi@OYcD8f!h\Jsmm?BS_74Lnom%M?tIBjI@Wu,,fd=Z&#B6JuVF0$6Z(B1(9m$Bo3aBKqY5C+G^>[U5:4QJ>u5*^T[Jq>88W_+J/Ag3D3Uo9#=C5A+18h#R`=X\rs.[g]Y.B*<9U*Lq=#`3;0-5m5+L1"I)M380uTIM.[:k0`-#Ypoi_Wto(aU'`Pb^VeaN?D4/&/%'%8Zl&MYG-!DprBZ34)u:c-9%">CQ]">LTh$SmrH7"kn87"j!A;PaN#JOEJb$rkS='[hY+0Jj1e8P1#""it?mQ!+3_WeI:B@\T,g!Jsj?#cO_SOs6&;W?e4;U7,8#L0=mk81Kp^+t=?G(mKkWAHnisMP-c&OpE6E#aSL>LkI2Y6ARuOCqq5ER#mVAJdA,8SS@R%U,u@B,2qU1P_Y.=qhfUa`TQeAgiauKn?<3M4f[#L4Z(mKVF9YKnoe%@Z#u(Bd,$`QAVDeb:OU*NV`RY$=sJqTdDVI6,Y_%Fd[+c06/),^MIB`Oq7AJ0S;8g7\t8e?glQ"EOr5I:$'L)f.%6!CJ>O_;R"U'*Tn3>rMMbhu<[NEcLm_]V#b['.+rUlF.T.*3aYFG7:n`Jm,"O,UM&<3WJd>nUM2An3@Ne,NKMb#@O[TBS5m.<6&:mYC5sZ&KXGKeG;*kt\,h5Uh9F4E-XTZR.'Zr6e1In1>8:lG^,*D\>@0==_GjA;%G;r@K)Hl13U0Uqb'je.o2KR&TqoQfGF13qC3AH.+fO=/cc2$ph[4JQ1\KR+InRDd$hXAXPCW)0BUP*SkjHTCJICV*m;O0b5MoU+d(X+$nj"tc.83]'PU8g/kVo^OOR?J9&i*)p"WkgUL=\5o%.[N+A\f6\#u(cDUi8^`rk*?+]8aV,N4s5MfiLqWb]0H5Bs)tJa;04*Q"c`a50f]3A%3PPnhMoG[kYq:YA*hVrniLa1$eHAU6;_?<@mGs-uEe\\UNbs71URg2qn^c)E[Bn=*%QnOR6RUPU3W_`QW`'/mp=X9GT-d[JL*=/'3?]Ip\TAZ=rcBt$?]dUQa1"1!9+9,+I<3BN>#963"FMqCbD&OG;q5sqUCB,Uq,J\bH!KcVHWf6HJUjG12J&SY<:d+j.#s_*=S`?0*QBY?A78e#dS2J]o&D@U6npn31b<[3?"om.Nf#-I*H?+NL6'>OU#?Yu;nIm#Mrgg)=Ad<.L*[X*)L'.n:P1)\3Nd2M1oD%i4l,c+k'8cImDS,G@5?]B%;"n^`gUhfOIMcObeV]b[7ac,+",1t`Fq;1YHcuMIiG.>Y.@\.\@61Oqd&L:B)ek2\op3U*@H2_5:jrOdDrg("Q4d>?-_>]:.Ku@4Z\Pg7Dfj^:T:1$m6*tP0Aaq=8>mo,'Z#_qP#@hd]rdVG42bVi[>Z!HE#VC^GV!;'=cfCM77GV&_eSpfo&O;F0RYU@jA\1!1enRiq9=b5d9$(Yh.N+"Du9r"]j6)%Oegm^a7R3Ff99W6MRj76=o)-.:_H/b"ASY.,Zn=E8%rZa8L;@j$dYI'h$i#hSf*GmhGZ-NC$9pjA9btLIPXdKFuoWFO60hj`eiu)8,CGAuQ7n%.U8rWV/$#9Qg$q:>+%bS3#'K6/s"R[9D,rR^$-[KZc5o"eW?LB>r'B_Mt9!2LSj(mB6>A$ukV/qJ.j.P96+qn>-&m9L4a>jVgVtYl5HU6Ya40>\d@ML3:`.033[)#4"=L7*\IdE)9k2Z&a%@?!@KBlsSWCC/$neJ^s5Uq/q\]`K`9hbqSgJ,\2DP%dc9*tQm?pZ.b3^=_V$M3W6n+l)./.F_Tb;iN*\eSu2%f_k.N\s9qr35`_C'M(?0p*uk72c>6mjZ+ia?1I@59mIkL=ob62n0ZF,#O7iJ,>bI;Ys+bH\s6prG6B./WbAc%opXP&'&:2qDjrkDNOp,4f]=R_DnO$)R;+KpunNG9W,h1oZ%@m.HA9*iANkF1:G)Se@]Bg2fR0K=m:Z>[7nd*hdO?B'$(`'*m;acP$rSaGF"DFF[rAs7H!2Qi:rO]US;_tQR]Xj5H:*L2^isO(CBTV[X7fp!8MK1]'+&$hoX2WNNSQrHK+rG4-X>NS\8kp*rZ4M3/F%.]`q5gL7-R2c&ji1@]Uus3/cdt:#K^nlaO%g\.C3!%4J@Zmj6t1P*FR^t$6U]_\]U'5V2cF,SV;+M3VJdGM)^+S>R(b.[ob,=XCNs3JF7;`Zf)d^H9^cA1@DWCfj\:VX'W1M=s%-+k[n+8m`''DPGN*jsU9R(fHMC++lY4:[k8M3l*bE&1(kFh?)9>\`o2&JY#_ZkUn8G)r@#U*0j(Hk+1a#rFjq!labq^O5/tSbNY1jd0,&hr*\7M]j?,HL(m.8HlTdWCB\O9Bd.;F!&'ZM]g+npj/0$*8eVkdn5<:Rd'po8Oc<(&h@mc&JjE?IL.dKmE,6:"H><`IX8bTMFiRY%s!\J.ba=0i/o5TAN]KN;hLX9/(:>\1*h',dGs9CEG`\,qVkY0;K"UPGYd<]Wd?o&^7t=>LYHG1pGbhXWmTcS%!:d7AVTron9q8L0Hkl:Rmd5pJM8C=\m'eDB6JjtJ=UGh)N9Qf_fEc1nmD6'PO4:AY[E`LLuK.(E4S%flilBT3%$\gUTinqBXN#hiae)=EMeeZ_=0pS5Nf^O-a4EE.Z/)C\;bM9(RmAM+%mI6FJ2m'OJk*0JNR57%dAi47ZN?FL`Z`Z[W%mOF*]Q\`mkI.ronM`:B5T>p%W#iCZ+[Pq7p?";P)S(B?u>j^=^\.69bsbGO5q3IMc3`pNc3RR@RB+^?(N$VM(KTecAFdm;uEr:[+r"nW&g:3Pjms1l>/A*6N?r39+8s3=&0MLdr;72dBU@=t3Oi**b9fmBSHdocEnJq.M+=q/NKp!t)lH*P7/Tp!.*#ARLiM.tSZl]m'"XW1'hddW)R2[6=kf1>NSfpI*K.gR'9"E=P*R;t"#bpVjGIp?SZ"j#@g#I$D#*IKFTFa+/.B,#7&:)CW4"P.TI/bRW7!m%qs,hPT#fRY'=rN>DsW(?h!gH#m%\BX6B9-'sh%+H8'J*nHsfRXN]KNub]/DZ`1.p:R4ZPXJTeaWPXihnr*[-Vel*87dQ/lLg)EUn6>6ZdW,*#(;HO1$7(4P:5_5N)rF8:,3gacnh=f\f>2ngV,hf!bmPMm+@/aT3U;i\&7H5[fdSPC,+B.2.?[4k\t/s)\4c_6fbtA4JXs5&0oB@8L>-qEd[kkkhh[U_ILg8HbRVI*p(ZD<$V?/([58/G[/mInY'ZCfFH!g_[=k=,H`2.=R#3bqV,`9[Jq$WE4)'ip76nT\As9gAB\l!'#:7ORW91l#%VH@MDO#ID]CCBL:#[\K\MjA8_2brHf**#3M!J7A$^.%Q2*Z1C>f%#fm\TW4[T9bVY`"4i0E5^5de]P#7bGJ\eX4B:msItf3.PInpUcc8h*1'OTr@YsNj)(3&KoG!5f>;a@A\#M'`6:bh46q>ZUhX5cuicOo).-2%B&QRmqOFAGJ:-Y+m7aKCTWsqhUhhWSge/7=`:m3X&T7e&m61eI6b`Zj@IjZEKeaG:F=rch$\u>kE4Zc'XQ6T+X:&OS@65fcb$'Q&cXk^eec0);.>j%T7hT'QFXr?UPk4HpKg/V7dHuaqLeK'3bafXW;1qH&o`&Di"MFf)<\sR_k"O^,*k7Eij>W_edUL"OTPni.2WNjRRNDR0S:f:VXkp3:Z9ScH(\#fIsId2q[7d&OdB/rk5^)="JM+9hQRke)DX7h%KVD.UV`FAb(8;/+V+1Jdd(F#^Ke4Yg`83n,:U)Z$0(8Kor.m2933TbYo[PZ%Z1/g;^.+_4d&3N=]e^3Y+#Y.n_Kf[krgDVm=lJu_0gX]PSVKOA45A/ZW]N'u@1>r^t);4uB,4+In([-(@[JW1ufo2'!F#dg*OCtN`*,3159bK+b[-Mq`:tRYhN)?6[^WX82hJ3u8)AdQbiV[u(^@T_a2[j@gkO,<*qO[rOJpF'Kh7o'^d;PA;Q>JXc2!o_K-#WS0!qWll:t>Ailsh&"=0=oUR)P]p.SX]Tp*kQS5C'aX6B:lk2gNAWPX`QFLMf_DgGZ;@=%-?C>!g9g/%ir/%hbU*!@sm$?A`;5jhcQ^<*h.*40EZeO(eBp+\C]BRD):Q%1UQCG%2&p6&a([pOiii\p7Ge-M6:(]@,:@uu1P#bA+Xc?]5*$/Nge`:hN]H3jPpKPCJc=X8XF.^hUqE[[4)5paW1aPS45$W@V.q]\AC1ZQn&W?7fR<[aeMHbNJYX;7@8^M?^$cMcTu<1b@iFtRjb[*-oUhMr.q2XPN`m90%h2I<-@%b8lP-c0/o!aReJ2I%0T()*mKpm,f)LHD?E%3t$gHh1#RHH,eEP]8'Fl+L&nQ&#*YS=JJYhb8?ar\^S@RJUoqcSiGKr)mt8.q19G3-rjWU>:lC(N5oa_`)G!7MpAN0qQoGZ&;Ht`R9)QWgUEN.l21m`A_)K?9C/dQ+GM>9JM#Q^Z8.t_=uoSQi#;O8D%d-Lp7dJcDQV:%7F(]WB2:>DBKS)/\99>5"P+2,A`pV,#kZkW#eLO_9GjM.T+HT*=hKKm>gt&76!PCZ._DsK_>4[qJi[-&V,F*L/Z@[i3GAA_Qg^hi%+p,-%G&4gC!VW5UnH?!-u8eBF624$XnI-+Y`IhMFf60G@8C$$>bfl=)^k+F"V%YhYY%^)l1;ha4G!nVPL1(n*1\DF8hEm>YTL2aKV@KXc.%Z8_b"/U!RUWg$:O/\fDWOFoB0L[h".>Z;k]A8pQIBPS7;:Vr!0["C:IWG9ik3V'm[W*s)KeIEis#\@DW$6-X&_Mtc0`AJk]p.BPGP?*i5*o8lU=DQ\Lq.[B!b%rM)=PEND%^5]m$m(tA9:(+.-E]V!s#bjTdH1d2`])>RD^8N>?A?>qU(Nd2BniCpbMDZ_o)G;9p9d&I_MDS_NIGW3Z>\:.jOGibkBJJ::$.UAUYWpBJru9DH4,Z,NPJ-6L-7Gk<3LALI,2lEEkZo=BViZ%Wl;?R2@c8RV.E[Ai%&&5:I(TD]ZZc3+%U9?1dAO%mC1Z<.::]("Lo2DhcSDa_;b%X\gP^-;9k6+.JNEl^"i:Wf'735@6%22-3p`?cdDH,rT*cK8qS=O[V!dSIC_Z[r$1H:5"C8R?WA`;CZPDXH0WNVR9tR>d9&VlM2dNf56HGY_F--UZ%091(?(k&E.52N@_/8@M`i@$:dfHf#";(:dnAU-La!G_UTqdL(MIIX!YJ9usicJj7;a[:&"dMe,9dn8>=ji5>8l?!IPH>Nh+[;&QR+jjcq>5I[(X%d24o?_SVGYcfYh#sK\JrKI/9*(W/UOGBa6FK&k!h#Xe\T?kP!YDQK@pMR0s+T3Jg3fqQP3P2R/mGl(e^%qA!;.AinEiJPTB'K8IgtD[3mr==ZV-9lf(fi2rL-"=*LqJ*eqO(hkgB&_Sdjs+8J#?8)0Qj1*P\](G_i#S)$XXZNr]bQn)A4$-D/rB7f7MA@#XdU+W#-?lka;On1MH*u4HdJ",+XgN3CVtLjbTGBR333%dQujtEcgsP1#GLnrkk'/odu$56l&8H;\cajCT.E*#^Kf]JtJ!\S1LR6XS\(-M=&c@#1guL5GB]h..6Qq8"+\]0)s/pZu5eU"c&Kc@Z\lDPd<:3G,t8[fsa^VXjQEG78b[=N/FQaVrYiu?E^KEo\`<@'n4XLqO\`idB.OoUln-N83%a*N9^VQ&Sf-c#nZ/W^;]^JsGri2J'rl`i,+7gfui2+fL7WDiDAbp$p`!"J6?p=u#0KCsVL;nm&+,q]L?BXKZFU(;7NtE8aM56::);1]/IP\1[:T-$lA7IA>MJ$k\`P[o+g#ph1W8>`EHe'OrThX9-[l6-sGk!qaG]?61H^g<@?+"hqBL?^5N4UM0et\i^hI6Xb'ol;5S0K-N+4ulm+H7I2]>4@KbY0"FWdQX1GtQ?dA0:"4bN`SCaEfU8JU3h)a?h;^(7#6S?,/\"c)e?-LkLI7XL4la$G\TCSND4RF5GYL#IW-VmY7SQNe&Oc>R2V*DQ&Nbo=bWC#u=nNDJlSlWM%4Wl#6WaD.eiYk>D_q_BK4M2%GsC4$NW%H/A^Or7R[E;d#Ng4Nlt9a*lirEZ1NDD_S"h+h'a%7.rIHpj%Cl'F4sG%jsD(qnR21&g,0N?@7=^Mi!Gg\C-nqp.qoJ%agBQ;/!>QOk`]L\Ek5hEk:-)J^dnnk(&8DJ>@<6;)EX/XlZ)rh)1o,oGO*\#Qp$:Q`^a1=GVR5^`cBO0E'5"kE'Y]Er#KOahh_':fO'mdZTce6"H_YXF^P!4^jXhL&UJM8t5Uto'Y[tY35.YY(MGjX6GGFm_:=Dc!84!Bfg4DHS08Qs/Pug8OmohM"&9U_FF'@QP;u7i;ht_4:&86;_Bl[N2jD<_-8bi'I*-.:@3pTdktCN_FdQD=;ffJ4>"NOaRN[rDu/GBls!+#piD]=[5#TFXa$=&cp")&N6Q4qBg%V&cSIak1Q?ge3fnAH.uqL=4.t=m5l#*-:dFjMg1I`tZf'E$*iC97mrZLXbU@-S+K1[(Td"5I!/D[JiSo2'Gk#%S%W!HRTiQu#2(I\*N(=s+2&b+XJKTOW%5>5%J`:=$\M#qP0aqa0KuAUIppYBe[+iU0'[$@EFqHRp8XVquXR(MF8K^[nPc"S=-kBn/Qb/^b)oOXhQ8-j:Vt1f1=K=Q.Wj]g`+uLQm!A&%VD+"48"gJ8"Jos[^&UC2a?`6Rb5Xh<[j'Nhu_([_<*l5]/?pnY!@72)2ZH+qfZm;K(eH1m?XT:a+1qSPm2.[@?7M1S874?n0(l#tK4`WZD$mHsL7PtCO+^)4(N@7@gBZ6o5V1_O1g")=a3RUs%LjmTs[lY'3U%*iRY6[<(W,3p$nYRU6l:*_%5:4d(C$PV`9lT[9Z7URaG4qR""fg<91kGEpW/AX1bl8T6j$V%-%lX<4o@o1U,!6"/k[J<[d[rb";_LSA$c%.D3J6_5,$?T@n^A1MDT$DiR:s/_Map;.2gH,g]ku$M4$/ZI:#*a*t.hW[rAc2pAaY?EA**]eb8#3`"ShA(e\#]WSd$IQXiugA>7E*IagiS4b_J\4'NgTf565H94@\(O\62P=-JmImj?hhb$!;L$pL5o:[,5geWUk_AXSoS#I_L[?Lcmu3bR@0kU1M>3Zc@8$#8mS0u6-b$^AIhlV.Uirn>/Y_3&0T2&-SrRbqgS_D8mSV'V\LoDu2B6dNpH8madZ43uiP5M7)7U3KiB^kEQUM&V2Bu9>GZA33hFm7pa(`&,LbplZkFTLiCh8(P^[PXEeH!UB/k[EaD5u2:h,:$jM5.]_$\NS%lB/alH]lUb^E7/XHg4Lho"sX\#;WQPZ%e#iF;riC3+()0BlGl8QIT3OF>A(.4'K14mQq3RKDM]hABSk-\)`k:KH63maCGf>DFf5W\0dWIW3Ncbil65o[3S6q4[&4Dc]Uk;CsndZ<`*#qZOOcecIL[*!_UucreVg@1tC5B4ar-Yd4MF26rnm^[b7Z]]4O5kBd_bjmpX93;nnS^.a&>]X?&#?,/.-1eNlHa)JSb^d="3sOJpNU*!sE8SG;0ikP9)%GVh)q1AB);8I*JuNrX;\s"d]VL)s"eD2m"g6/6@\%:D7en_R`*rQb+KVt^3j[\u`BC.@3*`J\!Y>>>.4bpaDm1GRO'q8nO.:4iI)1M]e%\St!Gh+"3]6;2XW;D4W=+E=@N?G(bJ%-jI6A0hQ'K5(6/*bLI($3('Is#7=7b+k9cIC2Dbj"!9/\^`DIr*c_53:nf-eu7W)9\=_5o<%j9KG<2PGtU^VCnSEk?bmM#p7b:+R>8rAHVBdZ-[ZuUqBnL7^U`0ZhY8-MO\XQrm+!#UlU4b'Z2-a*)K@oNm6b"^9soZ;@qdmBpnMmUS3*ula=7F_nTC&E[C^s9))l$5*T*U.@pt<;/WReWU>R!>:ZVkWBU';MGE>rT/W)`@N#YnGEVI?dCm!Cag>8.BopN:;=Y0h2@bIPE&Ml&W>8^#%E029/Z+h>O-d9<5:difl;\^/T"WBsH@#9m@j_*oj2u`B+3H1X6r+QL0Sp\=HRCD3W7(&`,$NT6WkpI7(Xm&rCd^?:"C3j[,j/[h(6Qt^)59(^+rHQ0#9oU36Su*,e9UD`/<d\]k:BUh=dTqI)3s=>E3Pu/ETe^jrr%"n9`gkGsSjBY)a-2Y?$n9r*lc,OGUC^.rCN8dRgWXMe&X;1^&_Zi6Aup)t.8kq=;9.nARf%1c;=JEiEL#Xj'kdE,&EQGoOq?g)1s6"`\FB`Z>Ra6Gqi^4W@Wk+'M%+s/Ma`MSuh4-&Lb5K>IZQ.+qLI+P:_>S3:3\7AK7n<5ICZsgRh,Yea%mM8&51Ir9/n_3IDD`Tfr>_e_W;C9n@-!59-#!o&Oe.O7BIW1O,^3"2`tB@(YeJ)*7_+?fDW<`6q87ThYhRXUBkkT4>0M"hQ4kj5,(-Z:]1T>o-S9D?p.gs8,'H,0_:Q&7Lb4"S?NuU=@-;(gmG2hU]hi&YiAk,m]8W^mZL2.EKr=C#*]p#aBPsuUPECRB=6NFa?)sqqk@$ncRC(YBD\56s%>AJu/ZO^NWhY`R]t.K9g!k7To6X?n*Z_"0Cujs%""BAj3[OsEJEujnJg6TNeJLV3f#aXN:mSC;FgB7:c06=(2)k`=<[$&72E90d\YDC'3M%k,FAWS5*BB5IER"7S/uX,;*kEg4\+1QWLK/lk"d?LEjDe[P\UAo__Y7:*:jem-@kj5"eQ8V6kfPOiRlK:W^I+&\T/5=u$,/!>5*A\[\;Tm),NjJXLE1R/5I0!8kSNuAdiR/?,g><8W&lL[[k>TnW*Q*bK0+Xr<5BpU,a?AU3.\I&Gie6QZ-UBl8uD`3p!T]gfo>[,G*WdE>9]J)V[?Y;G*/cFmBioJN+jj0l\oFJ>G-XGQs%o#$&OE6:*7^ZTV[?8EK9idL`BXRMf4GoVp^!T),TT4Y3&m*].>49]A&NhRlQ\)\G(ErcTfP@g%c(uMr[(g@SA&1@0n7n)ESa"c\_LZ,EJVm##.1Np1=j!IQn7\eDFiglBN;X0/bqLr1Yq+i,,a0:QS94a>FJW>_0'#(L"c"][M[b3g7/UGLK);E7^Pqh@Vd`BGR%1+Pn@DqLaQT@Peb3Q7#6ZpZa2.=&M]Kh-/FhBX+h4`6]W1](bAhFA:%uI.?>jjT"mEbFEG2$l8>rf-]JCU1=H$h2QbAsBD@1C2("%*Y]M=N+9?&Hro,l`ST)93P[D^(`r#U@8'^Lr]a:!`!1Z_+#mD%W$lk;i'KpCLF("C+K6`;bkg2dP6+3K/\f$*WW6Qi,/5l-'H=GP.FKqmZ(kLG.>%'HGosX"DA+TZ/f(2-GA\Z%,r.:PJa0$SP_iZJD>Out$kOY]TM=>$@-.TqJ0Ol5?Z,n_8O`;W'g$&8-g_P_t*-0)A$$e5[8V2.s\P'YX]#JYC%!_'ta2ps-/[YbSSV0,R'%;]2p?b]E-K5h[8)*l))a(O3S"J6mY85H$m?u0u1Y4ZOP#Bct]D@ASVo_/rj,:)."qqo:o,8f&JrjqH54?5KM@rUEe.3^O\I;^IjtY+r.k-2(amtWTS"1gqbeK'8.6XehOQSf("OkV]VgjA3FUDnOQ$!8L.:I204B0]Pn>#i?kJ>G6CHO?B?80l&-Co@9BZ"jHHO)^Y&QnsVl[2[3okJ]-[gtTU"uC!LD@PRKQt\LBlJ;U`d,Qm[;<:=G"i,$n4+n]IGeLX]kj7OA,%&]d7(/tj(b;cEP/`^G^a-*<``%GSo!Lp-6ED&=]g"`fnVr7b9>XL$YjX9Lr''qMMPRoWWNsluis.chAbr>:mD50KrQB2cIHf1N7crh/o6&Eo%)E;NYpDXi+AjEjo-Tc^l3o=6UnD[WKK'a)n*sDNECqWW$JI%/qt9I>:00e$*R&a9e&'c[0)]P0mFM#rbuR1k0sdAb#X6JgS*"=%6fHAXOM'freB,r!8)P7Og"FV6$_@00L61ZKldCIA.G\rX_cldTr\9().O)o0K`<[/00.QR0,Vj\W;O;BDc8V%0GtuW9L#8pQ`tg^`26hTg\"0SddNX/oZU3LD^S>cQql0F.UpoR\(>CKK+0HoAm'o`1,kb+n6lcME2_.8*`N.+oUVl]W%^ac,RF_C"VUOU`^IQ:\.rXIm\Y:n#p=Z^?B1JV9tb>;/JrN>BD@ZI$1Yc^0,[rp["aLIDm5"PIZQkIT0np4)LlGCtu@e4JE4]h7nq[Yt^k*Fn/_*O^u]&at?)2Nu4>s#sFZUe@0Q$]Gus0U`;lqB='$WY:Vfka/#FPO+[""9imMc,;*fD\YjS?WU(jM#9Zan\*,JD7RJ9Sqc;RL8k&HotOd\HpoT(NUL]*LYa&hHP`OgL]duO1;I(Eo/+dp8%[U?q6c'>XL^V?Wl2g*H`1KKQirA1$2N0sm6K;oh4gO6=PUC21\??5C9+W4L?1Xac)U-(k^Y7#g7M,oAEq_nh'.tJL`[[R(8RV5fu)lscU_[bKnY6SfZ\eu_=R^U6^+R5>4CU:3>eAk\ESmT,u77E3Q9A_h&`6f+CF.D*@*4&a4:-HB:X*'md4h9*aT"qhOY=/S`f%"(5q&tYO1JNb3L,XPV3oXX!\YdW3b]i1?c-J:j;N/__4iE6A9o'FH@cc/)2"G1m6iCdg-^9gnjOXscTU$lkA4sMPPoN[R1!b4I2^DacKcLBUR0(eh`h9cL\&_!J_s@G\pZ=::N60?q:@oB8q"Db-Sc]&f=JPqccHu)7CO9h=eqZA.G#$"8mAV"g%\^T3B?]e-0?L7i[;_O7XDI#j5Hp-8O*GRn]o_?c:6XHHmOdij#M"N_-3?"f0+4),t>DQ8Jf:gSsWDaEHl;:;eN@0Y0dESr"W[L6B=;'Z=r&L,F2a9BplL(VX#,G;g7umD[>`T\+=I;Bmb"X85/UGfmV+?o\Q&XYdi?3Z,N3;^7)iWf,Lp8S:.P3SgS.\nroF)iN\-;BYos+Y-T<+LLIbB>E1qu:Pcol3t#`>n*[=0g#Xq>&I"qiL(blHZ;X(\mWNb).>#mA?sO@gN?=uOc6]ns\Sh%N6]M,GfhmoN%,ASfaq/0EYfmb.+LJ,#86+P8/YOVRGP:L(o[^Pbo"-6]6,M]XpITriX_VR108IHBc'`**pEhi()1T'Tg+g"(gI;fLLC5%!#V3Q2^^sdE^%gLjE1$n:S7(H!#S2nNo6o!\HO:@#XRaOTe%9_k%Y$X[[>/sM>p8rl:1)_Nc/dr#a26OndpKj.T0I*N[QCrG]brYQ(cmrD#)T4:]D(#AbeIl2p("U4glG>TDg8,0]_b1rCjm8JEUTLAq`%2l\Ci)*S&pmm,UDe>dMu!54#X/X`+bJ&gZ?'on'1SVYrn=.0O'Ds2h-:KAf=Lddp)`EcO4%GH#m:HXL*nunV8-leJPYI-6ClL[6GJB"$2%DK0,jq!U5N*+b*RHmqLfZ6As%DK9Cs+"4p+oWE?c,#W=8XQSL8#I@2u%;^L?akZ./hM'bfNRte>Q^..#=deD1#J8T6MTcDmQFS`UoRANSZ;B7!mW!lUi90Va+0pYFp9Thn#,ACr.hkelgKg:6C-3jdJs]4W#1DO>i9)kEH1FJX)GA/tbX#<>D16.klPn/dVl.=FJ][CgpYUmp(sKQqk6Q3aR6db%.=FHnN!Tf;>`q^Q43*@km/M3;P0Ye/M8".[sPMLCotiW9fiiV[!T=Qe]uj2e^4]1Tt;s`K`d0>GSZ=YkGd\r1*aNZ0G35m`Ar1j<@!"HF_O(RmSpf3q([MQW`,(N-)'V51Tjh#`1.646L5UK@?!]if*R*&p/!Is2Uea';k`qPhTaS-bBa5oiL+Ebrtl0NNsnt/4IhngKfO]DJRbt2*%hJNp&JPU3EM;=eG0^g-ZrsefI:i`>uFYYuNlc_^Z]G/kL8O<7Y.*NdmB5L#67X^!KPX5'"4ld[;WRWT;P#Qd;1Wp?NRNpc0n-JpQt^otu,bD7^`-N<,n".HX]PBO:ugZE3jkfY9PG;+i??4%/mfN@E#lSDU_2F\e@&^Y!W20"<)DnNVeIT)UpdgompZ?<\#*\]&>aTh.L=cWAHa9rN+<-Z@gMf*Ad4W%hP]bOIa;>?SpL"9LE/4DXDO"G)RPDp)6]nFU!r7Pjl5'KonjugWIB:80N\-nS?jcO_]N\-Ar2180m)2Z>o&STjP?8*9.,,-0f[+\+hniqG;U&L=m&t2WC]iX:&P^R<#Z!nq.sp@-NZ+MR\iGE$_]-ZQG*.3=iP%s:@O&&E@]f2j2c3(?Qon^EC[.kBR)?\Ak`>#pbI`DA`3@NHR3';:iRpmr435KA"Cjb)&-X1jLBO%V&6/>4\u$`[MIFj/29+s;l.A,m?OhP.\Yi"W3S[Ne]BihSke#_,b,rKQpfZm;T#e.X?c&S-0\f:.a^s&Km.2LN($E94f-\3>RTPlQmOeqVE,I$sUTE2.9M"Ps/[Qj-^QPDY:@QbIZ*_kR1Y,i@kg?U2lYBB.S-?Wb^NH-dFTG4OO70h)(9XaSiLKdFHq2qs)]C`^X%;2t#1*+tR]>[bqcLo3j6p1,CZP+p(`P=>;BY.T\cqXgKIR+gEKL^XN0(C&uKWQ/BK=Y^j?R0XE;CtB]Pg;"SAF+)Jde+X+j;nn;*`3J%f[>F#nCSG2BYQ@WO&>&M`UeTJZlRAi&'Ao1I$UmQ=>'=3eWJ[f?@9*n%g`O;POd*kaZXApcFND(gZAaODhI(,iK9bscU+-Z51F=5/om?@-bI&1**eJV:MJo=>n6p/l+#KjK0GD[r6>NiH)FL%P:H#Ph-%V;D+Pq8;1jm_$r"Tg19M-F,o:;Do0rFQ^?0Yiet+CmNb9B9'g=5HTH*$Gie(B>hNDer\^uc6p\e.Y]3q%1J+qtC/)c2_iR$>_R'_dp`eVeU/QTK\Ps@D!d?-boJc%qGVtPU!(WN_\q-tZbKc"FmX`Hk91"dDEL,ggR"D"[)4u4AU>rKV0SJ-[?R&^C#030!f$S_F.`.\00RpeBN&`+3GkJ4>iDl\3p^qc?2^U`*4uog$ea2Ur);N()nC5ltAUNVYKO_Rfccr"`'&D>D-;8_8gG.TZ(!tV(;Ot3'0#YcD05eNG,_`hrm?"l''7)A'^9PE,Gt+fS/`;uTq4[2)r@t<5A_Vnc]qP[En%51tep72b?J0?,eij:6,CPr[%EP7:q]?2XXO_F\=(/j(>K%(YX1dN=PrXspK$(Dr,%q8r/]IX[-5<^_YnD!)fEM[V't/6k4r>DY^P6\i2:h^[VMp)qP_d'Gf;)6KKA(#H"&)md[BKLDs5+Y'<_\tLd6fi^YKnmOc9(A6Xkf`/V89QqrZL*[THo.4F=3Y\O&$dZ?X8qEtp3_r;g_)Jr.T#C9tSf[r)+?A.RNF1QF1IWqh)('ABA!9OMp1`\EYeO-3G,0o#Ft2@@],ad?"A,*"NK;%bWY,0`_mAGFWkCC4+XhN35P2IdsPPs'MY".d^M^)hPZo4n2`J`^#8!'I=BE3ca>)^FID3V*PoZfLqD`:Vb&>OelLIU^?f3MO!^Q3CtsJ=?%p=(t"F_5_j)]O4Oasg!`'.(ikp`I=JG49lei&C/"66,[.Y2K@FlJCFb@I,d;RWS2Ac+M.MZO2IP1rZYZp<_X[SmkH!Bj*Ug>>9dFDrjks\Y78&h0]/]R&`ds(!hR*%L>Btc5@UgD2%CTh*l`4!-[+CXn[t_OE)fe[q.9K^-jYF/j+et7Q`*Qc5E\9d'/>&P5'J&T<\8]j_6W=ZVSccp2Co@Ug>?MFf1NZ7mr&+n(A_]c.d^[*HZOd?gZc33H'ZBrq2sdtkKbKO>ImI\/m"N^f,%g%]Sjeb:qOhDPg55g;VCb23?ma:fft/d?GlBf]1iIN3`O3=M-HGn?.*U=]8cYV&A/c?bY1DJ#Qu@3YB4^3>1MP"cFH*V3\6^+0J?]NoWZKbi<@L(k=XQiQ;QL@MT]\U=>>;M3n0=jdD)GdCPFlVUBiJVP_BS.HL(1h[f9e>^[nmFk84Ga6ik=ZT4)ALU<&A_WgC^J+Q4.At(Zn;9SW:aTonJM:!Z["H1cpZGiHb@hsj=bqg,?Dn.?g$?>p-+7j8nds1eX5rJF`\rPsnj-k6Z^Aa[Z\ekFr*.&N\Vu"DHYX-<0$Ygo9kWh8=Yo.OiR0mCN>NdY!q,7GXJ$o;>tE@0L$JHNpgFNbV\B'e5-:;4a$;$prE^n\h@6boF_-tHs`UP:'I$l*)<'-m&sYA8iGI$MW2c3_V/sN9%oC@VEdr"o`NRQ>T;Us,Q&`qGeb1')H2`5ebCaWYtfhG04()%ldqV-Z6)ujVYG8(M*c,?ZA^P/@5KaK7eWJ$WOO;+;DEF\S02TT:*-kCo*QFdo"n3GA1p7>Rdm5,O:c9*L5RRA!MK)2IHZ]<$U&>(B$a"_h^Ag;4J9qg&G!9aMi">jXc,abH#X7G?DmET%ApI=5[JreUH1N%X^NJh>5WTK2H82\cb!Y";neO0o95o?`'P=_;YN]0U[AA6j6*_<'$ASt&AT*81ShZPd:mBRWcKA*HF+,@:*Bi?S&)rTD]@6Leu>s6B"+Fg@)Nk3f^Xeo-EGjFR,VOj)C@.`bb,!9)KnDfIB9P#sfM)2R&-EMrT@TOs24jnV5\tsL)5b%U50]-^(Zh(=Emd8!Ac>h1Zc]rXq1th^kina4Dl\O+GYoH1!T3lo\Tli#bmL_5gg+Da2,Y*kb`%HX;'N"Y+uOcT6XNg,1CT8Ld[:heBa#D&iL3;TnFmpdC8@2[&B3g0D^CTT%^f=kgrCG,Of-,R'e9)D;b8+hW3c]N;$i'N'V-?*>bJbZ0c_rMD)_LU%h(ZXc81Co+l&pLRpanQ;4TnT/i4Qr%Og,0TUD@]C\n@oBj.;^)u9F!&&/0f;gL9W3qD]aP08-a]7.\Vt=,g2!NKRmR4,o^%JWoWo2R-)meNFoba2`B(u2m`_6lC>][nYEUK6IMXnB]nh"k.rH`Nl$edPAUI[t-HZ;k(ipMK.d,.Abd-!T`,P+Xq@9GA!p;-E'>])PU^)Y`>O7g/!SbcZ.FLi(BVmgC^6LA?@b4[Ij(iG0Y9ccT<)+%!6)T\_iTmoN>RAH62-TNu:Bgp1*pD(fnk^bFJ9!ApLQ,m#p$=XL]e9`m]55us:I_>[(e+;-cppqF8%L$=L]en+#FHoL_)7)rGs4Bj>4]kuDs)Ce6hOJ,SbcS:u8Wm5:\1+mWJ0r3e!el+Ur>2aL3`8?FdQ*"hK5(PD>(5lFkf=uM:(oC:7T=6_da90rk=K\g4k:@Dj9q-+3KSgR^'[f0/X?fC.OSDb<)=^R)K!d.Cr6^H2cALO\o%U.\;OTQ'iWYC!Olti"(;4KjNV;q?[%2@h.uUeFi\-?L@;otXlH@.0VEl?VC$tsS.HuIJ$3B3S5Hm^u@/=&/ZlS-cOm'N5"Z\>:b7."kf013Hl9dp[d"cBTr=ScR!N&,k`\kPi0h+lh-$5L52)D(,3l(9[K*,K:2Lj_p&D/6'&=],P<::SP+/gD)WGl:QiHUIu413abXmVF+hfc'V1>.)]['(bQ6G[ldH7T8a.Kf;)2TtLAa_51EULb_G&WQ,Op%i)Gh__UPMntr3,CLr_h[>%Uh7fi><^9U)G]G^q^MmY`^qc<;nfg#G`RhrL"DG&CM2EQ&BJFdRH2L1YV=FBXF2)-]_dcgWe9?-,bu\bE]^JNQVT-k\$Zd%630IIXl.X`acI`"5a.Y_#f'<+7ISVkJFk4/nj62?WDRVKi=VB"\r#D]m.=2;AY'7k0MU^"=HnO^G:JDjiGLa>m?Yogdj2u[IP:M7.W.IHK@HX$[BIYK(5&YNcn(hok#4(#(ZXd^*8LcZb@dT[ClH2+i8tuMr/XOm"]P]GK,,UQ:;k#jR_[%,,-1ebCReQ$nP:kK^KH0>9Lm>+GH'H;3iG!q/*]NPGbQUUG9]S/cHGk-?"XNGa-'QM-T+jV4Y\"/mjFZ+snKq-`IU5&q%"qN>T1@:c?7FD5&j25V\uBn;9(_)l5cPB<&DVbqPEQ%[<_PFNHQSO7QNqIj\e\1BBN'9VrKiM\((-7AM(Q1[OO4b)!;8!_t][l:7%u'6uRu6VC$V.D\\"DUPZqYEJQ`DVCuNXhsIS[?EF;d!fWBN7R5Gl1N)2\>QWB:P'TKEk11chho7>CKOD,01obglc4"g?W+!r7UT?b%9@C@@eGfFZT'Ll:^@h-eR$Sb.HQn8gqP5U>FdTU*#'(7EXLNAb?D5Z+rQa'3IbPgA'@jfp6TppenE+,emEIFJ2;jDi+mG>9B8i,h,J=eXNK6m\Nq"_(G[X(RrWsT!`4.+8j3LT/on9+1C]"36q/46I!:U/PMQ7FFDUk>(*u#.?bTg+#9UNi'&rjIi.ih0Q@X#;:ChD@6LVC/Mq+ft9f@pCok?"eaRM'Q`2J]?C@PoT28[95I(\/@UOT#ZliebKYllTJeONU$Z]$O#@X5>e.b?&opkA?#lh2A/o=8#tCDt<'\Vo$!t76:6T[hO0s)iZ5LnO2kob@?%X\DQ$/[n6+oc<4ak1,fqi%nC(p/(:GH.V,+\S/8m/k8%.hclIT3SO2^_CFkl_QnQSJirs@WR[q=9")BEMBl>6:i`@[TsfCTm:7_EM,[j@924E[M;5ZLO+\RQ;h><^_.m<=R2VJQ7-Dq*MjL$&2^rUhj8Qq.h4OmgVNCDJruF3)OjF#k5%#/qaHe!](m>^sGgoD(d!U[!O$a7;pb0ELC?6/`un%=ii*NT+*882OG]arHl[g*`:EX=d3ME-1A%GW='j%p0Nl1bk+"jNFT`[\=4%I5%M"Ff1%s=$KaIHne=79R%S[5_1OWVD\/<6):`k`T-'gJV_MX65Gh3Er16mNu`&fm#2:1o5n>-_7H^B]bQB__5bqINA\,__IaOQ,P5)Vbi)0"GCC1L)+W-gQ'IM]'7X!Jb&?/d)`]7+,$RtVg[V=6e`3B1cDI"__H52j2M$=>Y,;on($iW']5Bg4iA-Wdrg.iE)_#-!M9*;TD4`\8ZPf:7bbX!R)",TEc$A3\fDR+OIKVTeXi-B42Z,G*PIuMk"Sp1T.PX7k6R5&lqVlm'q#>NFr2t<=mCcBaj6?1(>BPG=E=CS>XmteM)..CMNskC:mE4->o1_5l;Z&ZG<6=+TnX/%5pr/^M[rS@=o>DjqX'_a\-h/p.ju+c19@:GR>FmUP8ds@U@XAOJ"eH?nWR2:[Q/ZVnGK9^jQhQ]U4/_Unri#:c:1=mgnUmJnaPmYd7q5(\\:YGE@F.++VAP3I10&Wm[':s!$*/!%5XrLc+5[`?\;uAChn*k+a5g*l%+Ebn&e:3JQu!W[TBq>Wj_5`%CK>oBBWAPMJI@KWAIga.K>uo@@X43.:s4hBRai=n$KNc?%/82S).dqq"\1pX-*;pSV*EgA[%T0J&o:.Yu4f-McAi!hiQUG.Vi8Ld"llamn8?<2_s.AH98"3lqAZ(Oo"n@PE0M?hb.HPWV]IAOuiVC)7T.&SsY3V^SAWEN2F;Gq%2W=qs[DNhqu)^O0ea*WnjYX>pT6K3PG,L/XG3__Id-Qpm0`+63ZJ?]I5Mn?&c+X]\PY))Bl0J@5OEM;/>`P9)_%M1hr"_ch%\eq]LV%S^2jN5N'[@Fs#dd'/p"f&]WK"@7AMV(c,s/h&IMB%tM05L>LK@(8j_8O%(&-\edlKH0eOr?gbMcP.5trQm@4#!)Z9/kSSdcLX>gc5$T&GFolO!gSM0pSlfK;BX-9C0<;J-&WQ(lmt.?`nL]Rg*ku?R(abc11Q@m>LmdZ-2RhKA?!,%I&Dd7pe%\,>DsG2OD5kb25K>?%nK$'EX'Dq[LDO&aJ"tf65O[#&hKk@"4B']CLCuo[3X[PN)F_A:ooe>?1cPh`M?9kkkS=%sX+X`kO'4>h0tV(H\[$GH3p\r;Rq\h#7*Xe$9V]2Z3CXh2XpCOPZgGS/""bA;QM^QQ)Uhfa[ot:Wf't6ecM2?^:$3IUOQL(qaOaRuQsE,RH\VqWoXuG=GBj558/*.0TH'k]=E+1&Nj$T3POlO(')$*)"W2YfX-Ar+E!nmr$d]h\\\%?mGJraM2rjH]Ht'-e-2VV3!76bQ5+'1cYfAN-IJ7NSG+_PV',D^`KjS19fBDc"??O?8Hg_33GqmUH^KQ@l6,Y:KWk':0!E4e,NR8M'cc^F2P&ZO/q;(?Jg81T.EL$IhG9I%d\B%j,%C*O)$gsl@+g@.-V57FUmmhL)`Ssb7-\<[rs`l^HYL6lo+X8PsB`)NetNPODVF9;&IB2\D*e8W3e\<;V5]Z85\*3:+HWo?0!`I1uCc(\8+pN'-UZu.nj0*:?]'=L9;n^-P"ak2SkAR3>us9db#mVWl%Lf/(D`o#TD?Vf68q.1C,G!f;FMGU)D7`n0Zt\cONhdCEbc(Q,*!s*M\7la<>C^\ejqc(ekkW=3JGVX[Pa.Zq=$W8F,@19/s;'c8khQ]'[B/h\B(>*+=K*XJn,bB>1@^QLu#>kdST3IG`=dLpF*>J->+b;%M'[U=:S[\ODGG7]CXb4J$PAd;!Bn0#d<.@@l>0c4/ZqH%-R`?M[nWE.5F[=ih+204o!#>34:r&fDa9/'#oS6dN#3YFQlkqUTe$(-@.^o=7_0ZjHk+sKW-Jg`*VL'Xc.WFZDVOfF3Gp>^hn3QE,;Fs'0trKn\`G8-PIkg!<*HNjp6FH1Ql:?>59l94m=6MaHc6GK>%:MO-3:HP'tc(pZeW1&qTH]dAI=WK,_2`hob_F*VKqB1A']16N2Lj)c^82R(25n#o9uo#j+kR`2oW)a!i`epU8PhdF2c?USkATREs/erIYap8N8b=:$(q.P1lPtQ^+6aZ[jDh7G2JR>6nc#oWON3?i%K`%6k567q_5fT7oLT_)g=gd^s42:>q@66CnI-GuU@@70?RlB)'CtSI.5/5L6ff7?mdp?$^GJJ*>]Jj.\1aRBNpjO4D/E<2.qC?Z/JGZW@A?)AnPt3FZG][r7JOr@/hlf`XLO_W/V],kYN\1O-*4m!$Wc]]`%QUcWk&EmX01ch4NM]hkuJTq``(!p$2O&%$8`D)"2W$oH-<08cFGdRNh(qoQpgO@dR*H4@X-6W,86>-CFIDLi:#t`f`HBaH+u]/9Ye)i/Kfp,U(:^i+SPm-'3loVO:?ER1AcP%Ql!k7do(I-F'%`pm#iLlqWP@fSJ=3O.\B;1%tPK6P:ES:3&*Ren0(t%sP`5aCY6R\.t]L]K&l^S@c,2jLa>2[sKE.PMaggI6??C<=S)Ml$3()=oIqU_tY@bGL#e[aq/gt(5#/,0[WL_6?j"3ShhrQE*sN9;%h*D@DXi5"J-1ijHc1XkVR\,A`%W>A5l+00Htoin`45s4d>IH%&12=m5@&:Eqs=q>NLf^CR"/dlMjt&+OTol[FZ^58%4N"]JWBVd&ierf42IkOKg1lE@p5N1Rf=_6".=oLKB0&&:5QFW%r01NWjKSqI3WSZM[U\""&,a.j!aPC8X[a(K$2g0R.s)I(Q1#9iMM]1L?koZKt`AlNpI/Q4b8lGF>XT&gY7Y:M"iJ-!FauA[R^V`2ce'.W:?>rJZRTY1abO\IYY^F_R4Z'?'n*@/W^i,i<:GHb0dfoMj\[\O'n2L2(I_<"r[dH]Pr(5&$@NS.28?!)#5Gmlrcc\KdNULS7O.nQP(?a;Tn$?q=>WRj2m/;X/S>E,5HoL[l]>FO\i_Sg2b'>snO&(l92P&V[nC-_8h0n/3n4McUnmU'1l"i@4kYF+%p6idD,4SS\"[=#Vcg"U-DQS(M/*5[^ALrjj9T_/l2=m2Zoe.>/sk+UHjuCaS2]r\fmT^F,M_:s:L$?15hiO"1YCD\%IbEUk0U!YJ`'_7dp-$PagNBu?J<]tOB1f[OEQc9D8H9X/ej9lHrZn+#egVItcNQheB8eHacV%*X^[W;]0[EAp:iI(O@r3(M3WUZd[]4tH@JPj,UAEXYU1$*G81JmX^uD"eq\SD[f]8&NNu`#>pho).S!AilSCgsJ'gXJ_i1mbg+?QHd.9_U!kjm2Ym,J&0s*&FoFBg?S^9bJ`G_ia!Z$ohut+EBcD]&<]8YccBkemJNEADLJG?g%!fhHcP?2bIb7LZg<#uR<;@(_lECTF&BL3HT[gT`p(GIE*pf&^E9B.oWd0J42)\a*l"rS_&Ep7H\-a?'b9i:icb*gCTkrI[a4As53huh`SFlTIZX4%TCBod!7SQpT(3Gd3Iej*M(YEqj%o5g],dUVMr&fY:YL00T)`fWqZ?rn(mYYWT_"bfnWQ,nO_..He'dXRq+aB_6aZ,1ok"=3VF74%/4BH.9$V/Uosss8j72T;:QZ."-=ur7k9dP0p&*Frd`gH=M*D5j)JMuPp2U&gHu,@7VME^q:ZL'3\qtR_%H2$A_^HMu&+lg+b9]rRb;Q\^)uZP'*t7VUd_J]h4\UTIS_IMab_+3c[B\W:ZjrngeaCPffSe;/Ro59:Q^!6,)M_a,TsA"5>8%iqB-P+:mrQYtr%<'*eZ1q@WSuJoqYenQJTGcJ_r=A:+cq9`m%qIPhqA$1hsC1ek4?MeI[Df1Ie0bLYWZX@epAdZbM@QB3_C=LHB`e`Xa9/I-^jB#H0i!WcXn8D[k#KM%tXW)hT;AAL>d_.B1*eh3+CrIT!%VT<_ULaBo7N/SQ(+Y_J.+H6MY35L1C%!A<]![3LR_8N@4#[i8d$qZ1gTWH5^#sUJL$t'o"N>eWIN&)'_LCB"q:fuqMZW`HB*M&CdLJ_LW\Wjas#&aiBiIL[Z4$$du:=d:jgac3_#pAS43*Ieo%Qh)4YZb&;b7gbuDN#`-0"1[q21.N\pTRm5DCf21rm+P;C,"[>=m?<,7/XN@u=?CulV@302Iii;f,`e_Z(-`$AMNTKXfqG`8([([sb*r4/mdHdPo4u#%4['k]I,01\HLge0.^aUNU%1tEX$*f$:r:N+p;1UhI(DpV30o`r0V9a[Tr&u4?mZ*l)DA#.J?#/g9Y24C!Ccsr\K@H37XR4WFajXl!/F+kpSGij4j3RAjIpRDYWGD\4)^>rAk^VNqnioXQqKm[V#FJCp5EA$Qnt3DMg#Ue%."n/TkF8K)/T\A6FfH/,`J"U'`jUG_]5Y-CeS4JbE+XO%46nI0[*RO_b#_&9537fJY@l%1hkN&P;I\b\LPc(Ym"Th8[K1G,q?$5_:c.'"-)9P2H"C*/>V,GU8h.(P1P_V[RQiWS3:#a[PFYGa@HRj,ogGB%)meubTR7JMZX]'d"NdNU7s=.rZaE3m-)Q&2UQ2T4Ffp=g7]fpkiaqW=YQ6qEPj%K$WuGj2$Q+:#c]B\eLi[i/4:,e;]"L1F#I@qm;\FLo=OiE@A$6&Z+/3GZ^l$#di:hVFS.f("W5_:/_[(%U"@u&Clh^/JpM]kof:U[hX8DhpNrQ+/O,d9QZW)5qXj]_i'F`nIMl\)S%hk?O6X!&CEL"A^`a/i27uY%sp@Bjue9c))h:q8-4Sj6Sf5A\!G]&4rIJbJ5LO^S/*$gP*uHbAGb+4q^!82k.L@TL++YUM.5Y@$lN_/kWhoP&AbrY&?YV&Q.#J0^Q&u(rE#+18JBQQ334-!i)1#9YX:/])f*L'3)i>SfSZ"c@mPu$\\6Ks<[`7^r4IM1O%71+5(9T)OdR#LOG>/@[Y'l^]HsJ_sgU+@o?\-KS@li7EeBHlp>1mSXk3gC92Km-[L':d$)AcI>,:p2oI)*o6^"Du"'Qb^<9o8lX?4=:$Z]*Qg50_B='t,bKIHb^UZa7Q]glb5SP"@.tgNK#"Di8Itj/,3[^/XMG)bTXkMr8e@96hmEg7["eX)I$ZD6i>`KoUY+c>WU;470[5`Al1ESJ[`7%"S&LET0&-cPM2-aZd)OOc$]ci,tMus84#h^&R"qN4s&CsN4;;5]B>eu(,fZ\'b%@,`L\9)fp2AFffA'.'2W(e#:.3%CtST)Xq7W"8u3?Ss=rg&o*omR-X(hVr[b-JpiJV856QBbnLn^dPUA;8D'tW]?7upp`s%7KUHnUI`R>,(ljoQNSS'1r0=53u4`ll2=PLQeD2!RRkVt3t[gupU!!ejk\(nB6j>A1%h!dfsI,"9M.F-9"qoEk>[a$/t";p:GFUd:U9ijMY!>Ai;`9;Ek_dP!T#HPYuoSAHf7hc0uXkn\l3(O%dpAb_aS%*]?$fZr\)X#VbtV(eHe8CPd@#?(gA$(s80b8^lNUn;kNP7W7cj5(eVK\?ms.^jTfq(iV`*_U7jh4VsHfjl?=X0&%6p*UmkO$^ViDK8lj]^p:=V,lsABD/"cRjD,``f_-BAon[QEFQ/JN]9._u?2*5,)[@LTMOH_r:[U)\4f?4OlkkIQH!_bcV>;C0_Tk?C$[Vk(BO2KR-kF)eY%mdZLKEFR6)H#2d1/6&IQCeoLI)c%tfgNkVpXs;,"DQ9j0>ZY&ZWS^P*Vm4lu/[270R`_!nEob\W7jH>L<*lUA1`FD*Gh*]h`qE$C]Cj8Q00=&k7QrlWH>hARgDi56D*2ammTc3)<+i9?b8]TFh<&C(/?0%igM8Jl7^q&f^?+BE_l4_,T>7R+.H3$c_W8*AA=_`,UeXZH>i]-!T'>W;G6jd(!U!S7ff&@Y(sGp\a;.ptON&DsM0kKf?Ms$0F%8fMV=[Mq&hAs,^%]RDedXnTF@N,HOnMuKQT=,X2VZWMM&53>c+X@eN)&ImfFZi2**n1rbcmRff8[#@BXh1&:M12%A,#,K"Z"GtlA-pPD_9jJL@oH'L:M7;m@WR$>][:-;&*(-FH+EqA16oAE7mTMk8Nn7p?4pUC#^DPX-dYt<67N#1N5Ea^cISK@Qp(76@+a;6aS_:LnT[I3fEL$`_p&[N[IU?OYGORJY5k.Fd-tpDs38Wo#l#CfJR_Y(*^nO&YR=U:1$Q\?uB$\]G`CH070Fh=sr&WhI9#hj0\G&k2*/J]aI8dD>bAq93o6q8;7*]/mNI9X>^DoB`+@YjQ)BI8eZd*)XF0(fF?en1G4A&%u,)W+p`JYEE;,J)QWk*Lr3,jjsdchi=Fg^GebLtc-G<&ImN-08L_qmp.dE@As/,l0t-\.]oDZJDD]]\e24WZs(i.bMX87jQ6-N25(86P.+YURO,!E'VN:Hno%S56[W9tFQZbiUJQmrrr2rVmEe6%ZK<(X4RhqWoKY&qui=C3idJ`<`(lH9h)DoS+]-HQc;=I8!]4?WMm(&S8hKHn"772*Z(lq+AA,(UEf.LXBNd;B[Pb5mV-^L:.BP]W)75gLe%(8a1Mq?'KSFZM/pLAqKg02:OJ#(`b^HkU0XJGB`MBIX7s_h]12jVFk&8]4Ss>"@&BVjMQ91EiR4-(3V2VWVE_f2->;mfr39LU384*JnEOjVg/rd(C#acH6o`L%L/">VOe]*Pa\=$hCdV,5&*u:Y?&9GRp?1U/Y5+*\m:3^teg,m6%D-k>\n\.1E//O`'?8d&L[d3(J*A5DgqM1j=g#(+BMtK_[cFs>bus_q%^=p^]fHB=nVWq8S"M[4][kWb>RbDWZWE[EZ5%.ZM(D.9^3T@9Lf&FqDS]ccV@,7a<61HB'n_K(GG<_:DaIFG:omd,:D']3-Qo$Gi5_sWWIaaOB@;SA*]kVXJWublpsH6XG`)((tmp@>&cB@L[Qi:>J+J89QSe4;gcMb=CWO,0i)TKm>CZp+a^g:]n$Y2h*,sBJ?!j(amZXS+^*XmSHHp&r:T]b2LZI?Y,gV;P"]Qu\;21R%7Mh)6d]&.Z`&fZnSpY,A+/5jb)5NdZ,[10fdg]Q6PXq*pB[DGQ!(Vl??dAEV0c&_;_bk$aK&#JrAn8V1#;9kHLQk_C?AY>A>R'(dPpfCf%m@W+%Y$V=60\Pl^F#rlUlBdE/.8%,jXJgL&iEg*j^TR(h(*P46aiFQPD'rM5!kVPn?9R>)\QbUS]n\"E]Z4q,IX]qsD@J@Cd8-2Jf^*+kBuGJ_+ML:==!NGi(UE9e!qlZ:DALZ/t^puAHah$e5ZN6`QV-lQ#S3sB\n_^rmeB8jH>/ZVQ'9ktVWc:n^:ar=-T[rDj!DFul9RA7)ss1iKp/WpO!alS\'i`i""n#8?L>G"t?C?9uNKn!kG:jB$#b[WCWM#MEQ-R3dh&P7Z&0GZ=0"4e)F1A,Uc6qmuIb%@YA'KBfCTKtSg;k/i$CV.?khm#\03T_gK7_29@f,-c%tk#[:i&EmchfTsYKR=t<<0OJV37N`:!No-o)oTZfSM"+8^KClk40J[mKprf`85&!H'C6qI`'F(Q?kaem/f5.h"O?M3"'>(&Yb-q/<@=#TJ:(NsC,^*N&?J^FZi,4Q5R`sB8YZ'T-ethG1SR#O0m%Jfd/V;]'WJ$s-&>hcdmW+0mrI=%4@,:NL.j(Ya&XBlpN6_1Hkth9#iof&K%XV/PDfA4a?T$a-c?up;["LYV/#.9b4Qg1](#L3:j%,m-tCVDojhH=m>NV;bNFm"DfN4W]q&nk0k2bB"P%MWq$b9"^-Q^2SRE5Cp$5$)&c>Mg3!oi*6?)(3Bn_km0:]MEQ(8LT4FhW]1mZT:Q2]^(HBhNrYVD90#lc6]fq^P8p]Z'#_OLdS(W[j^QoEO1R)UXCKXC5Zt6DWNXs4rod*Da$')ObhP_;DDA$b2m@8FlVH0t2el;W,2nB\icY4Yk;DZ.GeFrTjAiV1Jg0@8kHI]Ch6jj2n(27H21U&N)G-!!5dVUa+i*jq+r^2Yas&OPNil(KhHJ#fW[+@rpYK\5^?\G,qX+MBDAMCc+-`8m<=h3@e>(,Z3c1fC7kWn-TZ#((iaqHJW2"P'qO^u3YZODUkARP/NHkb&EoYJ+Vk8p1+p`Cbnb0JhPH:@DlQ70ior*>i+!*3E*V8oen:PYCG3sV;b[tE7P-Y8akqYKcrDYebFPSH)M44*i7(&A7N-\qcG)K'ds3'a%`dD7t-@'b'hS(mX?U_T"Z[A]mG-ZO3(d1YT+^3X2.;DK$gLSAbgBRW*pjeA@<@gT\b,n]:68/opREE6V?nS'Q?3OqOc;fkgKQZ\5N^f+sDdCB+T095(FEZV7dn$E)p_V9$K&O'mitJl4a/,C\X^kr)M>"HhP!-5\LNAgnQV%XgOk&u?>piLq%B$ZJ[Pb*@`5P:=$Y^+"'B=G//cClZ)BdHF_E$A"P:<9@W7HrE`%XnA3[['Dd`/7_h^lDU=VZ:b^?dldphk07pSTS-3,>R[bk0e^#sA2?q9IL=`4RJ]RsMF$$$4JEI<8f>cfDg^f]=sco(fP+p>RmGgUjF\?&EoQ@pX=]/G_h6Y>-uk4rO5AGM1'DQOa]I\E&>=Y=@\%/8!s^g!c5Zf%q35rXN8;R'eQWP03?$@*Zu281/>&BJ=:e^AIYJoufDCK;CdX^6EE_hjaUMFNF-8EE[e\SrYqagD?VrM/HhHdu9c(r35ECS5ret04Wdb;.q1P^E@hC$`4o<%5X@(5idhRp@@k-aVebDt>J(INa%W)I`gm4E.LIWEblMlLIso6WR50,!U;,4i[uUZ2/nQdQn=Dc(^!o$Ef-bI>m*fd(7m]%o*$.GIq9CuWZQd9DN')b7F.lSRVT4T/72fA>A5*n.dUWh+FpS5l_/)ps9]nP4k@"7T'Gt_`fA5fX[d@%7Y?[]j[nBj>RW[:"n"h;/\;U[fIU?C[7=b,JFjl-m)Z"YY>=-l^`B>4-sRq]:DMr4VnLhQ)*"8HK%A>T.8:$2l9>SIW7n"pE*tOA!lYbCRr<,dHN[?k*C9s^D6:WEi8/\,Pa1horK,'OjIY-_SgbooZCEKqftdA4P'8tn.$3HB3afb^NU,V8>*jNc8Z6`OF?oXM?#[XBRCHl3N,V'pS'r,6LDC0mur?'f7OPWW$oot\!a[m!_KAQX/Z=-)^62gb_J0<48@L)7l!oB]3-)ls6(i_]S8;1ODm_4Ou(NPaXb*rYYqT`6,X5*ZD:)Mq-\Ml^["$dXGN&>^(;s,G'%DcQ%1"f9Apqqu/fSZ#$bq3D+1U`2Q7qRX'-a969M"mt+F4Ha/4Bkd,0/1t_8?Zsl'8Gf*X:Rn<28^YP`0fh\r`i:2rpk*eW]ZIhs5BUkZ##%:rr9%?#fFIT*',C+X&gWIg3DD#Gre`NJ?@HhhE:pF@dNL'.4,s]S\l#tjbi4)NNK<_h!H#(8pJpe'mje&s3q[L)6FF6b?I.FDS\>6E(')oa8jtGP%9fNoX;!)p1VJsg+ar,pgDh%EOH=k"iBh/1V`AScejna;9rZ:+02Ku\aWq^'apQS]^HMq19A9Ig:Q(#]#:A$E^3Kf;19)C<-RU:Il9AOfdb0DF+B[o:*ekW1#3iSW!Hp)qJFSt`S>^=`=?CVLB_>:f)a'G/frW(Kipt;1/a&:@>b2H11c\$>AP?'75+!gY]>ISIZ[?n8c_X4SS/$b+>fc@cc-Z::1,uer0)d5+q[1B:bu!nA]',]R/^X<$-%dkP#:lXkOmkn-a0TR3W!YIm^7=,t6NP%sR0'A89G\.u;sL0djS^4Qk7;7&PK+?&iFGXW#6Q=a53F3W-'uBHmm:>1OjX<%72WOOS\(GrlR:$=SjTU7goYA*Dm8j-)HU>9"eo;A<(i3G3@huor!ndq%`ap,Kn8`$;B`L)b!4s-;n6a4ORJ71aJnB&(['9k]'[#*4(=X.+G:;_^InHVlW.kIYnOA1V:(r*6+N/$:6CGSK`gfdHhu?so0)ECcY[RM)KW.N;Pc-8=lqk;S&6N,>8ENN`6dJ)kB6hAM*,>Zql/8LdB'WjkBCV@S88cGqg6N1ppk->H>#I$'k3tRHG-BsUX%,LbNh3to`_@h(CJe4$,Bs+H@D$R:;3\hc4.QH'7I:2^JYpiUJ4X&C($:3@V?F[E9@*Sq,Ll+`/1Lf#Cb?"4r4PL6sj'D:>5FPJj1R#PmBPuj;H[]a+UdA<)[%>%98%u*HSk]T:C3)F6=@p@SHQ8Y\K:P\eDn#C)eo@qisFQYd^^e3X7Ho`5"KsKA_6qOidZR`ACOp#uFWVa5tHI7r&/Hk]oB5P]TeQH-]N@j-T/]A0@@;2_];jqpdCD;!+nUKH$gHUjTT3g3NTh3t3?!.4*qMmjhT)Lj$R(dT[]Ct3c;O"$PaSmZa<:,p:$(9E+-Gd00g\q+GI[qV:OHt'M>h)T%8mMBf/9[K1#(OT+[%AGfBt79r:Cu_rB@X,1>3s;`4o522kc$B+Xu?8@HIe:M&/P.Rdp@i[?GA?lZfJdMD5@/6d$$5`odM+LjuI^[dgg04]6@$dWahfRO5g!l8I7Vubp/W8ekH+BMFd\D&paJS33:(:@;9u*>8\`bebbuB7Js$08s[2_K9;pg+1`LoIC3V(4#1Kc)&.OTTk=QV#8`GCVh`eho'n&!F)g^$qbB(\S(-JlBYa:/5"C&1,PSk*%!9M'm^ePd*GU"t9IYib;A:<@(SJ\q9Rqp)T4a9"?M#f.1^h+V@7kQG'Cn!--ck3(qf-CDN^(BZM`7isAdj)N6qnOQ?fhsNY!m6nQR$E.iT06V1oY[tps7Ro_oWrE;2BbC\,,*24$5`\qP-r$a6;[T:YmFO7O4c8i">"e^Yn)/UNY@oNrCQB0aX6j+R="4933$'`V^6KM=N8nJW\(WD*,'b%eA79V,YgE7Fnd!'5N(>kj7)U-irbVkZ5'ADO+eH(_qm(U^CO#Jl'T7W:_HGd9]"&feU;.HBd9Sg#;+aZ)1dVPgZ6E*Eq:>A2uA!h*DXqBcX*^-#])/gnWs66''oI1qd!'&U,*o9sQ-G0oB=45tqZ+35MM;8GGM&2-rt`sPOUK[J`4YiWG.RVKEKusbG$@6X,>#hE]h[AVri*BVTiIKhNlg*g-UQSK;)s;aMACI4=>lg908KFg_ZAQ0)W!X\_+LFNA$YUC\0FPb7JQ.LP"^PRCcMrSe#_]#7dN)/(4VtHpnon5I&",:BNZH=i:q_)m\Nhrk9,2-T+fd@E3_2j;]BahlY1JZeg3MXrn0_jl]FkU0!%26\t-2k6:)\J6@@Z.m>*/O"I[t='0Q5hr1-93m.9W++K9[8mV^0K,@l'_n$[(S>:Xp9g2:foBsuc%Zo]fX9:IM]5/c5ec*27/1V7YR>uT"4^4kVb7,I8q.57e#ieG^nh!+Xk(80l/Cg],ngk7@/d@okB&+V1k=AD1*;h1!nfF+t%nB"]qXc3nDClUE&"#Y]F@qMQ5Tg%!Hd`Y'fPO]hmfiNZ!M9O5eTX]u?;Up%IM7hi5/+ERN*jc%TK-,Np2[EIoOt\\&eYcZZbK_U#b5X)cJtn=&^lBPD)`F?;Xj]fLDg0"V4WDEE+mX'jVo]WPF?fsc/#Nb)B97PE!L(+iaF9<[L*p0mgm@ibd/>Y"(VoQ$haZK1F7C)H;4JIAQ(G\?^,`%Ggoo\^;h;h3p\k%d5?<8DF-3mjb7W7jgUN19U*IngA('('"4/GHGm:aIN>caSuBL.Pt2MHl%h5tf:tXDUs.'YiXg<:H#\[n9"V^nfhlXoaLY3EA,ML[DM)gZEEKIM^9p!7&?r#7b#IOpuPH5f_kGK`rd2:0^IAE/THN"IH4X8Rp4WM3PLg%9)S(;+`VgAa=_HZ\#*CDoA)[Q@aXtO`(sO@!//4Q9O(TO>@j4A.qao(9=+Z31`knnFftog96A!M`[oM#^:3IfBXGs>Sf!h<"q?!T@N'I__^M&](dK;R?S^C'$nUL^\F[Rjn4=)GH&YCT/.>o6(3qU0%&G5i$=*>^Kgh@hTQg3BkUl-k&Nb8_kF?WKUZ\t+Wf4a>k3%'/2[;>Jb=Y4C\04:ZV]Iq?#P7B":?4!3[@7XFE8Yrq',+HKWLk'5,@eiZ!XtP)GAq4J9]BhGG;T0ijj&P#a/FUPlbGSD!kSSM9rq5d*d2&;K3p]`Ola)1)M0dm8hXIS+rt.YF11m<_pg_nkQhf*>'kDj?.OYKeJH"]C[e#i1,:8udqQ2lYD6I0@8Bj_`rq>UDRO6T2D1!eu8hIc?`ajZ*9hSO.;EbU*nffI3H">n.W8c_]Mr1%Y5j>F<.A9n(Q,7:t-hFdl%ko@'8TJ?HP))8+HV-;mP(K(BJWZ"Y;m0tUnu&a+NJ7eq"fpc\S]jf""7f@'.+\V)d_FXS&F0_RlaID-kkb4iHL;lJY,-$E(brnrgkGPd5@mqZZ02\]\G2DU)8&b+N.,ZqJ`*nJXWNo`C:RRq6?rAWAl#)k0dt4iqeE<2]b!*SE%HDT_\1,hf$OqBhsS?)`U&`[H8Eqq4'98f9RdLJN945,q`PE0M7$A7!0`>D!9Q:+9D[8^9:U"^0Xn7mfr![C_jr]-"f^r@f3HY>+&dVYFq!8s:;D@H&mRa`g1\r8u^fLkEVTGkRs)0_5uHf\>dFBR#lF&Z-o2+p]%h'EJpaE_/j*V-)!r6nO0X.u04TI),4=!`EUAWQ\G9!,$,e,h32[0*72SVZW(X2rE72m!TG\cGG0/(-i_UUme?u=;Y\X1dk!]OuX0\ZVM6"C0aC,:7sNhZ:$HJR08dh!qQs6fW1r_-glXKN]hH`]e="rp(cJY$uO'F-(P)m*7ua.MpB!naN8EIRY"q'@Nm55#r,18nF)Z#:(/PWF:-',XQljk1Ska_RBcoCM,ltl@=VrDqNMO>mPK#g)[^Xo.YaaCG^*IdPMH^RpM@?1&h)eN)r/CLk]1I4:(sdP,Xj$DMqE?H"-inS,/=J%%KV^tM4mCr(I#I^rUm/:%S0jTb)CQ!sF'98-p3ZF3eQXF,&_48Z*j;@YB=QO(7rG,JP(-mFoHE@>EWL.N;p@2)68uS%'RijNqk<'%+Ocm9d"9^LR\q*QFU$+g\!>RE;Yhi4n_$_&oj<-iX'KRlUOVmb-W4LqR2)2hWF"ITBY&lK;gYbJ40/8F32UW\9MRu_m$H#F)4RqNII.G"]Hl"T)M'i;sl(^1)i6eVeOp1@8N6*o:()[hF"%?23??+Z-2'uL5CPUKQQm0mtG+(H!')GC^nggo5nkW]b8GZfXoD!%&s8n'3->%Y8Mc:lT#!:`@2;e)h5d@A9%e>fMO95.igN0k1[8[]snFQb.&"?F1Uqk9pn*S3i7k2iMm-UL0<=EC.FVDsGle29$E>!9d=k[Mg;L;Z?M8d:rF'P#mhEVhaBE,L_jcAF(l*lW!T@&!3LiB^[F5no0[(%c,p9]2KSG$VqS`\c_p>SA]uWJp/`sXeBA"JK=a-"0T8!hGkM2OKZjb"V`l>iNM1ecCe-&d2q")A(AAB@)dKeR!ib'jk*_b:6oGAPDgb8l^tOOSDn_eVH.=5YT5TL-QWfeeTtuND=.ci3pDN;16Z2W29[O/Bi`9!','3WU:JlK'T\<(VjCJ.DCM%!27+]dl68K:G1F0sZqAd.H>EG;-JZsaJ%lP=C/juCdeWL1KKP8s*cGj3oUUs)UDT3OcKEeX\eYI^U`nnN:5nkZ*^U)T3'O%B71;F<+Z&&IdfZ9U.H[&f902Q*7?knV6[nnTCNR5;r-dM/ORZLAK_M0tQj2QDL!2Vm\Cad5>fMVf_;-LWoi=o-C>RWgn1$s7M"1#>AJNtQ\U.3?.iG`U,GfS*-]O/lI\T[0+H6@$QSk$Ei2O54iGHH%46#!Qt"1FpD@I!hR+&QSBR6T8KPC0hKkj"Z[Dt%qdS'6H1TLH^o*-W*H#MW2G6WOO(*ZBIabFiEuHt]HLHN^KB0$f$tdBBaGY^p,-UZD&'!#spUf9U'OK))W1Jq'a@;kB?F*LHiS$]hj(nnO!.`=@KJ%cT^K_;%lsSBK35V;p2e)/Ur""[S>1@`Ka53s)75=KA[NZAC0'2\F&rFEZ+g-.+7K$>p`YE&c-Y<[AA6>O/\oQO+ekW&I)7Ho[qX>u0q/-qKRshQfp2!7gAT-HJX8P^%p@-?&`k+9+kQhdT%qu?I7)1J_^IRtsJ+dk[ra2mZn>Go7UlYB3^YD^dHJ3;-MgrirV-DjFs%On6AbOl$$K1V+PF7"#"p)L&(]b&io=uJo!hBJ]:ad1qbm>gqeo[OgukR96ijhs!Q]_h3?PoKK0d'gljR2'&*NgR?[M5^&D@,!JI&&0JH;K?]fS6FQ/#G\HfIcU>3^b98GEf>^)t?kM/-"#Pm/ph+nre;Bltl7-r"'nA:FE32?)LJouGbYiAn'9mPF.DVN29Z`T-MV1K\2TOF?QSi?.F^rlE4[iNE3_c)dh(sq:H&g+'#EZH]>Jb7iZH(Z>3>qJ..X:_C`R,=BDQ\KDdp-7VUc/K,0q96\TB/7(BI0!1FF.0BQ!@/W<4VLHA#g>_b.37,`7OLr9BdN;r(0n>5)e=W2D?T[B?3ZE.u1dAZB7bG#4lA"MR^`I`o!EAtp[luM7TATEap\Ra1=%+_Pf1;E-[Q+3>^KNjF5.POd9169#f"r\V1k2:[`nYmEXdQ24'JV5:.VB>I,gP*+l>mZd+JF+&W<^Bg3?Qnh\(ZTihqmk@rb'.F"0*/2R^-E'3B6H]+CDsO&#'[kD3ENkOJrqYm.m6iYKr-WI!"EjoAsr[9bb9bg[^Q(2m6ZAG3GI*A>O,p#ZOXEb>Il/Iu&$\7GPM:Fr=_c+k1\O9E*0*$eT9Z%+.IpUE'6IA=odGmU)96kO*mXrEF@lafTKC@.gb0EU\bZb]1YUfJ$Yok<%31/su;+gu$S>E1;6)'+OX3]\L[lqluc8]nb`70nJNbK'"1^(Mak?R\dR;-3,I_XFLS8mfl%S*)od5%HHud5,\:Gk'rN1InpTV7#O'pDnric2iKqs^r/%*&CBSe)r:W/hDr9aU5'rilGMR@#miVc;0GS'-_0LBA;C/"jpm7jM5K?r!D.V5anc(giIVl8tn^6*[+UrblFcP-fp[&pZ;D7Y\@U#)V(cb\V*:l?:(FEp0r_Ac8b5?G(_,P(0k-G=^@EQABNMsH`G7#BC*\DYAAF"$Y%6Lfah;E?Qn7,8T*6V-!HkV,`p,o&bO.m.-13&>M;G>F4_:T;pAMg&#)Z.@$4EgB%4X:Mn!ZaF*%QK#BQ0LpA8PE@Sd\gKQiUMXhGEn]9JaJlL81^ClAF8XWqs_4:SVi>!1;7af,ZQm))Ms$QqD4h6]"%N=2Ag`6$sHcU8[D6+ACZYqCeB(j@)*0+i*0'1`Ymr*s$4@99Ctk\ePd:9QWBJV>VUo*YDG%cq&]EJ#q563GVqk5-ae[PVU:gSfWg%M[lh4fA0UujQu"J:O"g"GH:Rc5%g3>k?jkSH'Km7q9Z37M7Du/,1ulLrTj7%.gZf":0dg/Kdc:^`"["P7qVe4$<%PpGs;M?Ia:pjmf=BOsa#;]TW:Ys2MUp4aF0cr`&F>%h^tqd'GGV$&[t:.2BP)lLqCEQqj@@$H2P"U@7>n`2gUK<>(4ob@s?4T_RA3>n85%G7V`sV#qMR[o[>I^#jdhX@Z"(D?r.&3YtPf`8b>>4l,\"ELZhdlug311UU7pBB>AlGkgG@?Br0EZEji9l/V\)0mc9s+s2eWLoJTc`#WNKgdGf*7^J)=V=8[fD\+Gb>Jm6U41Kp:!L$ed*Js^dsS@0:!=PBA^]<`LK+I5]s)/\s5Ic_0QFm7;^6'>9O'RrT8880;uhFp;q[C0j@^\G)'6Q#7PYNG%:N')`1u7G/MA@=\gF=[RI:Zm#E6hS_7ER_1NdPqq^\E__B6r_BdRnWXWPc=o>heM-mG-=e3u1_:I@m:/TDnf2RD[9a9$@l71lU^?ol"iTr7<9p'_AA4`%=S!`gC\/J%XQlZ6eToBNRMP9I&qOs?MhD\+M"eE#KEql$Q,895sU1/t'N2@2B%/"BiCUNT]J$C582D0rXkpU@/:0N_Mn%X2@lb5A)A7OCd6TUDb#gHJ=Qn3K:4Xu2mh7@UBBLQ5M^%_+Q+A#:_$X@es3HHIO>o-2H2q%jh4*jT+`[n^Dfkg)h1*)EYEsS;EN`Pqe*MsaKjY\:L9\:08XXeO_NuM-(W59?UW;>'SJJ(KR:aDNu)'DS/107YAFrGOY"b[LkFK#GYCQqVgR*-p/`!SBrI5$p>Op2+VdXWb5'AE5lW7mntmm:NQ>6rMDV?nEtO@L.U_hhnHi1XaD\po&j2&?,*V"8K6HIodS=+WQlm$LaaTqW(CN'5]u2B28h]S0g!";bN)6&92@7^'quE8`X8sb[[bK-Z_M/^AP95PH7*&+mFa/\]piKsWjnm`3q8%PVN/tW5d\nGpr9`LoQ4fX9W6QZm>1k7qlDoqA/YY1pn8I.EVu,J2K-L>([&t`#9OE"#h3Xrq;?g/IJoo7Y6R,=0-N'qQOAn[[du?u`iB`AP&N4\I3`geGYBRC.5A=TtXtn&0P_2UdVeUl2gXWkDNfm.B=F@%JA)^8mrd*;=$a+egDW6qambGu@jXe[gIU\NB9JLm>66he'Za.aK1E]f%b-=3:/%Cc:6:<1QEDLOUfVc$H=;is,5FFi9L2's1[N[mllBR,M>:dE'"3=md&akgf'Cl)3pdbI\tng,L![O?gTus9oYkT#.5_r*H':dNi+PsDFqU\TB&L!HgD3UEl1rH6/[BP"%4r:L\;np8H1LX8P*ehVL]SEf8`O0Ai^)`2lR&.l!q+"*GlCEE8Kn+aQPQ`<1\Dj;t@2h;DL%*RrA5aG/$ed!=IkJHX[[P.S?>"hSetShE:\de&fs,q*I8fEd>73!LE(e3hN(5_'R`oA@pXpu4EG:;Ni=#e/.H;2%>f6ctJOUtG)rHM@;@@5Fr)44oEen#QS7-0+9)3BhH(l6V$Cg/h2d<8YE`hl6KB(/Tb3#EMs76H[?Rn2NJIp;YX&!m/a^nn\YJ;^(*N]+8E"7+[C<<6NIfI&qG7d!ngl8SbN3#\Z$i:\prZ&J.$ZWjFe]>GtNjh%$)62&=EU67M[UG&r0U19aO';e.,6WXMJi(:o]W!>fC3!Jh24??3TKM8O.rD?NB&jKtS*.o?q3O$BZ6KKImUL2JCLUISca)M_rS(n9>?pg#Bfa-FQO92=RW83$6mX!Vl\5X7=9j-=?nfC_).nmqB,%60g+kL.lNf_)cIRD'`XE=Ii.N*Rbh\j#hn)gAkW&-MgEUi9Y;HtB.`<_n6W.g\VgL>VW%%qqnDKBT>'DTtP)aT3/B91%#9kC4$WE,L4Tqn.n?DAqrG7oBhmJuD6jf/8X9C55Yp!!8LUM@>.ul@HmsESq9Zp5/4<+Zp2u_@;#@O)s$WF2Rm>p')gD(,jrG(;s=+5P>A7ML\pCH9DK[\C+m3['7\EYY5nKPIpSqgrT*H$kmUDirmSU&*n#&lKKQbf&7k4K8^KI6#TrC"K(4>`&+e4l_:`Z``s.U!7%-NM5;F#CGY4`dlj8]l)7U_0.>+>/rL@)"rKdml+.6k@W^J<>B0[Mi7V[%!)`4K6i2btl+8?LEQYq9\tt)(PGKKCep$+5kQ[0]t[%IqSL7,a(Y%gpjc'#O1eL+3Dh60O)>g'C%tFrkuTZ@QQc?5S/G%DuON%kZB9Bj*\\^^)9PQq]:]gj`_@ZEiDfBf-`<\HOo.2kH\p$acRo(T&;"-_**'$k[21k`c1;FFLW&1:VSE6,TXe#An>?SF-3!?6YY<72E)A-;tKit^Pe1@@r.,P.97'%35uW8ZkXneIX@$Gg,'KHVT5Tptpt*Bju7l*0G-If7F'#H;oakVJX*RKc]j_(gNTR)>!F"0@gjqi4m8.6C20Z@.5MR@\i`IW:S!p*ZtnO*a9j$1Rf0qS#`UQrY'm4b3e)i&VgOk_=2q5\+&RG?KrEnDNYZ:!cuT-BS!&?k'LCEUGeBKNm?Mb>1q?Ca:o7&539>AFO]6K=G#)L[YYN^"$>BFdF-&^K/OAMI05m]82P8Ig,o3]hJ)aNLD5kY#Y*Pu4$0!lO/$U>1#;`I(:]*'k[%0&&WEfmuCe6pH@:s;c@5mHMY.7Fd=g.-7q*&5i'-Tn5WmR=+SPW#kkbBB+E20=&F3&:Y3qpq"UnBK`a889WRNXL"R?MR8Ie)hVZpqNY6MH^#&sof0H1dHJsgrqg+X]DrpM'C6O.R,=242#5:'<07]?Z];+a`;S^<67dM/1]"64g\cc%NHC\9K[p*W<2*=cR_Tc$\Q.kYTV;rKWhfiW']#s:*V,^do\qojc.j9b0=q9XTQ77:Pc3u&>qHifDMMu!BKS<2T;)E\)hDdiCLqV(jCq^U1o#;eUZeURn*W'SZU:&s8VL-8ua49<9gPIF#1L7(kD_<3IX7sTlkmr'ZfjYGSS)n12S'(O[:O-->c!$,Mm*2+%C<.;5OdjJ('*hRZq%NdN#!:]d(d/i&fnp@eCrKB@R2oKdg>ob#?oQH?`;#km8TP+GU3rNZG#M=>b3'0u:@9Hef1-u_rMLb4Q-\Y[QEdm,Z""-BeVYW@#Opl,4.,O=U`79GSU7+VIB[pPeTI-9!r!BD<"Qk1]c_SAPL!)]EOBqd\>9[sZTW]h,=kqFp+g!_KkkY2>1%^B?I%Gb:lnUE7fO/2`.<)cj41Y_1VpHKn\mQU3/rXRuVmsMi7$mHr=&^pSIcagM&[*YHcq?+'Se=8cWla[DheQ$p_nAQEgQ`**F?[*X5coOuf1"n'>aRfJ0mgY:kiRUM_U^O9A^eUnl@.+?\r/(*m?`lPsni,P+UNqCS;7J\"l/pj/o$1]XA:)Mh#2UAp"IPeshV^i*eF-n6Ln/\p4GfL:g&lZ(@ph:#k$.q$"Gf:4%NQH$A1S;+IfD\Mk5::gH[7Sor/Mk[cQn"7I1]P!!caVQ'`EiP<,)U#M:kI:lL+uAPJaZo*Y(pAq_-Hn"6>4.EQM4,5l$ATT*sk,"A(fZ5,Nj*<#6BAg]?;%_A1bEA5?P^4c,TSm[ZHMnOF85VdPBd3+As\JJD&C$?^)FN0R(0>`kS:TR>fDbU6./N)"R]DqS)o(QIEp]0[b%FP,sC$qrB;qi;S<4e]gN4f7SdV8+ikQ]WmG87@gGKLnY#rcpjEs.-LM>Bq_L[?egEsT"Op\3osX"&-69(jKf$p-=_0<)BR0bcM\adB;V#.mr_r&FeDB/Ar+l_2h#"Sk_S,i@#Et^aS\m<-$Ajh*WuR*MF2TH]DEOp]Nh],acUYNn?Bkj\^<%ngbZg_d="_FG#a;m[&rp4^CZD4o&ZHHI(^EqNFU2r+qgE=t?bAPW*JBfCLN"AK5*;9&m`T3aKF&7_Lh%,lp1a[.!St6gehs?a8$0W,s>/.f`Wj1"L/XQs';6o3X`acHUl0Usp!;Tk0-!ZHohmr\M,oYI?N]8>s.;J`@^GOO%qR/?GbC,H;JMTDP""bM^O,@sDSH[X95)>D#fgQ;mIYEOEb*"`H.4/$@0a9F!B2IdLNd$7$GN3j9fMj5n%-N!0hkKhd*&T)@YAfWJp9`o):?'5_n4:(Rgk"EQ4;M"/jD[dHV$p7@Z.gPE';:SGIlM$+k/u0;!g2XT_"dPXn"sJ4NE"#8i`N]n9i2raBh:@jW(lDr:H]4E1(n2a*;N]Hk'Jo*D`98HR+p)SmLOp\liI!r??5[c`lFl8*qHg9p/.AI[BRbsG<[*!6`hsD:dni]C8mT#.Lftn;W31`FaA(ahh`[BkABV&_pj@,$G!*\0%Ja]'IL9rQa7.2B&WR';$_`@V5%@>*LN6[_i6#3r<&P+gP^n\5l,/6W#koI>NoX2Y8@DX%`0%gYiDbbN7Nui^H^G5QuYb_C)DW0Vo.m6(b1EAX1sD\422rt]h2lR0qqrHA-ubKeYD-P83\?g,@AlKCa">_XB5d!i4UM=AMs1kCm%30;!R"o'G*tP'HfaJ7bEU6,;GE%/3l.O65W%".F+FtZ8"n,$:F%(TOF(#:[=OH\=6@jKWs1T3L#Y$5:!&?b3s%S,^W_Sltg(696+Q(rOi%*/EU!9,$:@VcNR6UOlGn@oPKjdjB"ft5f#A:uqf"Va@RAugL$/O3[cjbi2NfsJFj@EJ[9EC4s&/KRT"HEYr1F+4en,`WNb6p'QOBqiF0@,UK+j!2--^iBr"b[Q3!/V%B5#5Yj])!d:Y>WT'E.L(7pOk[0cl(Ya5f4\Ya\S:Vq0WW)k@P1!-6'nYiuo8M8WkgD]aeXm)%^J1q&0%aE59r6Wd\3(e8.bpp1gq.h.=FFskh9Y_*GSsj6&l(S<&tsn[+V&i@CX>>"'-rU);Btk'C65Qcb<+C\MT_4$@'sfX(X2XL:j`I#Qa@!6,'FJ10>'f"k_Rqk795qC]_sc!U`.-akpilefK?as'AKhnGkag.O6Qj?TNj5gfY@)'gMm,PKI&2;d(.S2Od2,1I,'28;Y*VgcII*2sT074CGEf;E2,X#FCV/R!k@G#&Fke%m8;X&t2?76aMu)^>QjQ^M#67Z:TId@(a-YLRJOe\mXb;IQ"(GCmZ6/)f]_bIX1NZJ(!ZO9;hZVGH44RZB\&Fi18_9a"XAk%iP6[)LC8J[?XM'quS#%_:Y]@%GN_^2*!(jW&M+GsHOPluSFf!_H?;uDXp]o:,0VSLl!=:,44ThJ?XF*SGJa!%2TLIU7s>&qc]/cR5@_r0X"GhOHD&o!&TSr#2^7I/h9bZkW'ZScO>L_["QE@!Vf"1dPo9l`&D^9JTs.'A8/mVM+f^(8OfCFh-7X$Ui#GAS".A)/>n@.W!klCaq)CILKl4"j?fsWa0h*jalm+KXBSMldQGIu@!.e\u(s.pP?pUZr9/&W88.I3>*iYPQ5/mW6WP/ID9[M6tE0$)H1]37C^GC60#,n^jN+,j^n?_Tcs($NgVl0Dm(US=p1e;;.LrbHTJE=DJp'2cU:QriQ;5!+qIinQqPQ:M7.Nkub.:Qs/Uah%c;5B$s!;<3J(I3Qo[/&+DQm$2;jPM*Y5!P&NlCY4ApaX8'Rg>a!_Wr6FpchX'psWpYY&mN2agff#-M][Lc[I]\LGr5lNGQZbsPm,R&rh)gi)Yt5iW8_i*5B1OuZ0Tr$<+.Wn%^(VT1,BRIB>EM#*\9NbOXF-2pK9d%cjgK2T4/oHA_\3->iR@MBM4T$!2*QlggL/dE.C>H#&q]<"](mCk^u[]C3sZ0qj:B@tVHnSNDo$\Wdl$!WCoD](T"ZDoIj>uC5ZWBiF8@tZoL4nVh_jT5.S[+Jk":9X4=9P\cqbU[>CR,EcOcuISHGaDLX%'8pJ'H6]<$&7bN&I_Dr6=mc?EEt8`**em?NfFqEGc;lUqslN_=\3VN-%eDsYbN?!p\FPG#^2$^G)h]2`7Vj46&:-#T6R7M=RJJ#!9qQ'6]kK(fB6nd-dVH>#W[7ZEFVqQJRmQ&jb7^s6nnas/R*NE6C77IJXiRhOY[Xo'Pks^W-!A5!H2-D[.ON[\A4\J.b`+[C2Mq[Q[qtAV3pF>[`OS\Z]7W]"?T1O+aKWoX#_*9O#mL*1[edaIuY^educ`1VO_d5ZKm-J$i2$?bV`W5%X\;STBArpcG*d[u\NDRq/QN_"qnG%.l>N9#9gejT:ojl[eRt+0H,O<*hRWEJ7aQ3Y!gYMSPZ`^[q@&?:/-u@/!,fc-:)[)$WU!oAag\IA;H$GInNLdA3fMFSlZZ/aNWJ2El@-bA=YdqJ3Xe$a!PO*M$:LK0oA#%X;Cl19=@+f4]A!YeX;lAMi\[h#q1^.dcqM>DB@;D\S\_bLZ)g8Tf3c#:;N[2d6MSjQq]/1UBj?D_qqbN+#%lVbX$N9#n!S3sPp"5r\VSgiBbt!cTS$!i3=#'PtkA"DAD=X,jdg0g>0P#^6"t`1S-TE`R>B\G'1RF[Bb?XBYd[@KT_$O*Ym=0;iCF@RWMXtYqd`1.'AYKel5>>F@6H4/'!Q.T6V&8%["jV4UAD&jB8UAB^03aWGQlPfO[4*VF%&L?_heBOg+H[\c6>EO,V@g!WQ`\$#noaS[uU(E8A%1QM@I4P8Rpp!>6Th[09iIKd^8om9gg&>YC6YE/9%)1Sjqq2Vm+2rMb@`l5CQg^6V\QFk$C\2kX5_Zo%?YoAUG*M48!-;J"cj*'cF,ER;?jS&+.Bgkok&HiA+',!kC1&sVM:l-%+,W)&VL33hf@@^J-+j`9XgPD(C$pu6+TEcFg7SHP<\J-s+;F#/Lfsohh87i2`7fp9=l!Uj4@r-j8R_2(.kUY4pKJcual80_a9gqr/^UO?WGQBh4'd7[B-,C+5C/AP&;OJB<)Add`_m%;X?\cXC6hl$<8i6R47\R1F[Ql>8aIllSmZ4p(gfYMMX9Zd5IE3mIX@\P':U&@.Un.0a`Tb6]0pA254Q@%h6k3(4BuaIjNEa-nLN(T]4TG6ZS90]mFbYT.31!b=SsiZClADt!qY_MXMs=+;?#sM)ONoNUF'ePr]X#>@@j&[&9f:;lCmhDs&6t&6b;F+H12F,^$i(f[aFRULkIIXR+u_7QNGneP#Ps2(go%C7gCH&=-%:Un.\-_d-lKO^u2n-"nN(X2i.ApS?OZqcg#adJTJ_ZC5;@nbN7gE#2hD[G)AKYq=h%>A8).fUBZCj-,8Z&a(d<4H\IU2.>rnH+VW[a)ZV][1o%2s4(CT?n1$.@gTgf-m1.=k_U0^gp.3#Xebh@`r0^=+[BZ*QP5m:_Am7E4HKl*N@umBQ"k.%HGMs6\?Qui!5\[Y*;d1<*3OHl1dEsRkoCB);>5^eD?U/S1'1KWW^G@h-X`J'7sbs!C6A1WR0*0@H;Q+GT0qVeOVI^>7m,I/dJ5Y.XcbY;qO3kkdV5Xs,9)pKG[\+0`k2ie9X;*O#;6`e/EA2)pMg?j24Lo'>%d8-KXUdP`"rMW)0_bnC1,F,ZPe&s$%Q1[I%SPbqOla1TfE4UWNm6aBoZP=':L8`4`agMl?f")dd$^r5O>6?.N0A-d;IM=1jha9/A'9_!@gES*D$4]aYBQo[G[F?Rb,EZVDQ4@OW[(d&A+X;Z+##+2]3Ec$XKeO6'SJcOr%Y2b3YZ&1QHClu0_,I.fK*h'LB7iiE5X5PdujV9G=F%QW?4BaW`0cLaf'uHR?+D70FB<3pa-k*?;Mc/j-?Ei$/mtX]#p75M\WdJ-V#sGp_-0a25p1=c:<&qD]l"ocHCDD4^d.5+9bp5R>PJ)ZlXPZ3F9V']m'%sa':h._L*FD:eX&""#j/(9'IG^5;<,dr=;:JW.Z8?-2N-&#j9O;Pr/)u(6h6Pb;gE!@=G;W0)Dnp=4[-8C$jTTcVhl>j'A!J1krI*G)>_(0ZJda1:%3pc,c_qHRk)MT/?MAh;uWQ@tW*P+BeLt!Ah$Jan!W%_ZtSIj+#<;#lm+Jb+MTo"LPRfs%=bVfltHjX$qjqj=.+m:0]F*I_kogBGU7&;#+2A/_lE":]3*V3`\L[I.I^qhua'[oo8"3ks;TLK/4=2?]uJeD`3qA[f);3g+eUT]/1NM"5gl!f&_V^D8W@<'UEeg;6PYDQr"QHC)]ica[[?G3g/A^M@E3L48Rc"\7d(Sd8=!PD(\JD%?j!VqYZH>G_IjMS?M&JOFHF\mR$:NsnN%Z4n32?VaQc@Q[=X0](S$ua?-*HsDh\@]Ae9Lq^d,>'^U2s(g^liT%pW$IL=4)3#0P@E9AQp`;1,[3)iEOXP`fR-&(6)*aA)c!:J8nt@fTJd+7&eYg^pZUF(M95)g#5]\C:QNX4]QqU*kbGqglR^SC\05=#4\GnjBs>ND6q#rL1DZ*>[dsCd_h?*89>er7ppuhei@g>%U=UuKJ-9B,[R.81<$1m1EOCuNc>SlM9O%">h5KYk-JM%@Blf(#Z)jV!T>X^V*eq#C_>^#7$kQ]2mo4&]m;s1R0Jg%6_mbG6:*uJ666ZV3V'F_eI?.gq+K`4irkL&Cg8A/;O)3c)1rPj%,G$Y8Y4tYgWdh=/D/1:rYCc\ff#ZHHNqX0=bT8?.%q5S?oa]Ol+Q\L0O&#r"DG-\<7pseiV&iQe)5NYb!-!o&.a/(B"q:gj?Lt"K10pCpuh3Ie:?E.D`0%X9St^p0_*'EWC(b6mXX21$k`/kO=<],#Kn697lbg;hg$;c85+lOEa_#gJnVsHRqjST2lhuMBnW)]i$6(ap9V<3EAl#(K1H=&-K@@P-C+!Hb^XBm0D!h$1A)^X,H>L8J[XU?"dI:WPuV2S^V!l9:;]Cq8tF0Io(PB":),qQGOTWX9s>+l*9%4jIc&kJB:L$'kjSI&C6&d^_dKc.FMXl?XCL%RY>!R/kCQ@croGK!p_6&VO7^!^n!;PtLUZ_6e0.XX`ET&?fMBq>:MKXiY)8$0o`?5lPS7#XO*a'on,@=sS:YV!AU#+McrDE\ZN+r=.K2>%!QU>['fpS_0\%m`4<9&u^uU>39^>VodMdWK6P7YnkGA19m/cSm35EWfcVfW.'SL="WVI;s[i>urn'Iu!CdZ9,gspR3ZJg?*:BaT[&+;!?%=.terotTglfI_e^`X0`:^>(^jnJ$<[mHQ1fqI+lP_OaF%]J%-a\b2$*i9_\"5H)%m6H+?(WL,!.5FL+#o'[9Zd>Dq_jU;K$u)JP[rC&?d.hRjVF4.Um<;E`\nim)eaN%1KU@9<]!\cbCE&Z!NLC(aTg'VS5@-GejAd]5[b`q?I%G.qf)FrU4LC3^-ti:f3\VD]F5&Sp0\i)e20KJk`a\_36Ad*#7n]=QMX;2U,>Lf:*rHTQH4J;&#dr*7$3C!p.C9NmDe)6O1)PpcQ:^CSu-^cgFE\KJF\/VdffqF87LQs+iqLO,hWU7n6?T:oPDjG)^iC(u"l4MBSfkB(.WZH`lIrJZ;R`bO!:d21?+J.;\R^>h;VGPTTmVH$_b5U=bTZgLT[7:#7\JqBsN"rZU=)+afhh[[C>F^E^#dp-6I9a$GT0"G'!t0CQX,`jRO_`Z/E-&-.OgJS8sfc#&_fGPQ=1S.GDg7AdGF2;BI6[0\!(qii[5X%(T,K-Q%A7,ro781)1d,"P-HLlrrQ8.DMS2_1l;&gjU6qA7H@78L.sms;RUq8#_>5Wg(=c:Q,j609T2=U:.e&8I]VmIqMhYe-^J8a7#*%:rm`"C5&9A!!]1g%97`Q%%F$Rn8.S`*Ue,Oi;J=^qg+tDb?<&6lbRruU5H6g'4_YO!oqQPXqD&#*q7'X7Oh9AS1m0FJS0AN7BDMMC6a83mkL(EP,sYBON(1D35Y!"<"o">bf#,rLLJ2Z7#%2'.H=DJ6I#aTfYLYqWTK0jX2h`3Z<&r^no:2c-Ld\'H4TYAT=ssFp%R_H88dVM_0[(B,PRh4.eFc=<)3t`"&e`G77f:'K(h?"8*(gq73[h_+g.SR+%os959.tKGljU=NE*2#Y$t^#KK$gl]8+D\5#(3.++uf,r/+I$<'ccnd6?>M7mm#:F!mUrngEK=!@>\iq`P.bCo\`9\T"SB@ZbRQ:Qmp!C9GsjK/DM!DOiT7+)/O91)WG+Tf`@9ERfn,/OGDTUr@EJ38V*npl'aqI#,Q.7'he!%8&)+GG4]bAhZc<$q9\"#7EGr0f>;YWE\K8h\9FBAJ`KZ[^ZAA$9ls=O@\b<^J1'%MpNq+f5=)Cf$10)4Ub#M+d@K#E[opUT-7-L>Llfo>7$F:uhqT#PbdgIMifp@nX5,87[\[5\qEN!Qt`K^k.GF"+Op<2iKH;)^oh+q"K#>GI#\QAh?n(afUPURB/V,W'iSS5]*Y%F,EA!k>3[KOcM`7GGlLkk-jR\-^Ylbgq,;_HEib3M`$U?XbN7MZr[DC-C:ifg]l`1h")OMs3!e?C#KKf/rM*X<p&';(YM]>_m^N-dL->aVEb93='9/Gh4^g/=rJ#t_#"e9K?]"8./cOTYGkg99:3p"i0_S_ENZn51^9VHK*U#=/7p0fiL[-N'XKf8Y!e\T9\G_76Nrf@gl3Omh?\EtSSM@7G+l^iK*kICD%Eg0umU99[)c]],4oXq\UM'+:9E(&n+=##uE&W4e8m%`[hUS]&]DAae%54,96VT%CBqc8=-a/*%55Yl!nZ'XjD$;mM-(o<-00V$+SZ>g`_dQpf&e:Su<4E`*rj'$-!)""H$XV*PCdU;s&>j$gZGIc&*E7?nP8Ij2!C2[r0sngs8l0Ylg$@XWMPkS\1CSJd'pWqk=,i636"rr&asSn&oF5!Y>)+X@N.='l?,<<=`\Vg+9iRe78)t]`H4bfKt1A+?@5G$UJA*KRo+^&LL+N8h]T2?e*(N`,7m!F1@)*a[J#h3l)ps7;roZ4_LVc_1_#:Fn_]r]VmXoVW#TO%MEMY-'Qq"iE2(,nXML=kfcTJc=/6HA[2:E0=lNgog+7Q2Q6lf8%cY75TgRj;$R[S%cMth(V/1I%jGj6GRG0l0;Ibr,h-ml'sO&f8i=NFekJh^=.lE^]XujuQ?C5Po;-tJE\BD]gR`QlUPpQ&C/0t"n2/cB)DR@YB4bsdhCNqVbN+aO0+>)oQtFFqRm%8&RSgdHQrcdY=XP;,hQ.#%K;OA"SFO;U5AMW+ao(O)@r??e%e,uekk+ZUb7,d!h8/"4Z/t)a&gbRk3:W!fmD^LWW^Occ@S.fgMB0=(-oN&nf%P852V=q-C1/7/T?@_Ik9VDpQb9JLMKPEd")N]2`Qe/,Pq'H0YKC,,NpC.8^B+73oeBnBWnE(NQMANBD-s!C"I)NY6g<^_tjQ7]\iF1<>_/9W8k-`5`e%cn)oFh:HZGF+I'<3mYZjRD/;,712@*aA00#U%!*(cR/&buE&cj@"*D-E&"hQ@l"&>pL+R,lY>Qu^XFS`*9:(+Y&Q-ai(7#4m0QBVmb]tiie<&eE(bfn@&D4,k\kXP;%%dj0e\*.6I#bX=YjnG%bBjTu?/b+;PO6Ud-7#(m6-$KoMQM&A)JGoK$!uD[G55`TC1o;dLq)Ea7W*p,U8`D=a:'590KEu1kI\>!lB&f*iORTlH)6^s0kYFsD0]=)MVc+$D6o-G_\f%/&@,dhfn^&Bb+ESE0k_R8./j+fN*Q05MT/UrD6/HT:XXm`j7,;hqj"VmuT%6h4-u/FnQZ([Q]0?L[M:@#bebK&O<6[](hSXN_D\_J.XeV4M/qp2."fl+VQq+0ZVFO-b$Hem'ej)LOn:E*IMQQ2:r.HP:ATX<,S9fIA;Fl"f3@"j1]J4e2g.AF/+2JEl:-li@&;g?>W,2+Ha/:du^^m(d#/K0Zi(,RiN;:b3&C:Q.G;88O*T?s[)P;,K8\_/[P&uY;(n98P%1V"X^iIj`qI-G8[a?:ep>$UKa"OB?;10O.+U83t2pJ8%jl\sO%c5&GHun[3.Vg.3.kD0_me-DW5.2l5#cLW5#Xq'XPf/bB\$q>%Mq8j@Oa;>9pHtgJps!E6N:>L?@1t.:2\?q%BLN%u2oK[Te&ohID^Q`m43gOV_ugBUe9m"QTs301&d7$A"iD@rBM?C,F1mgn4,\k-b7HB@fe]kUNjprcTnLdWUqsFbdTq;AdB#<6'$a`25%^YogY,u]YVLU"0fJWBIV<,_!k$P\!+ES]%H>YB,ca**(cjF04M'rkqMj`)=WhGtTG9&X_"rM$,$*2\7&bAkUpj<&D,R?"ZkNuU2!f5&!\n`,ViJ=IAlg,mlUstUJ3Zaia$GfU=K.(j:"Y&?*iI0$n'^n:L>N,GnqGEm'(uUBoXal4[)g)ga!OF?6sp5u/qe#2H9B]gMahh\=`&6Qsn@%c\);KuQYJm4*sC&X5[`L`tgNDuei$iF*7"4[bfZ-glgg?0J!e@iNPt:etmoCYisILIP-?S;>3:#8o=8gsg1V9fXIUPS"8H!CR/$-5r>oPLVBB@5&]PXQq7#Wq-!oRhJ*@QNF.EmQ%\m/WG[t=DA>6pe*IE;c('iS/B[YM#ak[>mEXem,Qnb37W'+5pmfF)_f6qU)jQpb6b0^Z%k*TS1];S)3:^CUZ%(,I535sMrSX)'Mrs$X.;7S+5;j0'HQ?Z5/1n(/"4LeO2j*e#-bU$ZIfPk+h,g$/6X\S*(,!Km\o`6dJrb)A.3i=q.+h@uo?AV1Cs'VNX!'$G6'0We5@?Nf`b*V=I5IOQT(TF9/BZVOF"mg7hr:CN)Hh,"H`fd$kF_4'"['oDkJ4+.0loT>=3lY#,f"3(J88(^2d[.1ljoU6&(B;OluRr,4,(7IcB$gC]@PWqoWJ4rpp5XlrHQm/oi,q`X]!C7>dKet&KAf6>4Y%&;$/Ma;m;G.*&5V1TB4+Pgm)()&eo@'Xg,#o.8\4P6S2O\ucBnSBn,]t30lLc[jofPbiX#fI`oD/TZX>IlL22G5p8;&o(&@pP?$.i2_jP[=lB77:dKZkbMc5r*jZ5o"]lS@1Bff(+.Yij\4XtjCUCBji`,_nV\@dK'#0UEKmZr4tn]+:9K/'(,H7NI0U>U_@3^pX,Z0'd9ASlonI"t^elecnDM=6e4bfX'6ffi7Dm&<.N1!DL;Ufnhe"8X7r/E[3\Hikl,d$(1H5e!De'0K.On+upO\9rd:<'bS[cVjEKO,72E!>:4]OtD)BUHr@PBs3<_8te`BQ[di@hi[9,;G*ne\__TiF.-gV'7+%2aXmV6:V7/6A%718)$@HABPENeqf@^:UR5%>GjKuDI$cl`dMA'/[\`$eY.-bi+WFkmVeZ6>#"9G8>1ORr^^NZ#kfarBqU)M:?2G-!F10gGdP>e8qE>L)7#VUq6]YOO$rQg@^nsLOQ3bZ2DkoI)Nu;s"XYokK21@a9gu-\Op7URaRViu6H"6"gW&9(%"qHrSm^`FmF.E97j0mVM9,2D9]1h/8\XF1mhY@\$0'-[NJbAS$7VE6^1.tB$tO;c5&"WbZXcQiGcf$>s4oUI1d*;I26]LZ:n"(9j4@AV.lMC`[@9f8-H3;2'3cj$*SpQPLo_"V@Pg':6^0o==fIMi$>mhFk"F2T/d0Com+uc#/*K0N_c,Dg&B<64BkWZJ_MmsV>p+653@.DF*N,H@Ncub?qoGGKq.Atp5nRaR$cd+))#-ATYG-.6lsYXB1XAjh7ank[LNE!JP_l,+\:50lS\t6kDda%51&LrJ;bY.g-3KkuGm/e90H?IKB2;'OOeF'EAkIY@oML[/HV^3[cGA19(Hr7EpM\\B%T)j:\O9Sm])aujPFSU-E)a>>:4..E]EC6P5?+$PFb%pTOX@><:bkkD>a7ZrUKCL')'Uqq_1@f+jOGdaaUJPCA-aEC,VjkZ^`%`O7RVDj)@S<%JAg@!2Xb6=AI^n?]UMDMCSV+D?Zl:oR?"#I#har*IQ4^)8CJo9S,nb/`>_']LgtR8O.d:1(#(iRZm9?AFbGN[(O(i4hQ0B\c*E-gZT\s>e-t0N(,"Ed]T8a>!ra@>.%)8'$E0DLG3=U235ED!-E]nTU.U"[W[TDi@M,8.fuU,oBfALM,lpD2<()j67#Ys&+Do=PtY1h74H6PA#n=#)5!SVTK=Mr%pm<&hRJCu\Dbo^.D19r9866)++SQ3%tL%-goe&1.&ss5LZOJ5@:&1G\:2FE^AboS@OM=BBY]CfuOorh;n8*b7ob^Aij9mJ>C)bb'gi1l3Pne?m$)hR=GFZTJC'qoA`=gl0//R%TLYb_rC4a5D9rtkH61NI?V[o+Rp#sA.kY2OA3XISqVBg1`*HZ[GZ&MF,O&a)f3(;NDA&9nb=s5qOjY6\3O(8FCfiBWjDTkES;nM_/O1k@u-=pWS[/F'>ggI_[3elashap0R="f"3d'U7AUr!^?-2rEn0(WmPlmQ5Vc#1a%>pNl#QnA+lEC\aV67,KgeJ?6B0JVjJrn!"mi$j"<)c+/@t0r$]b,W[E'lnH>1n>hJ%]LU1"fM!GL-)Jl/FpPo-?8s1.K4Pm"U2_u*R^V8PZ_N?XCWFM"jGW"6jLmpUVi&!$"3\,SBLM'LIcOsB+bRjm^*"QJm9X-%"=uQkp]O;S],XXffae/[9)e8r1>p3/ALP;tWgjQ;CWO5%E+F`N!bdkj?drXsU'L$cKo;&AOUP1n1I+lf+gdCAJ9>`U.S?])]'""WQ3kDf66D(Xp0CCf<"+DsDCb.e'/g#=\]jai>Lkjs3`GdPqdU[3$q8UQ!Q2[@ijr(S0=t=@F'qOl'd\'-1pdZ2,F\(c7i`^SS@d$RYm4734qaTZTXtfh1UPLNV.au^;<89\S>k41n$YkX,>qS(i-Z'G5QH2QPGfL]>fS7VK>KAcn>_Nu]-72BbLS;!0GEaI0dH\n0R:]5XBtYOq>+rgR.^8A]>@O%_okGCKP;r?LHok:C;pI@k'#`Z>)^jV<_[_[E)l@k9#^]Jp&9KO.eL(Zee?0uP)97qkV`H#6>7q]Y_;8*s$9.c%N%_(DKOR[oZmamu:=dM'Up/3$d1D%+GiFe,72qlN8S*Y!0D!$2k]12Y:f2-0aB,elmE1J0*"'Pa;1J76O$QRG$$:[&8Orm5FKYaNN?/>*Z3&r;kLVq;&`,\X:%GHaqU.Z3-38u"LFNdYe%%@OBY.)o^UTo_,f1:9Q+@f!YG,EMD?q'KM7f%I#Us3%NL`_r6a>&CNYo.4)kDZs5`+1PqK9)t.7Ig'5RSR4TF--&B^duWH"(CX-mNd;8Z7DNm#?qnHZli@O(9s!iUHo$8L&<>rlR<"UUWNFGJ.eL=mG+3##TV473P<2lBBPo;Uu;7$A<;&kis9;[jL9o?nR51/;+gkfkf@<\;hVoU^JR8"pCs+XA2XdI`kJ8D?/aeAd/*gU.GuZ.>)q6pY!t0nf(md2Y%*eUr]4o?kifgk3uXOC"O!uT*5g`bn!.,VPCj/e7k`t?k\E$M)1LBj.Ybt:#lZ#WpA0QOIO&Rd(^&&p!&e\5'$*]r:neWuN$B(LiA0XUe8cARh[Hq!5]'7#@:K8XJ%T@638ehm([Oei/lNOuK?%;t>tK+;I:=-jC/KJf]@X0W:6EJgX&l)j"t[2nTATJMMR"lZfCNPi?`q*cN]Co!<"DU'0,>ZGEZXcj?62nbSYjWW8h*MtFVL`j[aRqT*uF(I>@B*t.:(B/=6"%\56iC#5:,;urK1T=TW637sZaB]A5f1A_4*J!F1&]SfLJU[N(Y>gYnT[QP9HnJChHHsAeEgF#U(k#PQkD??eL&Z)lY>)BS4MitQGLb+E/KQbE"s+M],^:B^3n!m-)iq@b]thE,AlA]hO^S-3aZL;Q7GHCfFFk5?:VJ"1PHk?6jYb3ha!aWpUf<`]4;Xano_9nNk/`EQ>&8B\l.S]mC,(!>/?ct%TbNr.f%fl_a.L.A]-S,$><;\GF(3d_t9iOI'5'+'YVEpG&CZ(%"rJcR$_]3F!_lG8gZY7d/cn##Xb`ri'E2/VlOM(SMAcL$QpU\T'No^`52:`,L:#Fej-sW/D3VE&#ra9T<#G/D?+C3#_>GM8]R>6qO\_Jh&%!D,Y%j$HuCEB-p;m`q><2)8/=e.jrH99)o$3*8@2,1n@,k4#j@a]:SS8?C2%tDA6HLt5pl_SqE?QA?&G%,q+]E4BXI"\_.Xg`L3kJ/cH*"66;,;.?BU1ul3`IWF,"7&"-HZTfo`\J5n;UkK(2l/VN(5aX6VWaq-B6bXF;E$T.T(kP0o$F-(R[3CBX7e>XV`%BAa)R\%@H$N(E.0Sg6s#@cFBjNF/(56.WdO^36KK;M8^6thj.lG5$9$fPF$58aMW+a$E\j6OE%;A`QRIdQ%`P3E$8!^]QIUsPCW#dmR!d&L(%t(G5%#Ff9khY0cZ-,9VQ"V[^^`7)M9Zk$!^n>-M$8S&"HZ5Tl3^%bbBkX_Nb#&KEbcQO63ditR6RR*()`:c^42bi*gYA#%b4AJW9@d#QLk=;>3VAe#G9!U*A-7'Qa(1WLIbIn'WX#+?)]#9qX?Y)BDf9Y4"KdUKd)^_,PqVggDQQ+b?,>r6OmOcFE-k\Sp8r892PLsY:QqkjC@7EZ360bOV4aK^<\6h-H^A*\&'q"pO@h%KL3(cje.B[Nu/HJQaiC8Hb9j%i/?%'0jf.Ng&QJS$^&lb&^FK;:.,!F[/gB)f_V$o->c.clOI1]W*i&!Z;WYR5[8>CW7H$5W*L.6Bb;2b7M$8UY_J,q>kQYgmcCt6<4iO'oK75,\dXNEgbR%L&dCZ]V(>6]-q,AX@"a000*mt;8n4)@dp,HA6W'l,SE[KT#n%?T3ABI1X$pU^at=YH?pXq3;-<&kBLO,bbd_FF;J+FR"IL*6#uM%`))\`$p@H;A5asV2XdChLbWSAU&J3*`OS-,/`fg":HN6B,AIR0(iOjkDF>_45\(c7qc1@RXf!*TqY_\It9KbT,0TOe4!/(Q1$ktAZr+CYs+K5Dl&[Z3X"a#s+^<8JOc2a347_5kDNLqDR7q;\=2(k%W\WY&K"`\IgNT\+n/[+"N,9/Lmn>7,1k'QLb%BH2XXQ82V'G_23=GWb,8?QeVS&&A,)gGObf2,L5pXfc3MX_OSt[t5!7lSgeM["TmU%Ah$cCG/bYS*7/f9f[FR_MQu%TZZR]MpFIu-ahh+VW1e5>-=>n2Ss<>[ucTF2:5fYNcb-<1?mN(V_'Y`Tf_%*oP+R"jT1mH()Z^k*lalGTEWE!_)INOd1pS.1j!7'-3_snCc*n9HIdDhE9GMJ`4dCQV.bblkf*#q:VTaoo)#'OkUd=JS@#!-93)MRoQ;cBGVS;JbJfL+?@CiG/M9o*d!Ne9qe$r'=2'+nS0-Xo4[S-+_JT,UG`<#HAMTYKafVoM+@1q^=](&b6Pso9VMQI-'m-C!b[*Z87uO/,4V1cc!g/:Stp^GkIn2p1/[-__?us/TLh8;DgB6/krpE-4g1r20)lQ2A3(3]GKq$rgk1-l<$`YE(]_71M'"ePU/b<'_m;W^)>eX-6+bL/]-9A2=O%K\q`.u"X*&7Gb\Kc'uTQl1o\\HYe5=Wp=F6&]AWV'CR/'1&TL*1tMn","2k/es3h%>H!]IF/]q?=)UfM*HckL:IF(L']%K(ET3^YNs_2]r25'[Y+[=5.snL@D"(I1g(q*6;35&M+T?G$fs%(+p#%4+S@W(B@jIR`t,)O?6DIZq@"AW#F_pR&+W=6$Z!Bc43_ph$1]@i)l([G]9Q-XS^aj2+eNa>0b6+*]`RUh@]0@T[%uM5m"6leKN-or=AKU6TBF&Ir:Hf_9A8qmBW?drjl5AEfiX6QTF;Ha+u_b*22d@65qJ'no*W_t)XK:LJS!)I=?VAi:c:%HPmi"*2q$S!XZ])*)6T.aOoO0[%'O<"N3Z%J7:KH6l&N/1/:tY*O1c`SPCO5X_;fCBR>q#7lD?T[Zr;eVAM4s<=`quT?*,(G#H`?_Qg,@9`+LVkRLuA$pc$&N=G.1b,(#n&Om=J^h=Dp7984s'Rl+i=aCNk>$Ng.]X2lIjF4!2ALMRq=Fr7?(VLO%'s&3Gmg(g.`niVnfceE1/khso5&4%>un^H5O2ae)]n<>kIk:i#Dqr'_U)0W^uZ/4)q\XlIeK.>PLr!O;6hN!>%UqGc%r:X1\A9lln,g_76D:Am6d8!M0_sXbXTYb>0+@@+d#)g8.@S@SQgsfQ!,i0i\6`(jEe./dPgC8ohZ)*p@[dN'W`n83Dm#"GIVI^%0dIoufMs!]9"&Rq\TH's\OGki-5W4Q'Tm5ZIOVda0VJZH+Ko:h^H#U`:V5f8hr8YQn<"kaS_KWup?kt6Pr6dXJY[((+Se`e74+ji=X7OZ'fEo94:q0!8P4_758PreZc5WIXl3oG;X>iYWcGk-0(m.XXE"9)Fj]SAi-&$tq;oEPjB%l:QR4]V-NU0qEnOI!tb;"oo&OsS*V+RA\AL`7#5SHQal''SWA%Br&Q.->^*gT>1?6rMY/m&p]2#+qF6ES0J6=aS:h:jD@pbjVj7gebUr_)E%=MLSr+,@"4Ul<%=!jZI0,r-$W7<;krrq.opf:L/LFATZ#1Mf-ZF!nPVq.0G5rDN`4tOXQCY8:C91XOb)\NCl:4u.upY9>!`]qYsN_\d7Pn"]tr:h[b`jn+pWd9*3h74]:Igh3S%h]gVVuVNDB:`gN/\K>T\-\>?H$NFA9Y`ISDn82FQ9Th,(QH[Y#94Sa]qG#=aMd-[2B#'4YubRS;]UQt%]pkcRcmj:IjF?&)alVoI_U]&N-CPHdlF&:8hNcVCA'IHH,88rVTT()_HbQNBB1ES*K[$6Znf(iq6-cD&=5KfPAd/g2W3"KCAf0Stn0*;Bp9j3RJ.JY42Rc01gsnUT2`ZR7&If!#P_inddK&dHG!*0d/81GN'-=?MZQLcpq1UhG?LkI):",!1A2?%FWT2g[8#`-7;:%>Q.,iWPgcQ=P-i[n28"Rukb#^)A"=X"^X2BV?ik=&PK?_@o=,=2f1)0QJUcQ82<@rE=:\-;5(I=&%YUAfW7u!,-&!+HDCK&/6"B2F]udLfm1J4H1#t'Z-h;.V9nI8$=Y>I,R-Pk:mE;67N."2J7PZ&,NeXmr\q4MH9PS"jJc]ot6oPAFGBskegn7?=2@2Q9p/abP=U09T9S^N,hZod9L\+a/_qGn59N_1"r%4dic6;I848/ierj7D-Nt0&oE%-.,9h^X3jM#n9OC6gu[XHer#$1__'tYuA8Md>(h]QbkRD^+&L*TSqK`;kMghQoTpHcRA`Ch`PoGSWF-=\6W;p.>AD21Vc1bri+@<2%eL7%@[nt@'S`Y,Emn*Va5V,=;X1_H/qn!Y`bg'4#7NZfi/_VlD5o9@_VHA>arW9PVGf_mgM4-,'_HoAKOV3=N;Bd#ak(Q(&L7XQt-HrY`L(09Hnl`#<1^lJ\"8\5\6c/NV>>K%j#=GR5cZGI0N4VKU!9L2(%(Cd)b=pBmeUR(8BL&9scp1E>M7?*-L_T!1L8Kq7sOC06@&.YnsO:alGK1D%JK1N'cX!h32JH/D)h6;q$>JqT4'@0U;ia$M,OJ]qT0)Ur=tbs5,/:f(.d7)YlqTYt_!ZqH=1eKPlu@M4;kOLYIJ?tkU:LCgio'#G2O[a:?YrpnHVi7G*aA5)q1lei:Kah,cWs3'PNaEEMr_J2OGHU5Z,,aPWO"+eDU3nk)a[dDRc.N_>;.kHbd80-Xo;S"-q-mC!IBHfdAMJCAP.0+mSJr)CKW+;U$7D_=37iENba9*S^pNOZ:&-@(Fg&RYQ?Qmc=)l/!,*tp&5U.Q]I8/*m7_NHjM_B*QE!O=2P"TfHjKM%pS;OGi7"Z-o%&<`baN%@k,'Tj(d'L=QK!tYT&$oH,R9GK,j5Vs]:^_2m9K)e'O!QbO6O[:4<6E>bf+\74s.Kr]XYU'qhL6r^t!&A6g#bY`EKN]"B%L8I52uY\fakcAuLk[gU'u7F%ZF3qid20ggfaVF+)^9*BVJb6>c;@[%4[IDFJ07gZRgN6E-)d-$/+T%uI9(C/8]?Ktan:X.UDMiR?l(*,$M$/'Ad?jaAYO4N.p=\_N`T=b8tag)fBjh#@Uq6Z'sab^Oq!bH$csY%\)0u3p,%6THX>m@-bXgR#]oB.3^_gF5trM*ORckr@c&EWM?`tY1U!hV`+SsV(CL9*70?ue,hJZ)%^YbK,tuQXM\:-aW"^old!uO'M[4.Nd(6N(bphL?3g%o=lOZUqa*P>*]nm+a3gon/Q?3d6GO[[_5Z!rS`sMp<)b4_"eKB).F`??;l(K;&_I=!&kNr)D\)MR_@W;J>:;e]))1n?lV(,J:aMkoc.=-44SIA%0fu2^a4q4rXAutO%j27RNgr@;KUfb+7YXscMLYXQ7qusGcU9ib:"gA;iPI)N"-UB29:$g"4Hh^Hi6WF.S9u-\fUM9!*c#l@F[.qZCU:B7?h9G6k3-!dB)%5Hc:9eeBp]fSMlG8"$$j6t"Bp(`#UtUdf*U&s1Lq2b`lKOKlcs3%BRcPL=5=IHbsn]?Oa()a0]&:TqmP'n1Wh.NF+n:6/5G/Ji+AHLmh_<_2\0XZXqPY=Fsu;;lR&PKP=T^U]Tm):?;YgDfQ?c%H-3,g6SNDm?\1l*g.V17XR?XV=un`K*E!?d'Cu`**XhBFS_&10F@>f;]1egDafh-U7TB\7]CJ)32mK)4/EMA:k=@uZ4ML4+G]>Dlu$073DJ>rArDUog$G\/m6FP$M=B41^!CGMKLfi!B.d/Q?53/<,Fb0p/H%qJ]DgP03?BuHA+qE:n6JV9GW3FRiO?-l"M.4F8E6U_1lH:AR2EsPpGA&`]EQgU->/VFChD,\agBj'+9kcfp;\7Vr[T+i7&sB\8#"RLiW8hFSnO!-LEc@\lZ\D$bCC3OpBeqI-9(Xfu(8u@A&PPBLMaJ[pcN%cjnKm+N[)m5UThTW0O44\an*.t:EY5RubpRDY>%o"3??De=T)a0^Gbd3`F_l8o$fE4"%+HGRkg()BT*K4C5s=Q/IYe^=Xp&\Nlc"td\a&;r7XQcu,#&Q:BeCd[&5W=]5d*$3N=H1ubp_2F*"N;E;TA.CljUMN;jh72,"FWbcuA/"I`OW>uL/;+E;_#oi3B14f\L-R2%-"nTtJ//\XM6@,.V!X`oeT7TA[X>PIm*<_E5]eZ$.Ji_9dR5p`BQ)B6RYltidlc^`&0Y8#7bkif."[,@'!E)[_[s[5Wrib]9n6`PYVRGh:,s"V`H\^&PN[*B'BYDtY9n?&eh-Z0>CL)A^I[6CI0h5akQ&utfM:'dR$oanEcO[]#G[j1:tDD`gHm_/X:oH235\:,KZT9TR"j`N(MjfEB4Z5"agqkLebbBna9kJ-n7IJ9URkI`qqbb=uF;k[CsWS0_"9*hT=_k"KT:Gn%pg3o'*9%^bsnW@&"n%*4qG"!]@S#UPBkYV7pO9GXB+emP2(O;*gCToFTVNQXa-Xqc@>*-]*(PDtr>QQ&*_\K&_s8'(jJ"q(J*C9'qWk'lNi17:m*+bPf.U+p%"j:YT:g@De_P#rKUP`aUg:t)*)*("lnUFN7M@.eX#`Y1"6QVm[3/c3G,!n4AWIN?2O0eG5Rf;)NIA`jhNkq5H:$S\6SgLfkh6fRqN`l[#NWoK,IlsLG7Aap`+1hX>5!TWh*C_s5n!p&p`hGbMKud8faiUK86BQ;%M52hi.EP1Za[2;`@1sr\#:.DVU8UF1MF/L"(`EsB5bnN8.dY#*DEi7PsU0`Y:3>QSo//d714LelS\FRa;R=D(%K5@G6eQ'LS'-UU>cNAg*:.k>=L,"Xqnu651]/&n22MQKl1%8gNgTDm==KkT;P;5%]3%GEQluJ_@N`[_uPoSEOL,2e:2XTq>M-JIRmIM24BoT'hf\fEM(s;)Kf'*7_.q>Z$ilK6mg_[/,6i&GGq3W6p9#!SC9tknr(g%uK:q+;#"dh=STU#RB)ah[ceo1n_V:#a?_G8imY^H3c;%GB`_sMKdW];^a/uEc5.X>:1?q*s&%P1/X@rPsh@)A\laTl]R-7CIei&h%,H.`:gqg#G4i_%jUp[8nj=NGmkth?(\4sj5XcH9hrP13$^N+r7";N8O]Ws4,l:8nU%OX;&o+->+n+]_job.]CQ=c/$GZ(8#+L"Aam@?2QWdG^MuPW-TNPBL(tP27?spAp-o\:1cjk9f"X93g0h(n4,jW'=;o0hYk04t6oN"EK$scY,SN$=>&?3%4RU@X"_kfo:'"eY`*OVJ`n8Cq)dnEn_ui_ZW-FJ..=/jAd5!O8"Udp6!O\(2\j0GFHKu^#Nid<\#fa;bW#S\Pj$55"!a1.6"e[C^0_^+?SkWTR]5rh;0%f,3EIlGWF_$+uE[R'je*?R5\Zf.:4M!,pbSLl>`>3=$5Zi^!b%+V=RUA$jXfu\\E:49NK[rc%EP7.dJ+eie0U!XI?6+ET)2h4hi>;=621gmQ'M&6F.BnHaE+K9(Y\+uu;1n^@`:7s!*^`MS361BYrBV#`b-pAhGCYFWrLO/\BgQm2eOb0#(T=bX`#EgJa#(V:oBEfSO:geet7=kdk,!hAhn,lM8L\OICG6JVr,poK91GI#ZLp@?i!ellg\1C&^9N;Z2"er%Q![J3%JUium!5fpU$V2imOo^Y('3$;/!3f^dPfuJ:(at'3"K`k_-S[AU.7>KoQpUtLeaap\IQh4[:_'1T8DK?dcaUlQ.*.dtQJ1+k2]k%Eq/]KXMcTQ#inX^3'h=bY+#DDA&PmB_'nhQ6CKS("_:B^2?T`\1F\l6k:4r4>6"EQP=_uQ#%YNP2/&=V2Ic4o(dOS.C^3=aurL0t8(k[i`UT\sj;)SDkjeFgE#peM=oO3*D4f6Xc!KE7]hXob+"&IN_@.:8<>GL)S71$G^N-RHdh*bEu_'_(F6q\<_*D(bDI6Tb=Cm,K#j3d\3MHZroB0q!kI1%:0bri>PkNnC&"6oVe;KE_`NIPAD2^:<^OdV[n^`VH-oW?@#YVrCZR;+*qh'I5Oi`3P4AP75ONTV*-))@8q_BV^GmKV9(4!D!oEPVd+`BeJ`\=sdX7-A[JNBW7qB$7_3+Dfsc*oH83LMc`Z(fQTS(3ch[u[skRVp5gXsX0/a;YJh(B:4;"hSol/go=L/D$P1'R,Out\7&<&GPD:.niX,:h*2fe5KNf\?lq3XL=[E-FT__Xb`WYiK0r;ML%5Nn2E0m_C]8O.qnrsM=5(*I8mD7h"m>"Y=ke!8k3aQoF8K@b'NDgkB&kBIp5P_!eGe4R#DWFgM/`&+m,082Up2/fi1WqaSPF3T*'gqRp'-"iYEDH^kT3+#24aW4oqM6?i-`sMm>!(+6R2$)9hoNC^l"fm'r5DdKYT0n#ZL>'N"duX1t9JIUp1(k"]5@7^dP7rbbYD1"@Y_c1CQfR5uc92'W"GG1b'/9!`fM9U_OP15t)DQ9-fBc712dC7)U4a6V(-L'N>bY!>,Db8C8S+M)#VFJL$/lWali2;+Rc\"@*,F&O^F;WTaTc1*'W6^7G=CUY/*,']D8#$5#lr5,c=aa8doV7&3j+BEe`?5`njo!kAV(PPGa%1^Y4F'Md?r+4_ihi\1J>\UeH_-jCuj,,(_,0Zn&X+IE['3"ci[2&$[b:_=hW5XP[=N<;N\'Z:AO6qJI/EWo?*"V]>,4^q2iMG75CObWA9&_b9NkePu.iV&.aLT^^.4m;>G3JXaI-Ni+Up&C%JR,o!3r[E-ZI@it8KuklUQ=E>!OGQX-+O(LOj0M&YOIG#QAcP`IL=!amCC.XTaO3$Vqr,HOTG^Ft+U+*+lT4PZD"0lH8g]@<9[W>sFIo?N`_P%#GOAO=5YRLO;hUOn5?Y%-M:49pidUd*a"ke/GZ@USgIY#"<+&n-`n.3M0JZQ^5l1CS!FFA%FH8C%CI!cMgR#%\oV$\P9,,1f`KFjha%p?&jDVEtEBL#6ZSnl\`"j(i)F\+t@=^l;qb\K+5E^Od8?cR0;T$Fj1UpO$ItrXYe`8"sdV\%5T_+"<&2:1'tHgN]2C),U,S!c(:(_Y@q!T5LIa2HSnO/E.8su%j4GiB!n.#E8DL$imK@$N"F./bMW1i&l&1R)/I#Ht*m.^5o\on4m:(s@6!Kk':E"55&ko5WBJJ2f)P85:Gb^_*-_%O[*:dA!oecJ%BN(Ef#(k(R=o?n&#iS^aMM3LEemMqq]O?t?O-_66,7c2qhHVLkiAN!*@Dh';dk?G#b9^6"\KG(&jQ8:/2PYu4-q!7CfLN\qCLngWc-uMG=Vd$TC:\8_Hpc0)#-q,Yq99:m]eE`&%T4;%ObUnbcg(8WuA=Qh'dV[Bk#\*%sD`];kQOMJ>^s\[2GF@`3%XkIjpGL)*lM%Hc9CG./Ls@VQ^",7m6i6NI<&5X+h8,=*kA0gbBGE+E+)7\%OUE8tFeUG;+QOF/i%FOg.SUI08aco)`N_:FAb'r3'D0dldFSongQod4uMm_uOhE+\fZ8Q)LlGPGJu9Sb_.->O8/)ZgG8:O"^-W#Q=g)@MZJ2%8@@k3Qp.fO.g)#B@BACN@'7lAVC#,;/(>`@,VWD,M;nq(/&p#97Ps1toMjfL,Yal]'hRfKKPAi@GRFKWl>\&JcD]4<+*[8GWa8?@(-7<$;"h6)2:FF)5BHR7+m-UOV+^/%4'II"@Y`c;\7CY8AlY`;,mXL$\Cq-?kVIX,bKOF%%:p$q`1KeU69%XC$@>I'kT%AdX\Mo/7XF$^r3=.1DB29u!TM:a``Eb09OSU=8:pt%p+8niW/WX4e:pV&%gHM`R*a%G.9QM(QT$=:B,I".oc_hU=P9au=P>71ZB2s+I4Gmt1gs.>DM$>'cqL0e_EQ,+0eGdMAI.-d==+,n;qT!JU>Y@V+\jg+N"%HH&P7NeZ'6<2e.Oo\JqI:Db(c47[YHb&_+6SZd3W'L0WQs7M\'d*E0lO+Utjp'#-fAHe#.A51iO3L,HdF?3">.hH]b\@1)l;hBr3a;BI)kA)_D2Qf[1.J=%d]5ppVS&L?bTZ.ZLQ0?35$gJY;*SMKQ`*8EQii8.Gs!-.NU4,h!'u$36`=K9&VE,sA%]6+=J14@%s3e\4+T+ON0UK%1SrSSI:(A/-s570N^[7Ss`YQqe#3CYnn/mM"A?5$Di!'#U^X8r)Ll!c8Ip5MV#=^luVj#cL7Dj?41:#d3jn:0L`^4Ol+r80;mUb"SVRop[XL=c&#VEW[j8JVGHn$"d7qI,ebL,./^+=07Q_:?98!ElkX--&X,rMBUI`$[#UFV*tPa!om-6&1Nr8B?+0YdlB"G<%NaPe@*O/,>:"sH1E7RIcCs@P'a`!Gm6Z/^c$fbDh3C;e3/:@1LF6c73bRSj[fT5!o9j=NQ#$p#@hL\&NW6lb/C6f;^/MrAi%rTUrdoO;WaEH;dhBEDB=G/Cr2B#fp%r/L@g]qHqeQ0-d*]/h>[4)4GbW]nL"=f+!M3X3^IZdKEGZWPM@I[9L%?95K^$jWrf7Gb92=MUY[2&P/&VFALS&L(2!ejtZ8DWOUQl4/%+YfP:Qal)r+nhgER3N7b:[[Yc,Kkddbf,ua.0eE^e7iJV@5W8u_iGH;\"3E*G+HCdILe%#=5^gS")Wgd&59a7R%Fl5EafpTUSRP$YpLk2YjM[MQ:Nhg0E\;hgFij]/Z--QrV,Hu:#sHGegke:2OkrEIZ>gdd#!H_oN:aq@9:XHJ4.8gU&sWH]gFP:Sp1$gJk?3q1G5sukb=XFbr?M[Ec!um.=AJqW9oZ=BMi#p-%jrC]7:E'S0_+Z&F[$?J(Eb@#"'#u4O@KT;8)Ml?BOH1ZD,`a4L_#e_3>qdUeK7XfYi@G],?l)*(N@ZI*O'M9m.=/I0P,ug!q$HSqRHnb(\T6G6B'b##fY;[33UZ\KT97G38DMA=N1$;$F>m[?3Of?-tKD]_+E^P2N0T':d>]D)`>GY/J9Bbq"qIJ^Qa!*l<#%?[^#%fZLW1j=Khi3DW2OWi0a%L,8eUGQ(`NaAc!hG&s8b9+6gHaGM1C@bK2op7@Qh6Cc@nT;1;TgOnqp;AC"pX.PlArca=X'^oIl3N+cuCY*ge9t^&J'&gDok>\&Y*=9$MM2t`!e%el*X+A%:APq]f@n(n00cb7Vad\K\0/m*en3hkNGVajg9e8jGi_pUl80Gm%BD0B#s$;r*Gj$6\WTmQ&O>MFDl>dg86A,_EC5E`Z?]2+N#SeK9PiLGk&'guQ<*/tBf:CQPY;ff)e27?%2$u7n"(`M/O+uqH(Gg)CG&pGmopj#%6^Hh>:E$S[b>tfS]C7U[J#OSfj5]nE8.bb6agqmh7ptb]O.RBI]*()L[Mbdm<'k&u?tFR7bmR"B-HTWal1l!AY*JLDh_jj>'rr!Nu:D!9AbuL1%Pc`Xl]$5\CtEeTb==1SOnL@&4cs1D@K5%QiLM\`Xo(\7omKaB0sK_\d)#d5HfK2S3"daP4hIpATCocWmg.l,Y3Urcm/!Xi4M[B@:0Y0)!rm.)3k^H+aNAf%kO4S2fDRkVJeH_\>Ps(2p1\j[a)\-LdN#?J:JP,lt7R:^pm/\QWl>%K0g9uhml-Z.+%fu5&'5-hOJt[f1'`9hL_!r4B&][O-o<#rm(K'&5bAC#.B.iQQ.BJmIZebP._"E57gi1oo]VH?]^6@]_!p:bNg,^rh5-JUZ>*<6;9I>9#iFlnYmIZo_bl=LE0B,2fUC_&WXH5]5RMJLROD>bL^\*1]$/+th83"-N"mRlTo!e`@]a."74X-3hZ(h)5so*2@>lVY(62F68BG"&+Gr^VhC4-kN50/30+N%M8HI9E>Y@/b:J'h!#aj9k)oG$,pgCK=KQF$YB[l15-2TBcMjQ+.Z!g2KPDB.DR)P68*s4A]RY!-RC)fF>%Ve=6(m@=$2p@2G9(nYFE`X)L&K)N/V-ln5*N=gsJJU#m/"%9`c"Yh72,O]DBNXn>VU;.'a1EDGL)R1r@*$0;A;j?n!D#VSLchR#A!&QiD[hZT;':/^%7Q=P&N+$_P_L>,*pn?F;MW&ZeZP8N&l*qN.9T[:9Ak-WN\db1?Sk8'1J6*j7PLrMp!iLa\,`H`7%_DF0*`m\Q45bnYf*O1MjLeEbDH*[)&`R+2pWT%of_bdMSS5:.D9sd5+%2Q;cO%coqEOmF8KgJh689#a7$.VJbQL3D<3/YB;Fpr?%&1l]bfO9=C^B*a0rH9`(c42dAJ5r@@nKJMZt%Zf.,`Nua9r6#B,E(]:E%^0B-RGiSPka#QT>nbrNNZ$sFSj>I9dpSY&V:eg6PGY)3]=#B)DXfcZ[K3nCkCOWm#q@BV,f3-@M'E*Bd?pA_%0chF;F!l#&6)&d_aO`;N@U;c;5@IDRPMn!XH>4n="/riW2gLB)a3p"i8\H+.O.)[ig-(]PnVRo5L\0gAd>ec.GX2gM=kg^U_%-H&_k?$b>Dk7Dm.p)654u)CCu3E2m"#T,Yj^Y\dfE#d?^(eM&hZrOjTg1[)hJoK#W#XR(!Je7Ap[BT+WhaJ]5E5hZSulq?1Nc//VmtaZp<;?)Plr_LnUj6]j4gm4RgMcH1Wu)U7\X*#oOS(l#qg>8(^0>[FujkodDUc==\pm4SV(X_R4DPKd2J+ViM$RB*!U^*uT]!6>HQ6K,1U8/&@cAd;<*L2],2$j<*$p&p;B@$e,H)I`g&0h*r"Lg`R<)B"2G<"dcIg3=n8GDrWsk`^5Z58!BBNTUtqL:)1h2=k5j+GW+Wub`bS%9k3g[kF@p\=$dfMBVKdUgZM*-:\:hk`&\=>kgKMc^!Y-*V"TneDM^.fren\jT6J[n"_RAh&\?\%4=-+SX4$>L&3ZdT)\@Ns`(J9X(.GbL8$m7aAfCacK,kmW8Zn5W+f%Obej$$@(fb8Znf1]J[=iMD]8lW7J10C=SZe#9ONa2qn%W*/%2Po(@^)e0![;jg'&kr-'[B`ue5SdH<%+p!_a+]AGE&J60qCh&)m7QRVYmBsD,'m0ur1-&ef??4[,C.7P/VFarJdaUoM]VNp]<&q#h5inf!"&Na]6pP?tQR*Yc^nF88bL`g6E=OH])#hCC.n2H:%;KdP#$p\9=6PcK80!6@m;Nd7KK2.Lg#nhoC6j]4I`uW;Dkf7['M)J'p"=q--.mPqUZqql46W"sl1bf_!71f^r:,OjB<7+&9O_+e/"[nOgTN*2`!DsD#'-ee3`'kCQ,a'_^73PW`0F]`?9+`jU6;ipk&s32]KN,o9_"Y^5LXjnUY.*OTF)]V]N5.;J\O0.!lRVrc`&Te<$-49QJojGF>%g63+\HF".&%jl$5sb=@R.hTomR""UNab=6g*,#??He(J9=!cAXTg'!MOss6ejF4An7[Ze&f:!X@$jK@@&+i;%n5fh5G%@N"WWe/LaNg$fXjUJ&`:JhI3f^Y1B?Vm!8dEn+5fm.*e-b+GM9R;//"b;K*_tuZk?7TN$tZqN(!:S56d>H5t7&Im*qiX]^XX7j>Us#WmXf-jhB!(em-f14U,M$Siqqn(]jaK4"(I*t;RlJF.H&Lr"+bur"C]5DNLEnj7b_Z7CL3'I)MWX(am.V]K$-@kTER/fVH%M4+MQ']QnZjno:M+i2Qg@9b8dW91?.g2Xr?<<@KpL'WZg-3Tre"j,UTFjlg5$CEUin[SItU1XBT$8ZPn1Ze0lb)C6I=!g!j`-=iG=No8,Rt.?nQ>Xok(BbR9KL=]Y+FWQR[%fkm;cH^mM:P*XV;*X.DFDPYMJ*^G;(s7"OVia%Fe$AE$.sIu_[#OF5Sucng[F-3ol^'N4?fMP>!rI?@jgd:;Y\+H4`0XH]3&$@ZPG8R>U+D\)l>aKJi"Qj6+3>g,ZH?7Snr%[!.KBa#,dhD%LbKZ_7Z#iD0!drKJ;*[S`BdFPY)on&u[,/L?X4G"X0:b5X;H*Jlr=b`N1U11I+dR^m`Ird-jeG,@uk50SK=re7aGmAD*Cb9F3UH-Q**m6mYm=13"e\LbcNY6u(Z:,=[855p?\.%TXdI66K=I%1F)lg1*[NX!T,HQB8-Q;IJe3+I]fDP?8C<*GPR4!&CALQ/4+&N6&@:P#(hg8!7BTL6W+#@O>\5W99G?mM=G+i+;tHa*Gj.q"C)5,$(Oj@^oSARN>fV8R4'O9QNi&G`uq3&&s?^[Ukf;,0Mcir.YmWdHC=H`^%$kVi'M[E&"N;9d]\bnYoCId:2sk#'?H30nXX0d6pQBpLLVOGUdOJk,,HP-+fOheDKLQ]QO%+!i;b[5pET.=4Y\R7L2AQWEde:P+7.3RdP?5rn\b/P!bc$j_T,3dct)f-s(_VXrp'ZapXcMXY[J!G:s<`InejK^B%0TJ[R/0m\tP@1p=+$*bh$@]&HAab]h2uP^$g0PZbPIF4UZWGTipi&%V+[BU'3$.r3bX.(.7e/"hS5Fo![)B1Tr^Cc4UMo4]*OEO3=K%&>Vt`A9H4t6A$('dU93RKDu6ko4u+peDb+oFMG&S$KN+YpH?&45PpF0X8O>c\h_$Vs&<;Q$."V^K=AkrNKhS!^__B0RLo"!9g0cU(kc:F^CBOCd*EpXLf28V9"id9GFb&Es,XB9NaAET8'/=P6$;f9??oan#$#"$T[A>TScn[!eA193/_Ej>u1h/hh+rVcS"=+OEL&sE[>sJFh0[c^?!S3WuoL#&a-hPIo!&Ft0$`OB=3eQc))H:rHJ`S_8,%c5;T-)9Ecots=p?:r_AQb,Si%UgpcgHMp+Dbj2J8S0o+qTDNQr8I.rbn/$]akEuiO3)o]O//7i6&'[8jZY6%\Zq:!;>KP;IU_\L-F'"r*D\OGc)ZFeMb=lB;]^CG'kj>M'e'YoRYW8*>[M[8ceO:N

I$!MC:Hr!q_(TT,Cg+nH&`GU8T/B"XB`B0%#Is'-'`*2@i2D?rt.lMQ#J]Ba7*Qf\m[l1-Ja_((#S'VUcRm&W*#][*qK;`0qG^cLnk3(u0!Xe:_YRF)dFCW3&_#Jj\G:hA$p;6!F[.3J7Gp@!pN&\1C6U<(fQd#?lTKto&bEtJ3FBehg*-@\Q!td(&Mi!L[Kfn3&P],M8eWCNeRh0b("+RLElo!!eg_;RJ`Z&)5#nmcuEgY\2@*8UO:V_,B$D53Ts%U.Y_g27^)9ZQ3-(MstHhlh;6UETCD4;qI-UY-L4?NOJtG@X)u"A2$06smFRN[G#?9A1Cb$7eBPYr4ZDN=*`/9`_+?S@rCb"W7A"(n/Z@p>4PN.hQG-+=e^2Ho,It(D6d)9H]%hLnHLPb>Mf5R>!X=mXptO%9I\eh!3QhAOln6lSPVX\h!*Ce:,j:=5IC6&0?qAX"74UGjc^i%4V5+3XFqjjVo5/clGM8/nUVlMBL-)l'Ij;X^Bd1S:mi`]b)bq@&DSc"Bc9f)8Xk*_`gMp=D(#)^.aH8dPF/WXIHEK%^/@<[.)D6anLU)$B=XHuP-Et,5)7j7rP.Vu&Es9mLDK])bc/Z4.WRoGeI^\?U'u\I!fmmGi(nefq@Z6T&:>!iFQ]Mb5_*(Ohhg-n5oq"+p#^?SbeJqVKc4c(Benl)JY<7MF!?-/$R*YM^9K^_14H;gQM.oG/q!^6RST^=\sKOL:!YhhXBaS9Q%f:gV$@t+&nA7pj[;.GmJSNI]AJ)s,h-4Nf$_V4_Qs9VB[&]Slqm%V@!WiUe%#ID;\!.U8oTW:-u")'?(iYS-k#X+"I@*MQ.k_=&(2h9Gg3qQg[3T?(;X=q=[/>g(+3>3$k7SNZ2]&&qnf2&rbAi=\H7+V(!T-YWFE]J'11t>m$7`JQAg`g*K/mReqMCibse>=!Rj6Xl50PdI?\L6b#4i>lqgT<*rRp$J&/U0eM%d2N;3Q^\@U^$J;Nt,:ETa.Vj)Z)m*ig=Q3Z'51;fE"PG.:D#]YC0ZFO_N/M(e8qT-O!peuZ#A%)aTH#q2g:WVt_L+X&U\PbH"Q6Zbgs@INR/g$F%6cREk=;BQsD&N]`"/`b6190>nK63$YNMRnSDUhl')Jjs;E[i?UeY;npV90]/A0`F\9JC4iljHl&[p._c\]/FMRY-\I6tgeX$o*a*=$sEcb[Bo5?+A&Pau3#)A!EUrU32(Ag/\S!Ql:Y,:S]m\aLI'S9Dr!DhO054'%pZaLY54tok[fB7eekrmF03trOEZ:Yna3LBk>L4GTc'hpmY3;03j>jo@@+Z%2&r4>G5Rm^55-.T=i4TQdmJ%tBHuN[8RBV_^I8%m8$(76i4P#:aK'llL$]2fAaC'Ba&)>dA4eWE<6.=L;=QL`Bq!oC.ClHK/id2Q4lt>'7oKP>=IM/RJBbBi@:Fm*q!uD=i!s>?[Omj#u:$7o;@?K`-WJlPY:^N@78:s&jS4ATHkYE6AC*3b)pURIG65]'3B?9@,#FX4Xr#5XuD%Lu/^Hi^f=Xg\e31BfV[tn@^N"&LslieS+IaH[qa.J*JL/DV\TMgnR+>I8_`Ee>Lp.L4iprn/Ma=:jgg'!D5$%,m.U/#o3F9R<$9a%^W_=nX@8aO:_-BRGXC!=WbZ=4%+:]YNCW,cuIkF):'OOVLJ&L^KH+EH0.$r@3V";$N.Of;EF'GjsR5)_c!(YVOFbeDk-.[^/-)Xlr.6"=j5*[N+kh"*([U8V.ZBjm9_Z[tY)YEqWS8"iDtaUZU84gV(q%g<2j7g9%1l=R&P=NQM@4_.u[=rgiA1ZJ'!EiND&+H-a7qnB8BcPOumRKbk4O.5fF5hN0AH+endo[?#BPDe9Ck]#MH_,\M!,i4D*`];_=0Mkl&9U":n![`G=d^8HFENQuO:.,fXUuRsS"Y:54-ItWQ5q1F[78PRq-2R75N(+ptGS*HDQMhi]PDF3]g8'lDU/HO!LnDC,.8HQkKh6hDbXK1aB["U$1Eob8A@,=0&O@"#;&*)2<(05P9+qP!FVnejC'n[2Lk8/E.#=6=WeQD!7R<]9W+[NSLaK,/U'd?fWemaCQ=c"X#UO4rM5mPUl#cUq)p@IG4GP'[k>X<)'[7bI@`K2_=/uDMI+]FGfN:4I;IN3D!5qIJ-bqu@cWY[7F+SgrC[WbTBC2F]qU"5gStLp#P8QgcX#CMsmUkh\ULs++JSD2FMhg4uj!fNG/EZeX'M!os76\*[ii36bF"Ogq>r`PfnR@*gnIE08*XNY3G8Kju`1N/2U>6prtGX0+tsDtT:NjjM#]gk6T"9T12@9o4K:,`X`"(rhs"JqGg/EL'`5d/R091'CtrcnR9lDA\GEdPUB^XCh\_MTN/7>_Q"A.1mu.'3>8mc;R(;_ie]D,Rp/?BW^46p>TplFJ5X,fg&qCW-h/3AV7&D7VUAX8%O^/`,JI2%HdCnR,L2I*%#E4&;Va9CkX3Q[>&SB26Cc5P(9kZ8Zh,?d5'**'1kWf!uc\8S=C^q)FV\P@E9Z\!6Ba_+pN*'BP]Lq#<+5#;&#\NO[D-kL2hJ&e5q*Eft7t8p2\P3(u&+lYr,umkom#\VBHS+R?/#^er1V@Pht'H"ORY[@u!c'LI_i+Acgp*'H,2e3eYB>LDV'`-B8DR*[(r"[tZS66Vu8A6o7Yuk]JGp6Fr*]V_]eY1')MMN?>%S[R$!:3,LWs+A!gT'iISrA+Z#D:/;l^\n/&.aGB.V)jj<);,XNlV[X&=>=cQ)?Gi_8P!`9TO*iks>U(2c(Va(&e1\o`nCppo"D!4K=:jV,7RTX970_hj!Xp>&Q,6foU2'eGZk/ZGYX=/Pj"MBH(PUGghF-E=`i(U#"&XV);MiLc*+T)DBGb3`\hlmF,W?EF;+C(2au'L)bVMkG6`=E"CF"q5K,%j*7?K>;[??4m+e+H.&/XPb!nu6c4']%!YjWc4`ABTRTcdWVVKZE^CPPbF'7m1J_H;q)0_(#/Z[h\NX&hZa=Pa[.6(')OO.g%fg9$B99se/EGu\O'S&S`JH2\Bp#%BoNS0jQLLl2lAX9q63AQ38sfp/8-Ub!jY'I_!idgFaG6/986Tr!^PKJFm^W(g!")]lJB%;Tc,-t'8)0h`2HW/UsQ!g4GPL;p-CZRH9M-:t3I!&W+C!Vdr_Je&k^A#'T*\@"H?\RD(U3pM^CPKDKC%Btmk$qlP`m@8pPb>>d&0Z/bm))au?AC;44O+iKZ"bRJN'^!j]2Nu5C8[DgX?oElR=R8a,*]-G$6b-*X;1Rm8'bHGoQonS](5.lC1^lXf@OP=g9uVtEQk:`GY]+`+Y+S>:Jg]UU\#uO\Vd\&u`69\ljOE1PV5TuC"&6,Rk3NoKaT7M[9L%F+1!IrE"J$,tspu;,Aj2;Vj8eV8p5@@\YH-!!(%f?1\J!WNi)FL=2L*;)s5nO,/0M+]5&=#Z4&LR8tRPA7*_aV)rJY)fYHDb@UidcRUSQ6:G5tLLiA#[<"0`rK/-Q[P?=,/6NU6,3>#r_=O\j2Bic=/#V+7AOL<79lP-R5;6(pZ696u>KhTmJU<'YRK*,.46t*0Qa_JcAWf:FsXVqur@'n@dNf:b%Wm&JAWsg3[2.d]/(:Alg%Aq\jfR_XF((#f&Eonb-@;DY17ltNLphd\KKkk`3:hqkT%oGmqA%FE"M)Z:Yg8*(GLTYbqi5b?T3(\g2Uh7$7W\^p]2DX[5m`CjXCj9P/"_2d#;AWGtTj-Z#'\Z<=o5E]>;.gcb5.qfH9:1/nc!m(M"rFZJf1`oVXhmMVS6uAn*9N#Aa9GSV\fp8"JH-u0Z1@O!*8d=_\IbJC$F7T^O?%EKP"t-P:QO*T:4#@,#_!kqY"0RZqf/s_]G_7ggWmQ1LPcit[XjK3I(R:!r-L:>3>u/oO-0s5Eu4MlntEAu#S52?e:!o?=9__]YuK1;;FH3>&J4):'9_<6;b9NA5nM*KaO!D"-N85pkgh"u4J!fm57GT.Q[5/5@Dcc'LS<"ppAQ/IUZR=.0fa4(OQ.pg_<`7cH$?-U08k]akA1"m#Gr:"Od+$dPEjRpeDMXq'XQa5YH.9L0rE9Fg#?qIUk@bsDYd,p6mhO\0VR(YsUYGd0YqN&K,L\j>"-G6ZhDW\nD9(b.$QNAE!,ZRB9%VDSj?4S+1nkc@H#UaZX`8)*q60W[K5eYnp9VdgKA9%`cN'HE+2a(.nq^<.04=8'FEMY3uWCmW03D@m&.JAnO@9i<-501uR1P6PH9e;!"&'_Tk3V?iA2gkHE>C65@#AYNk\bRi"=,+"\68lCbLJhDTuD7%<8"rf*YkgjY1N">B1J`msP6VN7@Lbq6LS&eV7!9i@"S_`/V5tVA*Ch=OS";c\;@2%,=c&Wq.\IBqKFQB!'Bo-h?*mf^JM2DVU!'QO)5mS`83S8tZ^+=@KB-$#$"]J,heR/UA6'#+.l0CM#*jBjP_UP.D3JDZ%=W$;E!At.T<4gLV2`pX[or,GY#M:1!SLC?^D=+]qkT=2A]a:?GAe'V:'6K>XmGqSP;Ig]qeH4pJUk).SYcr;f#I\V\p7bBP?XCgI`0;Gn>WQRa.9-IP(i!.]m#7%R8lciFek1]cG.T#g-CBN2W$L&HhIaZO%1e[YT1l1;&1kVj&?7lSq#U!YpmE-fr\O5GU#R02":lb@To'?U:M5AAR?K6jfO,[ETKG02Y^,)DJ1@HaSY%8nK`9c''FQSsgT,8u"*pG/o5>,*jM?$NKsSl3%YTu4^_,qd;p(QthPrVY-m.Q$JtSqaMI7R*MQ3&,#mps2R\4=>6C!rc@43U%TNXTp&YUP*"pkAi6W+>&Elo$2\lW^(;\W-nX$Na3+C3VLbIKsn7g9RY!]6ED<[]k*'o6]fj"_Wj&sAr?Jr9nRJ254mO[S.SKOlSWOH%mI``H[X0f>daUdf,C(]mId7hL<;CRGaT;@utA2BmA+4gHPX75PN/KYkY.KFsS[L+sp$q>#0Y#Y![6)N6BX=rB%#M$#aN=!WT2;b8^V1+>(E!,^Jr2d))h!,Kj^;nF9oC]q\Aq/mXb2_!ujMM=HL61Uaq%TZfHT&Q0/Scr7StD.)=qbnRNb<"NcNZJ^?b<)dbi.`ueZUILt(es@aU1J8sO;1VRU;'mIj!>A"S:(9198W4#\m%Rq9nKCnZ#M\="1K9Ri-9K/3HMm:S#CaZH?7VDY[&[`%t5U&!b]p?hpHn)msBJeuS$lgNC]@RM9@QN'm*&ku.=dB,1lVqn]k%I`Dla$DWJ'RQ%2tptF)QSaFVd`^WRS"#1&(BZ;D)QUSsAR+729oU?s$^*alPOEG1Y:R@ruR^D7@i9W>\0:Yhu;P9IMBl;d-XY;QUW>6IIGhD1LL'Nnh7C(AN``VEJo]&"HThIHtILgA3/e>cj..[!.Gnc.P[Z1+40qf-=jt](L>]W)R`:?+\SMRX3B3ZlV`9(#AoO4+T7'`:79#,$q2gr(U>cI-B8Xf:Bf53_\SoBNEM!Cr3=X(e;>i`snA\m+m1U_@`."`2>:jHdRFgf>+lAbq9bLBa!=csC=?u7Mr,$"F-na,]ZB:QF>aD4P(U1RV2iF4_i'KGbto)N@us/.XsDI)s+Y1_bo.uu^]^6WV2plRP0,;"dW:D@%nhB(o[k$?jtL/'-eqf;aq\8-3ISZR6Ih&*4)@'cOEe=&bBR:nU*-r,BgJi[lJ6$1O_?8aD^Qu'OPMVPGnf8.Re/^EG!3J5;U[7M>Rq-'JTdNi(pVN1KA/?:(l$8LbUXl"%Dl%mQkF+W->joO(?Rh+4I/f_3[L8d9[)m:HR>lp5W"#(VA$tt3]Z'f#?>utLn-CDgWWEf;3ZAbc?a3OB#?7EuTDkfRdire>,JckP-4QJOuoM.9:+E8DhT2g;RqP_%[%F&^5Q8O>nb7bSB`cS%9$/1q_;3Z$Zj$&N',ce<5qmCs\EGm0V^9V)qG/d8GGG[]9q([12H$Q0nIQt`P3L\C]#9RRRcDY(V4<_6^#"YtmcM)%,9+:TP9*QUW:?EgClReMc]N'e&:.\n:X@+%tE,!\H`2(\i=u-0)oscn:FsF-';U#JanccKUG7o[I5jjg+`[68e$[r"c%1d;b@"Pb=h\8?m$k5eK6LY>>lE`@S\%cW%gJ2nVX/*)Amq\^u)e0Sl1"&am"f"b)L6aYFi%R.q%F(R%2Eh'[p%u1"nX*SlAR!+9SjQY^_ICV\MKSU71jYT!WQ]IP251[rJ"tFd!4<7&edOhmVa-#O_n+gOe+]ITlNe+U.TDS8Y^2eRMVA%_e=TfD3b;clmrB$%;3P2d:U;.9Bl%'4(D(C-5rEIg&uA7Dq9d<)gE?EfMeLpE@&ZFGUU8gIR*#goh?cN7IEk]O5EOk9tE#E!d#rdg(B"YEQ[MDH4j%4dF5Y!N2=$AWS,`nfM:ME>\:=VBn!GA:#$09#Itj`[Y9/_%e^G&2e-[KR\'ki5nBUFkg,"Uj*((JQ^:en<:kHW&A_8d#"!1uFOqkIXuC/J>SZ5$o$&!$nUO0gc_o<2FRje7b(sa.%H[tQK^^6>L`I2$]&$bdGh9$cbm!AXkL^fA=%=Fc<2_&-9,@67!F'p)1/q,9jB]#qelfdY'=#U\N#,BWgKqT^RiR3(lNr,'+<-d-Xj2Wj+Hq?$70M-@LhQ@#[!,b8cfUX-"R?^e;,C$6KoJl&Dm#,&pKF.SE?be]#NZ&OR>j5kO'UC:Zp38In-5-GP"]VJDLn)&s>Xe^n86J*_%3,'Cq)XiK*gBJLs0k3S3iC.oa_>`L8+=W?=V_+bV2Xh2(+F3TF1VqHhfEF=$*pSeV(8q^`efd$Z;Fjg(lAe.ZocmSb1ZI=:8(jV$L9mq/5S:A&hi:4?^^S]>qRsg(d@;7glG(h.i8icYB0B'^qaGku3eXj;Ka_XJ!K8^DK#o[lWUEY:SkF]^eDH"80f_A\0PU"#nPE?n@Lml-^N:'DPAlTut9geYr%G-kK8/f`'R,1136Y7=)"=OL:edW1lA!8QAKR(Z/TEWaPs.m7*,)@5`Mt5gq9')[+@E^RknSGacW>%H,)Q\_(KuiWCFOl,^IZ0I$rc2!,3NV+hsXWaTn\2b[_P35s.N&%?:JqjN&V_+HFEp#N>KUCgN%^[N1KeUTmRplTd`+-uai9S@S5jE[\a="u,dI'J2:Ed8j8pF>YKbRAau4Y/Z>DWMu[Q_"*Y+5grY.G;(h\#bHuHop.b^-+YE/kL_ARaFF?5Io8gH',!uWa.Cnc4$)mc!U@T0J"5Q"p(*X,b=EY)\,5hMR:iImTt"JNspM5S-:LYem^k$m\)t#Rp:/Zdjc18TMlh/3^Y>d1oP0";)6'Ye8eJ.':lq#tTm"5suJKN"hXl_UUq&%YesI$O[#Fr4aI`lWUbEp^c3+c6skZRQi"El7c?(dT'6]@]48+7>Rl6,rp%'_DGD]'ep=h9LQhD!COa`>.e(Ee+Z4^(5t!U=^b&.@09B"^i5:fN@[[S6&+I`IVeEl%H(81`LhK/#$7+ACS(`qQEdr1UUdmW=&#<4]3+cO9pP7?`s.3K2N70`O?rb8O!(i>YL#gKk;Ro(M7<#fI[9]_TYJQ4uK<8O#L:$W.$-rLXZUTu$)5R'8$j^U`\ab\;QAVH(]+'D;RPQD:&(m[>i"]YL*Q8$oGi6mTEC9"%4d$i0[%$MQ\)m2?I6:t#4Pc(<(1pRmU=HY(B#&t"FABRSJ,#P^-"VY]-hsdj/#)at4.`tGi94Wd:;_^s>O[Ts\6k="Q9XSp_?G;llRb9$ubeup%_24D-Dg]`gG%>HuX,R04_6R&KMl-B>rQPs"[pDd*I,43D$on9*mIBlBLf1n-D_3ijP9A.qWM\M,M1Amc%.)O(\0'$?fI)K:@k[-uE[R)D.lBoXAkCPBQF87N-CRa]X$1e&3'kEKVO3K=t*&/AJcD$Jl1&;R3U^MgCq4s9\hj]'A@%ZAO'qS;hG:/"=iY_[o?V`7J2"@dB(k]Ek^I3k$*%R7#TUNV`WDpC$H$t-nmMn0"r-(85s70o,7aHE5fcuWaIiUDrtnS*`tRT7q?L9AX19dS/Y8":'qZ`64m6afC,o")Dkk`3?k+)d;`15EjS<.tl,i$$V=R7pP9_e26c^>M'c;EV@jTePRAU.6n4bYl;,Se8#8N3W5IV>Ya]eFdL.&#C6)XX5kU+&nT\!i#\r*_iDBG,DM7bs!83i"cqAkdS"YY`p6KF1a9R<'sF+Ot#!oW/sa1(0jic`S+4+sO5$_u&8LP#mY4Q!r02c)_=MN&%"%?+:F0i*nUKc-:I(Q-(<2*:F.8VJ/?d:/`=jNOi5eq_s)06eta>$:ZI+C>?,:+03fBr,JlUh6K5TR]S+JL1R=Tr+)$@\RP1$7^XiDq\SYXFrj78..bKaI_Nm&agI5QU0am'iVP1d+`:;9GD/iIR&Ullt%IFLI5m5Oe\RtTC&Gijr5hm0/+fQ56FYl)mrtb)uAgVpI-t=47)d/P]@o,4W1ADiF=kol^em*#B(.:VX=BjXo]kt:R][aj&_$JG`Js"j@fsVDZEp,2t4_$9AD#!7l5c@UYT'`EM1ND/=S67-hs3:=Qq=$1B&n'&'e(ko_'uOKmUhhU/oVt9&5?\4[IR^of1%AM^$)a_Vc:r"J4el:d"blSEO,e$QVY-<#1I$ur6f&]#I78N@TSM8lW'UnLc:bi;T`L.jr*7k$R;k[S]=3=HO*/ZK)uVFcu?`&j>^,k608[OdL0IPhE=?:L^I`2RBEH_Qu^5dW0^n,CXG`k!K.a;\k*Dp3KPj\R/fE2-@#%`5mpX^^9*2YnY7c5TBjS'X]q_?.\G2ls?J1(b9A2oR4*RWBm4$+8c1NW?9aq4PM(lHc3+F"0A4n-ZOLMY#./-3!)';__2$4A\eM4:qWG2+S2$MM),+3utKo'9//+=q1;.?JP.bmo-r2s.)Rk"B$F@+mX1MH9P7o#&c3<)D[gYrBJ^I'ECTB8A_6@Wm//c*7dgTto@k%1QFHOeHQQRBd_fJV^*W%>HO_mdXHo]_/'FU%=j7(q`K)`sDTq#hqNK4i+U!]JMkr@]],C$`Z=GF\eMQ:WAHjqR[T1?\8q*?-'F@g5q+aN/U>BhT%]V>@iX5M_o)k@uP%'1#]im**&dn,&IYu,&gFH;B-.@Ha'C^2Je"UE;1:>P6&l^+i(p]p^kYpJCC(=S#iB.lj<1m>+?kXM(0]7Mi`h5f%U`X1FT2B03W(*TSD?SPFes"=l?*70KrXg<;Mbc8*jB!%q,SgGBH7VrO&gB2]b59XI]\2or#blShU:102)Tq7MVKGB`]uZ^ROqs;mRSdKI-g\@YuEq0*:*o?t7Y`9B\q#NCD$bjn:gK[Xo!5A[l'Z8%HrW21`a*%8Z^=H#_mjfCoh3o9_Z'l_>f_?>rJhAf18U1H2ni>h!JmTD:fbYubf):!)g,3Js7NKY-q,RH/h/)X9\'3e^%;b0^Tm0NS,"/B'PMYT8uX+Z2qeXL:@E`u2meJbpAcr61!G*WH!%Sk]H!'g2FOAOuNsFCk,6lajOe2Jb!(^BduO(8[CSQ6TNrLB#Q*5A/]/jO<[B0aEZP[#fr?M0JH\-OiAAGC?:khT%ekK;PU0D#S>m^M*r\l&0pf6*\i@CPEE@-Pp,haj)'<0LGj-L,H&]"jk=jD_9SeCQ`?b$f\m%jm"I'5"l+(A0(T8<0TY?l!W(>[,kA(uC]"RAhlRVp5_qLqP2pOqntuROeP#G<=8?j%:g32q9^25m>=hB6*Sm)9-XjM+&4P?imigY3m;$d*'^7m1Dh,!=?_r;67*1ERGe5g7oPJ_H07O/0]ZT6YsbFTXcI&D!-rB4K'\'()G#Z]jhPBVcY&W&iaJ>]9-*JG5A4R_DDZHA#Vk,%)BJVa5&rPIEG@8J:N>0i._kJn[0H-b,k1oQ9Ws_:*P0d?q%0`S7IC>39^`eju@Y?G*=&%RUO`;&QG1lb+eU#W1_jY]R/-E(!+`[!:X9@At%3l/shjM_'Pr\B`UQNe"g9XR)mi64gt-2X$qOJZt_S3afbJ2h@mTL%Iq5/qesBbXMr:*e@c"QUab&6etoJeG__M_'iPOMk$iu0!-!G%`2QE&>Df*>V'*T%>EJ8*Nk0'^;0F=BgNTah?=5TII)"ND'a6fW>KNm>oa##3dI%LCS\Bfn.5K?:-%MZ^3Q)[h?6(u>2PX,D$l,&B[r&>_9"5#rd%D_5'?B;-RWc,/P!Pg(eMr&<3Qbl?2ZK0d"@B'S.CP*ltn(*2bGp]H]`2Cm>N`,:1/fg&0h7i/IB(m#:e@edH?Jk3b&SL-6oW6(,-ZQD/I$7Oum7-jZ)!XVC'DHk-Rc@3oo8.BqAbq&F#rtPbWQh(TB+E'iQL5F"GdLIaX:^]ju<]VU=6]!Tl*2MrfNFrMX$CK.BfV%Gu\4%Wd>bqY8'*q5dXL!84q\%;kdE=HVmVV@:`2'T[u)HSlI59e:gMS"(;c.W\tVRe>e3&X/]U0iPo#c/>.#T6R$#"@d6\1W+NnK*4emuW-RAl*X>j5gZ-alfWn51]`BrE16f-m8Yn2Z:cbj]OTpj@@T+,kb47A=FYo9oe`,XL?&hO?b[i9c.7*j2lal7-h*%ioXpa8JF%<^#`V=4TE"3(q0PlbptGVDJ(Zl#k!AY#1onrH/<]S(suV=#=XLSN8LCuL0mFJap=1ch4,(B]l8GNHH(EXW2tR.q#3%Y:H2fq`-l:#?#h_k7V(/P.:o=G-i%:sYQMjl+4?2QT\OS)2(gq6i=QNB)uT$VrV!_i12XEf?Q"UW?da;:Ar<8mu9?"5,jc+Nd$G&;:9Y9d(\-:gZbe;MbiO89aO)O9;'2Cpg2UN&ml^b)RVa51<2I%qq\7k5P>8)OrtkaEtq@etQl'.j<'H?VW/rhmG-m$r&;qDm8FWAT:WrC1:C-/KZNP1bZ=d6Q!:J&DAbOL9'V9?Q%84#@)@:'kPd6K^Or`BSgr3]5#5<2/OcmUIL2%VHaG#-m:!M$83h@D`^nTKkgUt:ZHMZ5qP$m.&cZtCtj0$E8ore)&k`k@I])l3ocbi35C_F54EDk[2<[(8sh0+eIdh-(H>G-:=Hh6A>]mGI@HiLc)XXQ##c(ih:m>.8X5RSf+R$::;-S[F0Yp2.ghcYfdEG'A@sBOFVY*Dp^OPar`=##s>_iE")0)ROK^$SKp$W.-i([BQ4R&;;2SBmVj2?q[[lki,je_LG9qPi7D9>;)D+BLnm6s+UQgL'"Jcu/":<@Pdn#RW9[o0a&llV7$',+;6$)-%*#fA%+8`)CGhj-+X3@I1'8/G.*0R@CK4epBEC^ILoD^FAS;\XQ;VB'93)bO+V`(-ZUnnBU`CS>N6[VP?k/Sl8Kn@o3(pOC!,s)"BlEB+l$`5*FF'=33'`)]a&582SZu!B;dm^90kE=Kb'_ZJ/lJO"V2";_MCYfISR\0FfN,68E%M+-p'@5Rdju2#0E_N%IJq3t%u^VT@"'g*]ga@Z7u;3ZQ\!a<0HJB2caGq,Oi*C=*=CH>[O3Z89]K5`#ZpQL2kgi>AO86'mYF[`NIp>4daCj1/V.[NM(;S%"K!`K`/0Jo$sTQ^#_=<6LboYUp"m9>8=c6.#mc.afVKT34'3'"WVd4e+@!I^CrEscZ>3*rZOae2@ig;uT6<@Ufg5Tad<@kGm/C9&Z%BD#,t9b_&E\Rl)1HKKKqM2(V@sbk)\U)F7YD1J#\YLpIUZ:-XGW\X)HK+t?t:0@8eLj67&X!O-sU5X..0LU8r2a8fcn"9AlLNN3^,hR\.Y_(KmG&d"!E%*1a!QCL^(G0;g5rQ?-7jF#/Wb:Q22lLHcLaD[obXLL*aLU+:c&Wim1sO(Xuc8ob_EjY\77FU@!njbpM2PTaH)iC+CRZ.HUQ3TK+.-PXY&tFJ7W>3W#R=iQQYRoCLh*e'7KQ.7/\[8jT,)M56O@AHQ7Fs-M3k90d9T;]5F'"OZFUj>3:W:Lo;\q>(q91EaW9`37O-$[-_iA%$-pS@a3QBQDO3L;+X^J\\!"_n2W1:fS)pJgic[`dC/fOt(2a?cnp7!tc/N_P%<$+LC'@U.Zi%2B+Toa;'`q"ed/oS:a(?tR2olp5uc5DAE?es'I>aFj8s#4-9O6;k^/?XcB0do#S[/BIZof/AYCD+SE+JjiR$,O&Qb5iIDN,kX^Haeb&?\W_9onSq"tVA'V9i.-MBF`QnZt/_AH`Yq1_l:U[2juMkQT0:Vl"t6Xr>`ZODu^Mi/2#1fak0/@?.if>"s-`5JP3'3TtL0Lei-*"sRjiV%JW')[`94KM4eCnub)\+0q'FYY7c$r4hVBIH5j(5TnKEu]&WK^/^FAglmRd)5qTV&I3]_9%:CA13mDRG86#K0;GS`9tX>[GYY\0b8H!-^Zk6a1gjNl9jccQ\1.1+RD?YbXMJL#=K2\"sFk7P`h3+&gj9/Q%E^JJ>AlDOJ$R5]M=-Th=UU83pU:&`*hcg3Ln[O.aP;PeW0LT^%3(l$]`4[OI.:/M''#FB-)>Z&%s>"=b>KA*/iM^D7\1-4,u=pZJaZ0?O%,HN70].!&M0m(8@RJ6UELP6:qe$&LsDHp43!r:L8E1!C?AMpk3V-<2Zl%Kd6/>ggH"ag-4HmcA`LF\d\ZjW72Lm:o^;X229o:4e;4.Ec^jEqI1KE23p#i8I;tAVj)m5m_6Wg]g;A6&beJR]=Uc[eETYJ_e%,&)\?8$:nU!qk;t%5;mPmi&W")1WK]EeA5gK@e;W<91m?s%\S!F+p<#jb%@T2'UDlc<,ebTlk+m:1FY=Gb:7I!IhJh25="mq"NoQZaAW^LO<5M6V(g6l>O>L7@VbQC0SK_:nf".mpAP]'8H>=8Z3#At^]@L9A\D#JH$mU1=$t";3<89Obb_q2oe2>HT4mc=Vp=?c$[\/_T1!'pUlm]aNB&F+&iAcL_*SZX!H6,SeUnt"$6tIamo.u5W&(5,J;j+@f9h@GUAX*9%uVi&1`0Gu<+uJV+@53:!q8:>o4L:e9J6Lu$pS](>PA6,?5rW903`,L-GVL'!Xs!3/o[J:^AClun"i5_OcIL%4c#Ndb*Ooc=46#Ui*&UO[-s\jSpNBI^#2)f0D!02C?^(Y]ul*;X'Yfb>32%@T!"0B\I(>WpYP6H^r'LopTs="FR&fSico>tG.]pLNrmpL[@9:cAts&Kj+%eT*u3o2k&+H+GW:]eF)J0HSgdoK;@;=rFSW9\I[aV"'9g_KrKRf_Z)9\0$"`3_n#N7Kd^W1V$]MG.KlF_P#rHp.N(O((>'(U`ZCd8Zg'VriT3<7nPD7PU2"@#]F$,l#U)2=^,fB%710aO7"l3UcquY7Af-4.!>(sVjimjI0%*+\+V61lrH2$\2B47/fHeL."AEh^JtU61r1_^0.g33c)O"KrKeSo'S1Uj+-k%p4*"%lV9Xpu)MS"[Mq][pGu*JY0^I2tR$>_:5',S9dafA'V@N8_1CZFTm=M]))7]&G`ank^Y+Kh9QD8H&'TPM^:c&i#?Gte1,)]>Kc6Z]rtluYDDQHq*k`TH;/^;0b"l!_f6;O#.Jk0&/kAE5mNfRb\3"9PPikh`B=bHqm5jgKQ3?R?;JB8*t@f>9hT]u[N"nR\F&i)\D%$Ze@%:G',&.AS%?RosqgDm:KaGM+X0ekH-Cs*1k.0bW`MC>#\(mMmk3YMT9fVi7>bZ!M<&-U\i&&T-3XoSij4%^RY7fuATp=U.l(mOb0.#4^mS$+'jOSYTE_#r97'U`E]];_n4E'mYG(`G+",^kfCNXpTF:_?Nn&[WCo)OA!Fcd6NM=H&2++j_D[Jf>hgMkQ3O7o`I`,OeCr@!!I-3CcU!TI9L6L683or1E,jqK<\dquQooD#O\(W"T[Tcd;;tW0SQ^4qj)Z#n[jdl6%W61FRp^.&=k@0VF6?_P"[k$*'pJ*6/+'Ukf;L#Qmt$r;+9_H%]-t98*cc!A"m,85Bh9MYUpFWHXXGQa'6\D8R\icq32U`"p;(E?G:hL?A%?N_]oQ+m#m;6OmB!3$:-I2#`>g(7%u,JP&0@PSfLU$<111+__75O;PhZ!Wr^UK;llenDWgIg8j=9--(0OH\bTC+ppf(%k"l:4PCHQSA8j+;dkQ&s"nXs'F$osdtA1&QBsr/-[\id&ZHHRICkXY1&d\c^KKP)=5'=J`"RQ08I',\a(jOXsJpsgbom2R'sMmZO81JAYDV?gd1\;;OXlTq:JbqNXZR'A1u'GM3@KG\;<.?l&LUlZiZ;j7J'Kb5LD"H5Vi#m1;a/P-Zh6q[erVqFPG9JeFo5q.`n%WDUY&it_/5i%"5HW;ueg0pgAljk(^ft:+#22O5LP9K*-aMTaM6m`JLD9?RdR'Q4]Po.@3+)PL[&b;K-egMT6],7YEbT1f'B)Cj#UnFTr?7oRomWXt/7S?6S9LLT*X^S(DF%ma7-Ibh6b4s\9@g[DRo#'#$8'28O&`OD-H@VA;lLjm\Ucnu@7\TcYg"t0q:=\4MArA@9-iAqer2uIH[tC4//f>u4`6V=[PR)U]qVWo2CM7b[:Ch!+4h)s3/JSL&iN!LVT4_%6'QE>2FhH.#$-Qu!OPtS*4B&X_#cG*lb#F9N<6>L<4,NMieR3M&r]5?PS!jb?aS)gs6J9^M(,2G9W!aU>=E3:akc$2hliqECeSefiNJH=_KNftT:!Aj%g0_BqA_n3-Sd/.`k;'r^';%P)U_C)JU&_G!PF(SjUG.Z@s"=Gad@N/ah&qhTu15t+#14_b7%[uRmn/s=EC:eCK\NB2h_MP>O,G>(F(WX=9N&^`'^OPENtNI`RYr9TO&PS!1HltpYd[/<-!gVD\!Pc`X$f5R-91XUa"Aj(T%??Y?X4J<659F`[/B#YtUNCU9c>Q:W$ht[6ClMkMq^[V65=8^srkl6G]p`p[kro5PKZTn,CZ.Fo!lBr4P>os2XC&rd+Ejn+qOrr1EjNj8U5#hu3PoqTkkgKYfs&(c9$XFoH37J!g81B[J.HIrpsD1`I&++79"SS6_BVGOV/QB_L\5D2JS_B9IFML&I<1\oeT'gmG.3j+_I]47(13*QV.!mNh??o5F,Krb2MO6c?US`$S%S!'e%8RX\jn"*0bG^n(3*jV?=WE#ZX2[S@GT%7?Ck#B:Up,oRn?rd.TXVN0&cNTNAQdf:45Id\FG@]CQ&=%ILr2@Yb`)Q5XW#_taKhpT^H&RRu]TWf&'!."e0p.\,,2c"/m3$I5jJ1gL'*KGaS-.XD21pT8$-T=&IH&j&'0.iTF@=\u2b1`8WOD_QhBL#"fKQ:aj,q>oOd*'#)CJ=oMq1$:fl+"X8!D+NsP4-3OS-U7.n^s0),PE.-j_J57[C0RI1&jt#]21GYjK!T&A_igrr>7Vd*4B\6><[SpC`jipE/)_%/mN_0b\grQ^PS.-8uU`l4=Y#$kH85g;i.b181P:,?L``*EF1[R=&R14Z;J_HRQfA@#'%M9"sncZdW\<"%=5?A!Jkft^9'F>2%$PK*t9b`[ScrCN=_Zb!EIBp'/Hf9J%!oj:\RDnoIKEFF.og6:e+L'):3c=%f,6O3WXeOFKfUP78(RkmFS7a!84s'/5knW2ec.p=_K44Hs*O[KKe:#)bFXR4PL@m&Nb;2f#GM-aNVGb+ff3reO7.p:G.iQ;f]*B<*NZelP^B$"tIB9QJqAV,h+PnTqE3o^#B\`D.\;u/iZFMuEaOP3&mBIHoDcW9IKAtV^1p5Zb%RSOGS3?&?5^lRU6dZP,:siUd%!Ch;LNtec4n*O0p;C&?4[ZAbp&)QZ9_llHr?f8Kck+1a\Y&ljX6:jAfhDKH#,"\Sa^UHI/tD!:[g(!I,qm8oD\4T"@_']60GgNh1jrU)=r.I:/DW4&:fp2Il.3(*,kK^oe2FLr-_rDnO](kq1UE^00JBH^Z`S7B%C8,=Bo*fl"a)Y7b)?tLcW$e:Oj"1L2*@I)39*L:#*Xl'3C,R55\LPO2[<7ra%h`ghciNs5r\38S!GAjWNCZT?[C0_raK5S_)1Hs/&Ve;seZ+FP$=Q,b+g>OoAu.>-rR'Di+0YNd*cpJ+X@YKjllcEdWB#_RHj=.1"dO=")/IX%Kb/CDo/gI5OsM,l0%+kLOh2Yg-9(FQ*G,8U\6ls.dF,^9.=K0u9.9<'>`#T6<"[hV;NWm%U4*<=S7dU:P(/iUuc.f%EfJr!e6K&'J16-D.p7!+>j+0'%n/TcibS&8D -#<== diff -Nru zyn-1+git.20100609/wafadmin/Action.py zyn-1+git.20100609+dfsg0/wafadmin/Action.py --- zyn-1+git.20100609/wafadmin/Action.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Action.py 2008-03-23 19:05:48.000000000 +0000 @@ -0,0 +1,108 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2005-2008 (ita) + +"Actions are used to build the nodes of most tasks" + +import re +import Object, Params, Runner +from Params import debug, fatal + +g_actions={} +"global actions" + +reg_act = re.compile(r"(?P\$\$)|(?P\$\{(?P\w+)(?P.*?)\})", re.M) + +class Action(object): + "Base class for all Actions, an action takes a task and produces its outputs" + def __init__(self, name, vars=[], func=None, prio=100, color='GREEN'): + """If the action is simple, func is not defined, else a function can be attached + and will be launched instead of running the string generated by 'setstr' see Runner + for when this is used - a parameter is given, it is the task. Each action must name""" + + self.m_name = name + # variables triggering a rebuild + self.m_vars = vars + self.m_function_to_run = func + self.m_color = color + + self.prio = prio + + global g_actions + if name in g_actions: debug('overriding action: %s' % name, 'action') + g_actions[name] = self + debug("action added: %s" % name, 'action') + + def __str__(self): + return self.m_name + + def get_str(self, task): + "string to display to the user" + env = task.env() + src_str = " ".join([a.nice_path(env) for a in task.m_inputs]) + tgt_str = " ".join([a.nice_path(env) for a in task.m_outputs]) + return "* %s : %s -> %s" % (self.m_name, src_str, tgt_str) + + def run(self, task): + "run the compilation" + f = self.m_function_to_run + if not f: fatal("Action %s has no function!" % self.m_name) + return f(task) + +def funex(c): + exec(c) + return f + +def simple_action(name, line, color='GREEN', vars=[], prio=100): + """Compiles a string (once) into an Action instance, eg: + simple_action('c++', '${CXX} -o ${TGT[0]} ${SRC} -I ${SRC[0].m_parent.bldpath()}') + + The env variables (CXX, ..) on the task must not hold dicts (order) + The reserved keywords TGT and SRC represent the task input and output nodes + """ + extr = [] + def repl(match): + g = match.group + if g('dollar'): return "$" + elif g('subst'): extr.append((g('var'), g('code'))); return "%s" + return None + + line = reg_act.sub(repl, line) + + parm = [] + dvars = [] + app = parm.append + for (var, meth) in extr: + if var == 'SRC': + if meth: app('task.m_inputs%s' % meth) + else: app('" ".join([a.srcpath(env) for a in task.m_inputs])') + elif var == 'TGT': + if meth: app('task.m_outputs%s' % meth) + else: app('" ".join([a.bldpath(env) for a in task.m_outputs])') + else: + if not var in dvars: dvars.append(var) + app("p('%s')" % var) + if parm: parm = "%% (%s) " % (',\n\t\t'.join(parm)) + else: parm = '' + + c = ''' +def f(task): + env = task.env() + p = env.get_flat + try: cmd = "%s" %s + except Exception: task.debug(); raise + return Runner.exec_command(cmd) +''' % (line, parm) + + debug(c, 'action') + + act = Action(name, prio=prio, color=color) + act.m_function_to_run = funex(c) + act.m_vars = vars or dvars + + return act + + diff -Nru zyn-1+git.20100609/wafadmin/Build.py zyn-1+git.20100609+dfsg0/wafadmin/Build.py --- zyn-1+git.20100609/wafadmin/Build.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Build.py 2008-03-25 20:07:40.000000000 +0000 @@ -0,0 +1,674 @@ +#! /usr/bin/env python +# encoding: utf-8 +import sys +if sys.hexversion < 0x020400f0: from sets import Set as set +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2005 (ita) + +""" +Dependency tree holder + +The class Build holds all the info related to a build: +* file system representation (tree of Node instances) +* various cached objects (task signatures, file scan results, ..) + +There is only one Build object at a time (Params.g_build singleton) +""" + +import os, sys, cPickle, types, imp, errno, re +import Params, Runner, Object, Node, Scripting, Utils, Environment, Task +from Params import debug, error, fatal, warning +from Constants import * + +SAVED_ATTRS = 'm_root m_srcnode m_bldnode m_tstamp_variants m_depends_on m_raw_deps m_sig_cache'.split() +"Build class members to save" + +g_modcache = {} +"Cache for the tools (modules), re-importing raises errors" + +class BuildError(Exception): + def __init__(self, b=None, t=[]): + self.bld = b + self.tasks = t + self.ret = 1 + def get_message(self): + lst = ['Build failed'] + for tsk in self.tasks: + if tsk.m_hasrun == Runner.crashed: + try: + lst.append(" -> task failed (err #%d): %s" % (tsk.err_code, str(tsk.m_outputs))) + except AttributeError: + lst.append(" -> task failed:" % str(tsk.m_outputs)) + elif tsk.m_hasrun == Runner.missing: + lst.append(" -> missing files: %s" % str(tsk.m_outputs)) + return '\n'.join(lst) + +class BuildDTO(object): + "holds the data to store using cPickle" + def __init__(self): + pass + def init(self, bdobj): + global SAVED_ATTRS + for a in SAVED_ATTRS: + setattr(self, a, getattr(bdobj, a)) + def update_build(self, bdobj): + global SAVED_ATTRS + for a in SAVED_ATTRS: + setattr(bdobj, a, getattr(self, a)) + +class Build(object): + "holds the dependency tree" + def __init__(self): + + # dependency tree + self._init_data() + + # ======================================= # + # globals + + # map a name to an environment, the 'default' must be defined + self.m_allenvs = {} + + # there should be only one build dir in use at a time + Params.g_build = self + + # ======================================= # + # code for reading the scripts + + # project build directory - do not reset() from load_dirs() or _init_data() + self.m_bdir = '' + + # the current directory from which the code is run + # the folder changes everytime a wscript is read + self.m_curdirnode = None + + # temporary holding the subdirectories containing scripts - look in Scripting.py + self.m_subdirs = [] + + # ======================================= # + # cache variables + + # local cache for absolute paths - m_abspath_cache[variant][node] + self.m_abspath_cache = {} + + # local cache for relative paths + # two nodes - hashtable of hashtables - g_relpath_cache[child][parent]) + self._relpath_cache = {} + + # list of folders that are already scanned + # so that we do not need to stat them one more time + self.m_scanned_folders = [] + + # file contents + self._cache_node_content = {} + + # list of targets to uninstall for removing the empty folders after uninstalling + self.m_uninstall = [] + + # ======================================= # + # tasks and objects + + # build dir variants (release, debug, ..) + for name in ['default', 0]: + for v in 'm_tstamp_variants m_depends_on m_sig_cache m_raw_deps m_abspath_cache'.split(): + var = getattr(self, v) + if not name in var: var[name] = {} + + # TODO used by xmlwaf + self.pushed = [] + + def _init_data(self): + debug("init data called", 'build') + + # filesystem root - root name is Params.g_rootname + self.m_root = Node.Node('', None) + + # source directory + self.m_srcnode = None + # build directory + self.m_bldnode = None + + # TODO: this code does not look too good + # nodes signatures: self.m_tstamp_variants[variant_name][node] = signature_value + self.m_tstamp_variants = {} + + # one node has nodes it depends on, tasks cannot be stored + # self.m_depends_on[variant][node] = [node1, node2, ..] + self.m_depends_on = {} + + # results of a scan: self.m_raw_deps[variant][node] = [filename1, filename2, filename3] + # for example, find headers in c files + self.m_raw_deps = {} + + self.m_sig_cache = {} + + self.task_manager = Task.TaskManager() + + # load existing data structures from the disk (stored using self._store()) + def _load(self): + cachedir = Params.g_cachedir + code = '' + try: + file = open(os.path.join(cachedir, 'build.config.py'), 'r') + code = file.read() + file.close() + except (IOError, OSError): + # TODO load the pickled file and the environments better + pass + else: + re_imp = re.compile('^(#)*?([^#=]*?)\ =\ (.*?)$', re.M) + for m in re_imp.finditer(code): + g = m.group + if g(2) == 'version': + if eval(g(3)) < HEXVERSION: + Params.fatal('Version mismatch! reconfigure the project') + elif g(2) == 'tools': + lst = eval(g(3)) + for t in lst: self.setup(**t) + + try: + file = open(os.path.join(self.m_bdir, DBFILE), 'rb') + dto = cPickle.load(file) + dto.update_build(self) + file.close() + except IOError: + debug("resetting the build object (dto failed)", 'build') + self._init_data() + if Params.g_verbose>2: self.dump() + + # store the data structures on disk, retrieve with self._load() + def _store(self): + file = open(os.path.join(self.m_bdir, DBFILE), 'wb') + dto = BuildDTO() + dto.init(self) + cPickle.dump(dto, file, -1) # remove the '-1' for unoptimized version + file.close() + + # ======================================= # + + def save(self): + self._store() + + def clean(self): + debug("clean called", 'build') + def clean_rec(node): + for x in node.m_build_lookup: + nd = node.m_build_lookup[x] + for env in self.m_allenvs.values(): + pt = nd.abspath(env) + # do not remove config files + if pt in env['waf_config_files']: continue + try: os.remove(pt) + except OSError: pass + for x in node.m_dirs_lookup: + nd = node.m_dirs_lookup[x] + clean_rec(nd) + clean_rec(self.m_srcnode) + + def compile(self): + debug("compile called", 'build') + + os.chdir(self.m_bdir) + + Object.flush() + + if Params.g_verbose>2: self.dump() + + self.task_manager.flush() + if Params.g_options.jobs <= 1: executor = Runner.Serial(self) + else: executor = Runner.Parallel(self, Params.g_options.jobs) + # TODO clean + self.generator = executor + + def dw(): + if Params.g_options.progress_bar: sys.stdout.write(Params.g_cursor_on) + + debug('executor starting', 'build') + try: + if Params.g_options.progress_bar: sys.stdout.write(Params.g_cursor_off) + ret = executor.start() + except KeyboardInterrupt, e: + dw() + os.chdir(self.m_srcnode.abspath()) + self._store() + Params.pprint('RED', 'Build interrupted') + if Params.g_verbose > 1: raise + else: sys.exit(68) + except Exception, e: + dw() + # do not store anything, for something bad happened + raise + else: + dw() + self._store() + + if ret: + Utils.test_full() + raise BuildError(self, self.task_manager.tasks_done) + + if Params.g_verbose>2: self.dump() + os.chdir(self.m_srcnode.abspath()) + + def install(self): + "this function is called for both install and uninstall" + debug('install called', 'build') + + Object.flush() + for obj in Object.g_allobjs: + if obj.m_posted: obj.install() + + # remove empty folders after uninstalling + if Params.g_commands['uninstall']: + lst = [] + for x in self.m_uninstall: + dir = os.path.dirname(x) + if not dir in lst: lst.append(dir) + lst.sort() + lst.reverse() + + nlst = [] + for y in lst: + x = y + while len(x) > 4: + if not x in nlst: nlst.append(x) + x = os.path.dirname(x) + + nlst.sort() + nlst.reverse() + for x in nlst: + try: os.rmdir(x) + except OSError: pass + + def add_subdirs(self, dirs): + for dir in Utils.to_list(dirs): + if dir: Scripting.add_subdir(dir, self) + + def create_obj(self, objname, *k, **kw): + try: return Object.task_gen.classes[objname](*k, **kw) + except KeyError: raise KeyError("'%s' is not a valid build tool -> %s" % (objname, [x for x in Object.task_gen.classes])) + + def load_envs(self): + cachedir = Params.g_cachedir + try: + lst = os.listdir(cachedir) + except OSError, e: + if e.errno == errno.ENOENT: + fatal('The project was not configured: run "waf configure" first!') + else: + raise + + if not lst: + fatal('The cache directory is empty: reconfigure the project') + + for file in lst: + if file.endswith(CACHE_SUFFIX): + env = Environment.Environment() + env.load(os.path.join(cachedir, file)) + name = file.split('.')[0] + + self.m_allenvs[name] = env + + self._initialize_variants() + + for env in self.m_allenvs.values(): + for f in env['dep_files']: + newnode = self.m_srcnode.find_build(f, create=1) + try: + hash = Params.h_file(newnode.abspath(env)) + except (IOError, AttributeError): + error("cannot find "+f) + hash = Params.sig_nil + self.m_tstamp_variants[env.variant()][newnode] = hash + + def setup(self, tool, tooldir=None): + "setup tools for build process" + if type(tool) is types.ListType: + for i in tool: self.setup(i, tooldir) + return + + if not tooldir: tooldir = Params.g_tooldir + + file = None + key = str((tool, tooldir)) + module = g_modcache.get(key, None) + if not module: + file,name,desc = imp.find_module(tool, tooldir) + module = imp.load_module(tool,file,name,desc) + g_modcache[key] = module + if hasattr(module, "setup"): module.setup(self) + if file: file.close() + + def _initialize_variants(self): + debug("init variants", 'build') + + lstvariants = [] + for env in self.m_allenvs.values(): + if not env.variant() in lstvariants: + lstvariants.append(env.variant()) + self._variants = lstvariants + + debug("list of variants is "+str(lstvariants), 'build') + + for name in lstvariants+[0]: + for v in 'm_tstamp_variants m_depends_on m_raw_deps m_abspath_cache'.split(): + var = getattr(self, v) + if not name in var: + var[name] = {} + + # ======================================= # + # node and folder handling + + # this should be the main entry point + def load_dirs(self, srcdir, blddir, isconfigure=None): + "this functions should be the start of everything" + + # there is no reason to bypass this check + try: + if srcdir == blddir or os.path.abspath(srcdir) == os.path.abspath(blddir): + fatal("build dir must be different from srcdir ->"+str(srcdir)+" ->"+str(blddir)) + except OSError: + pass + + # set the source directory + if not os.path.isabs(srcdir): + srcdir = os.path.join(os.path.abspath('.'),srcdir) + + # set the build directory it is a path, not a node (either absolute or relative) + if not os.path.isabs(blddir): + self.m_bdir = os.path.abspath(blddir) + else: + self.m_bdir = blddir + + if not isconfigure: + self._load() + if self.m_srcnode: + self.m_curdirnode = self.m_srcnode + return + + self.m_srcnode = self.ensure_dir_node_from_path(srcdir) + debug("srcnode is %s and srcdir %s" % (str(self.m_srcnode), srcdir), 'build') + + self.m_curdirnode = self.m_srcnode + + self.m_bldnode = self.ensure_dir_node_from_path(self.m_bdir) + + # create this build dir if necessary + try: os.makedirs(blddir) + except OSError: pass + + self._initialize_variants() + + def ensure_dir_node_from_path(self, abspath): + "return a node corresponding to an absolute path, creates nodes if necessary" + debug('ensure_dir_node_from_path %s' % (abspath), 'build') + plst = Utils.split_path(abspath) + curnode = self.m_root # root of the tree + for dirname in plst: + if not dirname: continue + if dirname == '.': continue + found = curnode.get_dir(dirname, None) + if not found: + found = Node.Node(dirname, curnode) + curnode.append_dir(found) + curnode = found + return curnode + + def rescan(self, src_dir_node): + """ first list the files in the src dir and update the nodes + - for each variant build dir (multiple build dirs): + - list the files in the build dir, update the nodes + + this makes (n bdirs)+srdir to scan (at least 2 folders) + so we might want to do it in parallel in some future + """ + + # FIXME use sets with intersection and union + + # do not rescan over and over again + if src_dir_node.hash_value in self.m_scanned_folders: return + + # do not rescan the nodes above srcnode + if src_dir_node.height() < self.m_srcnode.height(): return + + #debug("rescanning "+str(src_dir_node), 'build') + + # TODO undocumented hook + if hasattr(self, 'repository'): self.repository(src_dir_node) + + # list the files in the src directory, adding the signatures + files = self.scan_src_path(src_dir_node, src_dir_node.abspath(), src_dir_node.files()) + #debug("files found in folder are "+str(files), 'build') + src_dir_node.m_files_lookup = {} + for i in files: src_dir_node.m_files_lookup[i.m_name] = i + + # list the files in the build dirs + # remove the existing timestamps if the build files are removed + + # first obtain the differences between srcnode and src_dir_node + #lst = self.m_srcnode.difflst(src_dir_node) + h1 = self.m_srcnode.height() + h2 = src_dir_node.height() + + lst = [] + child = src_dir_node + while h2 > h1: + lst.append(child.m_name) + child = child.m_parent + h2 -= 1 + lst.reverse() + + for variant in self._variants: + sub_path = os.path.join(self.m_bldnode.abspath(), variant , *lst) + try: + files = self.scan_path(src_dir_node, sub_path, src_dir_node.m_build_lookup.values(), variant) + src_dir_node.m_build_lookup = {} + for i in files: src_dir_node.m_build_lookup[i.m_name] = i + except OSError: + #debug("osError on " + sub_path, 'build') + + # listdir failed, remove all sigs of nodes + dict = self.m_tstamp_variants[variant] + for node in src_dir_node.m_build_lookup.values(): + if node in dict: + dict.__delitem__(node) + os.makedirs(sub_path) + src_dir_node.m_build_lookup = {} + self.m_scanned_folders.append(src_dir_node.hash_value) + + # ======================================= # + def scan_src_path(self, i_parent_node, i_path, i_existing_nodes): + + try: + # read the dir contents, ignore the folders in it + l_names_read = os.listdir(i_path) + except OSError: + warning("OSError exception in scan_src_path() i_path=%s" % str(i_path) ) + return None + + debug("folder contents "+str(l_names_read), 'build') + + # there are two ways to obtain the partitions: + # 1 run the comparisons two times (not very smart) + # 2 reduce the sizes of the list while looping + + l_names = l_names_read + l_nodes = i_existing_nodes + l_kept = [] + + for node in l_nodes: + i = 0 + name = node.m_name + l_len = len(l_names) + while i < l_len: + if l_names[i] == name: + l_kept.append(node) + break + i += 1 + if i < l_len: + del l_names[i] + + # Now: + # l_names contains the new nodes (or files) + # l_kept contains only nodes that actually exist on the filesystem + for node in l_kept: + try: + # update the time stamp + self.m_tstamp_variants[0][node] = Params.h_file(node.abspath()) + except IOError: + fatal("a file is readonly or has become a dir "+node.abspath()) + + debug("new files found "+str(l_names), 'build') + + l_path = i_path + os.sep + for name in l_names: + try: + # throws IOError if not a file or if not readable + st = Params.h_file(l_path + name) + except IOError: + continue + l_child = Node.Node(name, i_parent_node) + self.m_tstamp_variants[0][l_child] = st + l_kept.append(l_child) + return l_kept + + def scan_path(self, i_parent_node, i_path, i_existing_nodes, i_variant): + """in this function we do not add timestamps but we remove them + when the files no longer exist (file removed in the build dir)""" + + # read the dir contents, ignore the folders in it + l_names_read = os.listdir(i_path) + + # there are two ways to obtain the partitions: + # 1 run the comparisons two times (not very smart) + # 2 reduce the sizes of the list while looping + + l_names = l_names_read + l_nodes = i_existing_nodes + l_rm = [] + + for node in l_nodes: + i = 0 + name = node.m_name + l_len = len(l_names) + while i < l_len: + if l_names[i] == name: + break + i += 1 + if i < l_len: + del l_names[i] + else: + l_rm.append(node) + + # remove the stamps of the nodes that no longer exist in the build dir + for node in l_rm: + + #print "\nremoving the timestamp of ", node, node.m_name + #print node.m_parent.m_build + #print l_names_read + #print l_names + + if node in self.m_tstamp_variants[i_variant]: + self.m_tstamp_variants[i_variant].__delitem__(node) + return l_nodes + + def dump(self): + "for debugging" + def printspaces(count): + if count > 0: return printspaces(count - 1) + "-" + return "" + def recu(node, count): + accu = printspaces(count) + accu += "> "+node.m_name+" (d)\n" + for child in node.files(): + accu += printspaces(count) + accu += '-> '+child.m_name+' ' + + for variant in self.m_tstamp_variants: + #print "variant %s"%variant + var = self.m_tstamp_variants[variant] + #print var + if child in var: + accu+=' [%s,%s] ' % (str(variant), Params.view_sig(var[child])) + + accu+='\n' + #accu+= ' '+str(child.m_tstamp)+'\n' + # TODO #if node.files()[file].m_newstamp != node.files()[file].m_oldstamp: accu += "\t\t\t(modified)" + #accu+= node.files()[file].m_newstamp + "< >" + node.files()[file].m_oldstamp + "\n" + for child in node.m_build_lookup.values(): + accu+= printspaces(count) + accu+= '-> '+child.m_name+' (b) ' + + for variant in self.m_tstamp_variants: + #print "variant %s"%variant + var = self.m_tstamp_variants[variant] + #print var + if child in var: + accu+=' [%s,%s] ' % (str(variant), Params.view_sig(var[child])) + + accu+='\n' + #accu+= ' '+str(child.m_tstamp)+'\n' + # TODO #if node.files()[file].m_newstamp != node.files()[file].m_oldstamp: accu += "\t\t\t(modified)" + #accu+= node.files()[file].m_newstamp + "< >" + node.files()[file].m_oldstamp + "\n" + for dir in node.dirs(): accu += recu(dir, count+1) + return accu + + Params.pprint('CYAN', recu(self.m_root, 0) ) + Params.pprint('CYAN', 'size is '+str(self.m_root.size_subtree())) + + #keys = self.m_name2nodes.keys() + #for k in keys: + # print k, '\t\t', self.m_name2nodes[k] + + + def pushdir(self, dir): + node = self.m_curdirnode.ensure_node_from_lst(Utils.split_path(dir)) + self.pushed = [self.m_curdirnode]+self.pushed + self.m_curdirnode = node + + def popdir(self): + self.m_curdirnode = self.pushed.pop(0) + + def env_of_name(self, name): + if not name: + error('env_of_name called with no name!') + return None + try: + return self.m_allenvs[name] + except KeyError: + error('no such environment'+name) + return None + + def env(self, name='default'): + return self.env_of_name(name) + + def add_group(self, name=''): + Object.flush(all=0) + self.task_manager.add_group(name) + + def add_manual_dependency(self, path, value): + h = getattr(self, 'deps_man', {}) + node = self.m_curdirnode.find_source(path) + if not node: node = self.m_curdirnode.find_build(path, create=1) + + h[node] = value + self.deps_man = h + + def set_sig_cache(self, key, val): + self.m_sig_cache[key] = val + + def get_sig_cache(self, key): + try: + return self.m_sig_cache[key] + except KeyError: + s = Params.sig_nil + return [s, s, s, s, s] + + def launch_node(self): + try: + return self._launch_node + except AttributeError: + self._launch_node = self.m_root.find_dir(Params.g_cwd_launch) + return self._launch_node + + diff -Nru zyn-1+git.20100609/wafadmin/Common.py zyn-1+git.20100609+dfsg0/wafadmin/Common.py --- zyn-1+git.20100609/wafadmin/Common.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Common.py 2008-03-23 19:05:48.000000000 +0000 @@ -0,0 +1,182 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2005 (ita) + +"Important functions: install_files, install_as, symlink_as (destdir is taken into account)" + +import os, types, shutil, glob +import Params, Utils +from Params import error, fatal + +class InstallError(Exception): + pass + +def check_dir(dir): + #print "check dir ", dir + try: + os.stat(dir) + except OSError: + try: + os.makedirs(dir) + except OSError: + fatal("Cannot create folder " + dir) + +def do_install(src, tgt, chmod=0644): + if Params.g_commands['install']: + # check if the file is already there to avoid a copy + _do_install = 1 + if not Params.g_options.force: + try: + t1 = os.stat(tgt).st_mtime + t2 = os.stat(src).st_mtime + if t1 >= t2: _do_install = 0 + except OSError: + _do_install = 1 + + if _do_install: + srclbl = src + try: + srclbl = src.replace(Params.g_build.m_bldnode.abspath(None)+os.sep, '') + srclbl = src.replace(Params.g_build.m_srcnode.abspath(None)+os.sep, '') + except OSError: + pass + print "* installing %s as %s" % (srclbl, tgt) + + # followig is for shared libs and stale inodes + try: os.remove(tgt) + except OSError: pass + try: + shutil.copy2(src, tgt) + os.chmod(tgt, chmod) + except IOError: + try: + os.stat(src) + except IOError: + error('file %s does not exist' % str(src)) + fatal('Could not install the file %s' % str(tgt)) + elif Params.g_commands['uninstall']: + print "* uninstalling %s" % tgt + + Params.g_build.m_uninstall.append(tgt) + + try: os.remove(tgt) + except OSError: pass + +def path_install(var, subdir, env=None): + bld = Params.g_build + if not env: env=Params.g_build.m_allenvs['default'] + destpath = env[var] + if not destpath: + error("Installing: to set a destination folder use env['%s']" % (var)) + destpath = var + destdir = env.get_destdir() + if destdir: destpath = os.path.join(destdir, destpath.lstrip(os.sep)) + if subdir: destpath = os.path.join(destpath, subdir.lstrip(os.sep)) + + return destpath + +def install_files(var, subdir, files, env=None, chmod=0644): + if not Params.g_install: return + if not var: return + + bld = Params.g_build + + if not env: env = bld.m_allenvs['default'] + destpath = env[var] + + # the variable can be an empty string and the subdir an absolute path + if destpath is [] and subdir: return + + node = bld.m_curdirnode + + if type(files) is types.StringType: + if '*' in files: + gl = node.abspath()+os.sep+files + lst = glob.glob(gl) + else: + lst = files.split() + else: lst = files + + destdir = env.get_destdir() + if destdir: destpath = os.path.join(destdir, destpath.lstrip(os.sep)) + if subdir: destpath = os.path.join(destpath, subdir.lstrip(os.sep)) + + check_dir(destpath) + + # copy the files to the final destination + for filename in lst: + if not os.path.isabs(filename): + alst = Utils.split_path(filename) + filenode = node.find_build_lst(alst, create=1) + + file = filenode.abspath(env) + destfile = os.path.join(destpath, filenode.m_name) + else: + file = filename + alst = Utils.split_path(filename) + destfile = os.path.join(destpath, alst[-1]) + + do_install(file, destfile, chmod=chmod) + +def install_as(var, destfile, srcfile, env=None, chmod=0644): + if not Params.g_install: return + if var == 0: return + + bld = Params.g_build + if not env: env=Params.g_build.m_allenvs['default'] + node = bld.m_curdirnode + + tgt = env[var] + destdir = env.get_destdir() + if destdir: tgt = os.path.join(destdir, tgt.lstrip(os.sep)) + tgt = os.path.join(tgt, destfile.lstrip(os.sep)) + + dir, name = os.path.split(tgt) + check_dir(dir) + + # the source path + if not os.path.isabs(srcfile): + alst = Utils.split_path(srcfile) + filenode = node.find_build_lst(alst, create=1) + src = filenode.abspath(env) + else: + src = srcfile + + do_install(src, tgt, chmod=chmod) + +def symlink_as(var, src, dest, env=None): + if not Params.g_install: return + if var == 0: return + + bld = Params.g_build + if not env: env=Params.g_build.m_allenvs['default'] + node = bld.m_curdirnode + + tgt = env[var] + destdir = env.get_destdir() + if destdir: tgt = os.path.join(destdir, tgt.lstrip(os.sep)) + tgt = os.path.join(tgt, dest.lstrip(os.sep)) + + dir, name = os.path.split(tgt) + check_dir(dir) + + if Params.g_commands['install']: + try: + if not os.path.islink(tgt) or os.readlink(tgt) != src: + print "* symlink %s (-> %s)" % (tgt, src) + os.symlink(src, tgt) + return 0 + except OSError: + return 1 + elif Params.g_commands['uninstall']: + try: + print "* removing %s" % (tgt) + os.remove(tgt) + return 0 + except OSError: + return 1 + + diff -Nru zyn-1+git.20100609/wafadmin/Configure.py zyn-1+git.20100609+dfsg0/wafadmin/Configure.py --- zyn-1+git.20100609/wafadmin/Configure.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Configure.py 2008-03-25 19:28:28.000000000 +0000 @@ -0,0 +1,350 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2005-2008 (ita) + +""" +Configuration system + +A configuration instance is created when "waf configure" is called, it is used to: +* create data dictionaries (Environment instances) +* store the list of modules to import + +The old model (copied from Scons) was to store logic (mapping file extensions to functions) +along with the data. In Waf a way was found to separate that logic by adding an indirection +layer (storing the names in the Environment instances) + +In the new model, the logic is more object-oriented, and the user scripts provide the +logic. The data files (Environments) must contain configuration data only (flags, ..). + +Note: the c/c++ related code is in the module config_c +""" + +import os, types, imp, cPickle, sys, shlex, warnings +try: from hashlib import md5 +except ImportError: from md5 import md5 +import Action, Params, Environment, Runner, Build, Utils, Object +from Params import fatal, warning +from Constants import * + +TEST_OK = True + +class ConfigurationError(Exception): + pass + +g_maxlen = 40 +"""initial length of configuration messages""" + +g_debug = 0 +"""enable/disable debug""" + +g_stdincpath = ['/usr/include/', '/usr/local/include/'] +"""standard include paths""" + +g_stdlibpath = ['/usr/lib/', '/usr/local/lib/', '/lib'] +"""standard library search paths""" + + +##################### +## Helper functions + +def find_file(filename, path_list): + """find a file in a list of paths + @param filename: name of the file to search for + @param path_list: list of directories to search + @return: the first occurrence filename or '' if filename could not be found +""" + if type(path_list) is types.StringType: + lst = path_list.split() + else: + lst = path_list + for directory in lst: + if os.path.exists( os.path.join(directory, filename) ): + return directory + return '' + +def find_file_ext(filename, path_list): + """find a file in a list of paths using fnmatch + @param filename: name of the file to search for + @param path_list: list of directories to search + @return: the first occurrence filename or '' if filename could not be found +""" + import fnmatch + if type(path_list) is types.StringType: + lst = path_list.split() + else: + lst = path_list + for directory in lst: + for path, subdirs, files in os.walk(directory): + for name in files: + if fnmatch.fnmatch(name, filename): + return path + return '' + +def find_program_impl(env, filename, path_list=[], var=None): + """find a program in folders path_lst, and sets env[var] + @param env: environment + @param filename: name of the program to search for + @param path_list: list of directories to search for filename + @param var: environment value to be checked for in env or os.environ + @return: either the value that is referenced with [var] in env or os.environ + or the first occurrence filename or '' if filename could not be found +""" + try: path_list = path_list.split() + except AttributeError: pass + + if var: + if var in os.environ: env[var] = os.environ[var] + if env[var]: return env[var] + + if not path_list: path_list = os.environ['PATH'].split(os.pathsep) + + if Params.g_platform=='win32': + # TODO isnt fnmatch for this? + for y in [filename+x for x in '.exe,.com,.bat,.cmd'.split(',')]: + for directory in path_list: + x = os.path.join(directory, y) + if os.path.isfile(x): + if var: env[var] = x + return x + else: + for directory in path_list: + x = os.path.join(directory, filename) + if os.access(x, os.X_OK) and os.path.isfile(x): + if var: env[var] = x + return x + return '' + +class Configure(object): + def __init__(self, env=None, blddir='', srcdir=''): + + self.env = None + self.m_envname = '' + + self.m_blddir = blddir + self.m_srcdir = srcdir + + self.m_allenvs = {} + self.defines = {} + self.configheader = 'config.h' + self.cwd = os.getcwd() + + self.tools = [] # tools loaded in the configuration, and that will be loaded when building + + self.setenv('default') + + self.m_cache_table = {} + + self.lastprog = '' + + # load the cache + if Params.g_cache_global and not Params.g_options.nocache: + fic = os.path.join(Params.g_cache_global, Params.g_conf_name) + try: + file = open(fic, 'rb') + except (OSError, IOError): + pass + else: + try: + self.m_cache_table = cPickle.load(file) + finally: + file.close() + + self._a = 0 + self._b = 0 + self._c = 0 + self._quiet = 0 + + self.hash = 0 + self.files = [] + + def errormsg(self, msg): + Params.niceprint(msg, 'ERROR', 'Configuration') + + def fatal(self, msg): + raise ConfigurationError(msg) + + def check_tool(self, input, tooldir=None): + "load a waf tool" + tools = Utils.to_list(input) + if tooldir: tooldir = Utils.to_list(tooldir) + for tool in tools: + try: + file,name,desc = imp.find_module(tool, tooldir) + except ImportError, ex: + raise ConfigurationError("no tool named '%s' found (%s)" % (tool, str(ex))) + module = imp.load_module(tool, file, name, desc) + func = getattr(module, 'detect', None) + if func: func(self) + self.tools.append({'tool':tool, 'tooldir':tooldir}) + + def sub_config(self, dir): + "executes the configure function of a wscript module" + current = self.cwd + + self.cwd = os.path.join(self.cwd, dir) + cur = os.path.join(self.cwd, WSCRIPT_FILE) + + try: + mod = Utils.load_module(cur) + except IOError: + fatal("the wscript file %s was not found." % cur) + + if not hasattr(mod, 'configure'): + fatal('the module %s has no configure function; make sure such a function is defined' % cur) + + ret = mod.configure(self) + if Params.g_autoconfig: + self.hash = Params.hash_function_with_globals(self.hash, mod.configure) + self.files.append(os.path.abspath(cur)) + self.cwd = current + return ret + + def store(self, file=''): + "save the config results into the cache file" + if not os.path.isdir(Params.g_cachedir): + os.makedirs(Params.g_cachedir) + + file = open(os.path.join(Params.g_cachedir, 'build.config.py'), 'w') + file.write('version = %s\n' % HEXVERSION) + file.write('tools = %r\n' % self.tools) + file.close() + + if not self.m_allenvs: + fatal("nothing to store in Configure !") + for key in self.m_allenvs: + tmpenv = self.m_allenvs[key] + tmpenv.store(os.path.join(Params.g_cachedir, key+CACHE_SUFFIX)) + + def cleanup(self): + "when there is a cache directory store the config results (shutdown)" + if not Params.g_cache_global: return + + # not during the build + if not os.path.isdir(Params.g_cache_global): + os.makedirs(Params.g_cache_global) + + fic = os.path.join(Params.g_cache_global, Params.g_conf_name) + file = open(fic, 'wb') + try: + cPickle.dump(self.m_cache_table, file) + finally: + file.close() + + def set_env_name(self, name, env): + "add a new environment called name" + self.m_allenvs[name] = env + return env + + def retrieve(self, name, fromenv=None): + "retrieve an environment called name" + try: + env = self.m_allenvs[name] + except KeyError: + env = Environment.Environment() + self.m_allenvs[name] = env + else: + if fromenv: warning("The environment %s may have been configured already" % name) + return env + + def setenv(self, name): + "enable the environment called name" + self.env = self.retrieve(name) + self.envname = name + + def add_os_flags(self, var, dest=None): + if not dest: dest = var + # do not use 'get' to make certain the variable is not defined + try: self.env[dest] = os.environ[var] + except KeyError: pass + + def check_message(self,type,msg,state,option=''): + "print an checking message. This function is used by other checking functions" + sr = 'Checking for ' + type + ' ' + msg + global g_maxlen + g_maxlen = max(g_maxlen, len(sr)) + print "%s :" % sr.ljust(g_maxlen), + + p = Params.pprint + if state: p('GREEN', 'ok ' + option) + else: p('YELLOW', 'not found') + + def check_message_custom(self,type,msg,custom,option=''): + """print an checking message. This function is used by other checking functions""" + sr = 'Checking for ' + type + ' ' + msg + global g_maxlen + g_maxlen = max(g_maxlen, len(sr)) + print "%s :" % sr.ljust(g_maxlen), + Params.pprint('CYAN', custom) + + def hook(self, func): + "attach the function given as input as new method" + setattr(self.__class__, func.__name__, func) + + def mute_logging(self): + "mutes the output temporarily" + if Params.g_options.verbose: return + # store the settings + (self._a, self._b, self._c) = Params.get_trace() + self._quiet = Runner.g_quiet + # then mute + if not g_debug: + Params.set_trace(0, 0, 0) + Runner.g_quiet = 1 + + def restore_logging(self): + "see mute_logging" + if Params.g_options.verbose: return + # restore the settings + if not g_debug: + Params.set_trace(self._a, self._b, self._c) + Runner.g_quiet = self._quiet + + def find_program(self, program_name, path_list=[], var=None): + "wrapper provided for convenience" + ret = find_program_impl(self.env, program_name, path_list, var) + self.check_message('program', program_name, ret, ret) + return ret + + def check_pkg(self, modname, destvar='', vnum='', pkgpath='', pkgbin='', + pkgvars=[], pkgdefs={}, mandatory=False): + "wrapper provided for convenience" + pkgconf = self.create_pkgconfig_configurator() + + if not destvar: destvar = modname.upper() + + pkgconf.uselib = destvar + pkgconf.name = modname + pkgconf.version = vnum + if pkgpath: pkgconf.pkgpath = pkgpath + pkgconf.binary = pkgbin + pkgconf.variables = pkgvars + pkgconf.defines = pkgdefs + pkgconf.mandatory = mandatory + return pkgconf.run() + + def pkgconfig_fetch_variable(self,pkgname,variable,pkgpath='',pkgbin='',pkgversion=0,env=None): + if not env: env=self.env + + if not pkgbin: pkgbin='pkg-config' + if pkgpath: pkgpath='PKG_CONFIG_PATH=$PKG_CONFIG_PATH:'+pkgpath + pkgcom = '%s %s' % (pkgpath, pkgbin) + if pkgversion: + ret = os.popen("%s --atleast-version=%s %s" % (pkgcom, pkgversion, pkgname)).close() + self.conf.check_message('package %s >= %s' % (pkgname, pkgversion), '', not ret) + if ret: + return '' # error + else: + ret = os.popen("%s %s" % (pkgcom, pkgname)).close() + self.check_message('package %s ' % (pkgname), '', not ret) + if ret: + return '' # error + + return os.popen('%s --variable=%s %s' % (pkgcom, variable, pkgname)).read().strip() + +# do not touch +import config_c + + diff -Nru zyn-1+git.20100609/wafadmin/Constants.py zyn-1+git.20100609+dfsg0/wafadmin/Constants.py --- zyn-1+git.20100609/wafadmin/Constants.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Constants.py 2008-03-23 19:05:48.000000000 +0000 @@ -0,0 +1,27 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Yinon dot me gmail 2008 + +# maintainer the version number is updated from the top-level wscript file +HEXVERSION = 0x10303 +ABI = 2 + +CACHE_DIR = 'c4che' +CACHE_SUFFIX = '.cache.py' +DBFILE = '.wafpickle-%d' % ABI +WSCRIPT_FILE = 'wscript' +WSCRIPT_BUILD_FILE = 'wscript_build' +COMMON_INCLUDES = 'COMMON_INCLUDES' + +SRCDIR = 'srcdir' +BLDDIR = 'blddir' +APPNAME = 'APPNAME' +VERSION = 'VERSION' + +DEFINES = 'defines' +UNDEFINED = '#undefined#variable#for#defines#' + + diff -Nru zyn-1+git.20100609/wafadmin/DirWatch.py zyn-1+git.20100609+dfsg0/wafadmin/DirWatch.py --- zyn-1+git.20100609/wafadmin/DirWatch.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/DirWatch.py 2008-03-23 19:05:48.000000000 +0000 @@ -0,0 +1,190 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Matthias Jahn , 2006 + +"DirWatch chooses a supported backend (fam, gamin or fallback) it is mainly a wrapper script without own methods beside this" + +from Params import debug +import GaminAdaptor, FamAdaptor, FallbackAdaptor +import os + +class WatchObject: + def __init__( self, idxName, namePath, isDir, callBackThis, handleEvents ): + """watch object to handle a watch + @param idxName: unique name for ref + @param dirList: path to watch + @param isDir: directory True or False + @param callBackThis: is called if something in dirs in dirlist has events (handleEvents) callBackThis(idxName, changedFilePath) + @param handleEvents: events to handle possible are 'changed', 'deleted', 'created', 'exist' suspendDirWatch after a handled change + """ + self.__adaptor = None + self.__fr = None + self.__idxName = idxName + self.__name = namePath + self.__isDir = isDir + self.__callBackThis = callBackThis + self.__handleEvents = handleEvents + + def __del__( self ): + self.unwatch() + + def watch( self, adaptor ): + """start watching + @param adaptor: dirwatch adaptor for backend + """ + self.__adaptor = adaptor + if self.__fr != None: + self.unwatch() + if self.__isDir: + self.__fr = self.__adaptor.watch_directory( self.__name, self.__idxName ) + else: + self.__fr = self.__adaptor.watch_file( self.__name, self.__idxName ) + + def unwatch( self ): + """stop watching""" + if self.__fr: + self.__fr = self.__adaptor.stop_watch( self.__name ) + + def get_events( self ): + """returns all events to care""" + return self.__handleEvents + + def get_callback( self ): + """returns the callback methode""" + return self.__callBackThis + + def get_fullpath( self, fileName ): + """returns the full path dir + filename""" + return os.path.join( self.__name, fileName ) + + def __str__( self ): + if self.__isDir: + return 'DIR %s: ' % self.__name + else: + return 'FILE %s: ' % self.__name + +class DirectoryWatcher: + """DirWatch chooses a supported backend (fam, gamin or fallback) + it is mainly a wrapper script without own methods beside this + """ + def __init__( self ): + self.__adaptor = None + self.__watcher = {} + self.__loops = True + self.connect() + + def __del__ ( self ): + self.disconnect() + + def __raise_disconnected( self ): + raise( "Already disconnected" ) + + def disconnect( self ): + if self.__adaptor: + self.suspend_all_watch() + self.__adaptor = None + + def connect( self ): + if self.__adaptor: + self.disconnect() + if FamAdaptor.support: + debug( "using FamAdaptor" ) + self.__adaptor = FamAdaptor.FamAdaptor( self.__processDirEvents ) + if self.__adaptor == None: + raise "something is strange" + elif GaminAdaptor.support: + debug( "using GaminAdaptor" ) + self.__adaptor = GaminAdaptor.GaminAdaptor(self.__processDirEvents) + else: + debug( "using FallbackAdaptor" ) + self.__adaptor = FallbackAdaptor.FallbackAdaptor(self.__processDirEvents) + + def add_watch( self, idxName, callBackThis, dirList, handleEvents = ['changed', 'deleted', 'created'] ): + """add dirList to watch. + @param idxName: unique name for ref + @param callBackThis: is called if something in dirs in dirlist has events (handleEvents) callBackThis(idxName, changedFilePath) + @param dirList: list of dirs to watch + @param handleEvents: events to handle possible are 'changed', 'deleted', 'created', 'exist' suspendDirWatch after a handled change + """ + self.remove_watch( idxName ) + self.__watcher[idxName] = [] + for directory in dirList: + watchObject = WatchObject( idxName, os.path.abspath( directory ), 1, callBackThis, handleEvents ) + self.__watcher[idxName].append( watchObject ) + self.resume_watch( idxName ) + + def remove_watch( self, idxName ): + """remove DirWatch with name idxName""" + if self.__watcher.has_key( idxName ): + self.suspend_watch( idxName ) + del self.__watcher[idxName] + + def remove_all_watch( self ): + """remove all DirWatcher""" + self.__watcher = {} + + def suspend_watch( self, idxName ): + """suspend DirWatch with name idxName. No dir/filechanges will be reacted until resume""" + if self.__watcher.has_key( idxName ): + for watchObject in self.__watcher[idxName]: + watchObject.unwatch() + + def suspend_all_watch( self ): + """suspend all DirWatcher ... they could be resumed with resume_all_watch""" + for idxName in self.__watcher.keys(): + self.suspend_watch( idxName ) + + def resume_watch( self, idxName ): + """resume a DirWatch that was supended with suspendDirWatch or suspendAllDirWatch""" + for watchObject in self.__watcher[idxName]: + watchObject.watch( self.__adaptor ) + + def resume_all_watch( self ): + """ resume all DirWatcher""" + for idxName in self.__watcher.keys(): + self.resume_watch( idxName ) + + def __processDirEvents( self, pathName, event, idxName ): + if event in self.__watcher[idxName][0].get_events(): + #self.disconnect() + self.suspend_watch(idxName) + __watcher = self.__watcher[idxName][0] + __watcher.get_callback()( idxName, __watcher.get_fullpath( pathName ), event ) + #self.connect() + self.resume_watch( idxName ) + + def request_end_loop( self ): + """sets a flag that stops the loop. it do not stop the loop directly!""" + self.__loops = False + + def loop( self ): + """wait for dir events and start handling of them""" + try: + self.__loops = True + while ( self.__loops ) and ( self.__adaptor != None ) : + self.__adaptor.wait_for_event() + while self.__adaptor.event_pending(): + self.__adaptor.handle_events() + if not self.__loops: + break + except KeyboardInterrupt: + self.request_end_loop() + +# quick test # +class Test: + def __init__( self ): + self.fam_test = DirectoryWatcher() + self.fam_test.add_watch( "tmp Test", self.thisIsCalledBack, ["/tmp"] ) + self.fam_test.loop() +# self.fam_test.loop() + + def thisIsCalledBack( self, idxName, pathName, event ): + print "idxName=%s, Path=%s, Event=%s " % ( idxName, pathName, event ) + self.fam_test.resume_watch( idxName ) + +if __name__ == "__main__": + Test() + diff -Nru zyn-1+git.20100609/wafadmin/Environment.py zyn-1+git.20100609+dfsg0/wafadmin/Environment.py --- zyn-1+git.20100609/wafadmin/Environment.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Environment.py 2008-03-23 19:05:48.000000000 +0000 @@ -0,0 +1,180 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2005 (ita) + +"Environment representation" + +import os,types, copy, re +import Params +from Params import debug, warning +re_imp = re.compile('^(#)*?([^#=]*?)\ =\ (.*?)$', re.M) + +g_cache_max = {} + +g_idx = 0 +class Environment(object): + """A safe-to-use dictionary, but do not attach functions to it please (break cPickle) + An environment instance can be stored into a file and loaded easily + """ + def __init__(self): + global g_idx + self.m_idx = g_idx + g_idx += 1 + self.m_table={} + #self.m_parent = None <- set only if necessary + + # set the prefix once and for everybody on creation (configuration) + self.m_table['PREFIX'] = Params.g_options.prefix + + def __contains__(self, key): + if key in self.m_table: return True + try: return self.m_parent.__contains__(key) + except AttributeError: return False # m_parent may not exist + + def set_variant(self, name): + self.m_table['_VARIANT_'] = name + + def variant(self): + env = self + while 1: + try: + return env.m_table['_VARIANT_'] + except KeyError: + try: env = env.m_parent + except AttributeError: return 'default' + + def copy(self): + newenv = Environment() + newenv.m_parent = self + return newenv + + def __str__(self): + return "environment table\n"+str(self.m_table) + + def __getitem__(self, key): + try: + return self.m_table[key] + except KeyError: + try: return self.m_parent[key] + except: return [] + + def __setitem__(self, key, value): + self.m_table[key] = value + + def get_flat(self, key): + s = self[key] + if not s: return '' + elif isinstance(s, list): return ' '.join(s) + else: return s + + def _get_list_value_for_modification(self, key): + """Gets a value that must be a list for further modification. The + list may be modified inplace and there is no need to + "self.m_table[var] = value" afterwards. + """ + try: + value = self.m_table[key] + except KeyError: + try: value = self.m_parent[key] + except AttributeError: value = [] + if isinstance(value, list): + value = copy.copy(value) + else: + value = [value] + self.m_table[key] = value + return value + else: + if isinstance(value, list): + return value # no need to copy the list, it is not borrowed <- TODO ?? + else: + value = [value] + self.m_table[key] = value + return value + + def append_value(self, var, value): + current_value = self._get_list_value_for_modification(var) + + if isinstance(value, list): + current_value.extend(value) + else: + current_value.append(value) + + def prepend_value(self, var, value): + current_value = self._get_list_value_for_modification(var) + + if isinstance(value, list): + current_value = value + current_value + # a new list: update the dictionary entry + self.m_table[var] = current_value + else: + current_value.insert(0, value) + + # prepend unique would be ambiguous + def append_unique(self, var, value): + current_value = self._get_list_value_for_modification(var) + + if isinstance(value, list): + for value_item in value: + if value_item not in current_value: + current_value.append(value_item) + else: + if value not in current_value: + current_value.append(value) + + def store(self, filename): + "Write the variables into a file" + file = open(filename, 'w') + + # compute a merged table + table_list = [] + env = self + while 1: + table_list.insert(0, env.m_table) + try: env = env.m_parent + except AttributeError: break + merged_table = dict() + for table in table_list: + merged_table.update(table) + + keys = merged_table.keys() + keys.sort() + for k in keys: file.write('%s = %r\n' % (k, merged_table[k])) + file.close() + + def load(self, filename): + "Retrieve the variables from a file" + tbl = self.m_table + file = open(filename, 'r') + code = file.read() + file.close() + for m in re_imp.finditer(code): + g = m.group + tbl[g(2)] = eval(g(3)) + debug(self.m_table, 'env') + + def get_destdir(self): + "return the destdir, useful for installing" + if self.__getitem__('NOINSTALL'): return '' + return Params.g_options.destdir + + def sign_vars(env, vars_list): + " ['CXX', ..] -> [env['CXX'], ..]" + + # ccroot objects use the same environment for building the .o at once + # the same environment and the same variables are used + s = str([env.m_idx]+vars_list) + try: return g_cache_max[s] + except KeyError: pass + + lst = [env.get_flat(a) for a in vars_list] + ret = Params.h_list(lst) + if Params.g_zones: debug("%s %s" % (Params.view_sig(ret), str(lst)), 'envhash') + + # next time + g_cache_max[s] = ret + return ret + + diff -Nru zyn-1+git.20100609/wafadmin/FallbackAdaptor.py zyn-1+git.20100609+dfsg0/wafadmin/FallbackAdaptor.py --- zyn-1+git.20100609/wafadmin/FallbackAdaptor.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/FallbackAdaptor.py 2008-03-23 19:05:48.000000000 +0000 @@ -0,0 +1,152 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Matthias Jahn 2006 + +""" +Fallback WatchMonitor should work anywhere ..;-) +this do not depends on gamin or fam instead it polls for changes +it works at least under linux ... windows or other *nix are untested +""" + +import os, time + +support = True + +class Fallback: + class Helper: + def __init__( self, callBack, userdata ): + self.currentFiles = {} + self.oldFiles = {} + self.__firstRun = True + self.callBack = callBack + self.userdata = userdata + + def isFirstRun( self ): + if self.__firstRun: + self.__firstRun = False + return True + else: + return False + + def __init__( self ): + self.__dirs = {} + #event lists for changed and deleted + self.__changeLog = {} + + def __traversal( self, dirName ): + """Traversal function for directories +Basic principle: all_files is a dictionary mapping paths to +modification times. We repeatedly crawl through the directory +tree rooted at 'path', doing a stat() on each file and comparing +the modification time. +""" + files = os.listdir( dirName ) + firstRun = self.__dirs[dirName].isFirstRun() + + for filename in files: + path = os.path.join( dirName, filename ) + try: + fileStat = os.stat( path ) + except os.error: + # If a file has been deleted since the lsdir + # scanning the directory and now, we'll get an + # os.error here. Just ignore it -- we'll report + # the deletion on the next pass through the main loop. + continue + modifyTime = self.__dirs[dirName].oldFiles.get( path ) + if modifyTime is not None: + # Record this file as having been seen + del self.__dirs[dirName].oldFiles[path] + # File's mtime has been changed since we last looked at it. + if fileStat.st_mtime > modifyTime: + self.__changeLog[path] = 'changed' + else: + if firstRun: + self.__changeLog[path] = 'exists' + else: + # No recorded modification time, so it must be + # a brand new file + self.__changeLog[path] = 'created' + # Record current mtime of file. + self.__dirs[dirName].currentFiles[path] = fileStat.st_mtime + + def watch_directory( self, namePath, callBack, idxName ): + self.__dirs[namePath] = self.Helper( callBack, idxName ) + return self + + def unwatch_directory( self, namePath ): + if self.__dirs.get( namePath ): + del self.__dirs[namePath] + + def event_pending( self ): + for dirName in self.__dirs.keys(): + self.__dirs[dirName].oldFiles = self.__dirs[dirName].currentFiles.copy() + self.__dirs[dirName].currentFiles = {} + self.__traversal( dirName ) + for deletedFile in self.__dirs[dirName].oldFiles.keys(): + self.__changeLog[deletedFile] = 'deleted' + del self.__dirs[dirName].oldFiles[deletedFile] + return len( self.__changeLog ) + + def handle_events( self ): + pathName = self.__changeLog.keys()[0] + event = self.__changeLog[pathName] + dirName = os.path.dirname( pathName ) + self.__dirs[dirName].callBack( pathName, event, self.__dirs[dirName].userdata ) + del self.__changeLog[pathName] + +class FallbackAdaptor: + def __init__( self, eventHandler ): + self.__fallback = Fallback() + self.__eventHandler = eventHandler # callBack function + self.__watchHandler = {} # {name : famId} + + def __del__( self ): + if self.__fallback: + for handle in self.__watchHandler.keys(): + self.stop_watch( handle ) + self.__fallback = None + + def __check_fallback(self): + if self.__fallback == None: + raise "fallback not init" + + def watch_directory( self, name, idxName ): + self.__check_fallback() + if self.__watchHandler.has_key( name ): + raise "dir allready watched" + # set famId + self.__watchHandler[name] = self.__fallback.watch_directory( name, self.__eventHandler, idxName ) + return(self.__watchHandler[name]) + + def watch_file( self, name, idxName ): + self.__check_fallback() + if self.__watchHandler.has_key( name ): + raise "file allready watched" + # set famId + self.__watchHandler[name] = self.__fallback.watch_directory( name, self.__eventHandler, idxName ) + return(self.__watchHandler[name]) + + def stop_watch( self, name ): + self.__check_fallback() + if self.__watchHandler.has_key( name ): + self.__fallback.unwatch_directory(name) + del self.__watchHandler[name] + return None + + def wait_for_event( self ): + self.__check_fallback() + time.sleep( 1 ) + + def event_pending( self ): + self.__check_fallback() + return self.__fallback.event_pending() + + def handle_events( self ): + self.__check_fallback() + self.__fallback.handle_events() + + diff -Nru zyn-1+git.20100609/wafadmin/FamAdaptor.py zyn-1+git.20100609+dfsg0/wafadmin/FamAdaptor.py --- zyn-1+git.20100609/wafadmin/FamAdaptor.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/FamAdaptor.py 2008-03-23 19:05:48.000000000 +0000 @@ -0,0 +1,83 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Matthias Jahn 2006 + +"""Fam WatchMonitor depends on python-fam ... it works with fam or gamin demon""" + +import select, errno +try: + import _fam +except ImportError: + support = False +else: + # check if fam runs and accepts connections + test = _fam.open() + test.close() + test = None + support = True + +class FamAdaptor: + """fam helper class for use with DirWatcher""" + def __init__( self, eventHandler ): + """ creates the fam adaptor class + @param eventHandler: callback method for event handling""" + self.__fam = _fam.open() + self.__eventHandler = eventHandler # callBack function + self.__watchHandler = {} # {name : famId} + + def __del__( self ): + if self.__fam: + for handle in self.__watchHandler.keys(): + self.stop_watch( handle ) + self.__fam.close() + + def __check_fam(self): + if self.__fam == None: + raise "fam not init" + + def watch_directory( self, name, idxName ): + self.__check_fam() + if self.__watchHandler.has_key( name ): + raise "dir allready watched" + # set famId + self.__watchHandler[name] = self.__fam.monitorDirectory( name, idxName ) + return(self.__watchHandler[name]) + + def watch_file( self, name, idxName ): + self.__check_fam() + if self.__watchHandler.has_key( name ): + raise "file allready watched" + # set famId + self.__watchHandler[name] = self.__fam.monitorFile( name, idxName ) + return(self.__watchHandler[name]) + + def stop_watch( self, name ): + self.__check_fam() + if self.__watchHandler.has_key( name ): + self.__watchHandler[name].cancelMonitor() + del self.__watchHandler[name] + return None + + def wait_for_event( self ): + self.__check_fam() + try: + select.select( [self.__fam], [], [] ) + except select.error, er: + errnumber, strerr = er + if errnumber != errno.EINTR: + raise strerr + + def event_pending( self ): + self.__check_fam() + return self.__fam.pending() + + def handle_events( self ): + self.__check_fam() + fe = self.__fam.nextEvent() + #pathName, event, idxName + self.__eventHandler(fe.filename, fe.code2str(), fe.userData) + + diff -Nru zyn-1+git.20100609/wafadmin/GaminAdaptor.py zyn-1+git.20100609+dfsg0/wafadmin/GaminAdaptor.py --- zyn-1+git.20100609/wafadmin/GaminAdaptor.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/GaminAdaptor.py 2008-03-23 19:05:48.000000000 +0000 @@ -0,0 +1,107 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Oscar Blumberg 2006 (nael) +# Matthias Jahn + +"""Depends on python gamin and on gamin demon""" + +import select, errno +try: + import gamin +except ImportError: + support = False +else: + # check if gamin runs and accepts connections + test = gamin.WatchMonitor() + test.disconnect() + test = None + support = True + +class GaminAdaptor: + """gamin helper class for use with DirWatcher""" + def __init__( self, eventHandler ): + """ creates the gamin wrapper + @param eventHandler: callback method for event handling""" + self.__gamin = gamin.WatchMonitor() + self.__eventHandler = eventHandler # callBack function + self.__watchHandler = {} # {name : famId} + + def __del__( self ): + """clean remove""" + if self.__gamin: + for handle in self.__watchHandler.keys(): + self.stop_watch( handle ) + self.__gamin.disconnect() + self.__gamin = None + + def __check_gamin(self): + """is gamin connected""" + if self.__gamin == None: + raise "gamin not init" + + def __code2str( self, event ): + """convert event numbers to string""" + gaminCodes = { + 1:"changed", + 2:"deleted", + 3:"StartExecuting", + 4:"StopExecuting", + 5:"created", + 6:"moved", + 7:"acknowledge", + 8:"exists", + 9:"endExist" + } + try: + return gaminCodes[event] + except KeyError: + return "unknown" + + def __eventhandler_helper(self, pathName, event, idxName): + """local eventhandler helps to convert event numbers to string""" + self.__eventHandler(pathName, self.__code2str(event), idxName) + + def watch_directory( self, name, idxName ): + self.__check_gamin() + if self.__watchHandler.has_key( name ): + raise "dir allready watched" + # set gaminId + self.__watchHandler[name] = self.__gamin.watch_directory( name, self.__eventhandler_helper, idxName ) + return(self.__watchHandler[name]) + + def watch_file( self, name, idxName ): + self.__check_gamin() + if self.__watchHandler.has_key( name ): + raise "file allready watched" + # set famId + self.__watchHandler[name] = self.__gamin.watch_directory( name, self.__eventhandler_helper, idxName ) + return(self.__watchHandler[name]) + + def stop_watch( self, name ): + self.__check_gamin() + if self.__watchHandler.has_key( name ): + self.__gamin.stop_watch(name) + del self.__watchHandler[name] + return None + + def wait_for_event( self ): + self.__check_gamin() + try: + select.select([self.__gamin.get_fd()], [], []) + except select.error, er: + errnumber, strerr = er + if errnumber != errno.EINTR: + raise strerr + + def event_pending( self ): + self.__check_gamin() + return self.__gamin.event_pending() + + def handle_events( self ): + self.__check_gamin() + self.__gamin.handle_events() + + diff -Nru zyn-1+git.20100609/wafadmin/__init__.py zyn-1+git.20100609+dfsg0/wafadmin/__init__.py --- zyn-1+git.20100609/wafadmin/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/__init__.py 2008-03-23 19:05:48.000000000 +0000 @@ -0,0 +1,7 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2005 (ita) + diff -Nru zyn-1+git.20100609/wafadmin/Node.py zyn-1+git.20100609+dfsg0/wafadmin/Node.py --- zyn-1+git.20100609/wafadmin/Node.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Node.py 2008-03-23 19:05:48.000000000 +0000 @@ -0,0 +1,502 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2005 (ita) + +""" +Node: filesystem structure, contains lists of nodes +self.m_dirs : sub-folders +self.m_files : files existing in the src dir +self.m_build : nodes produced in the build dirs + +A folder is represented by exactly one node + +IMPORTANT: +Some would-be class properties are stored in Build: nodes to depend on, signature, flags, .. +In fact, unused class members increase the .wafpickle file size sensibly with lots of objects +eg: the m_tstamp is used for every node, while the signature is computed only for build files + +the build is launched from the top of the build dir (for example, in _build_/) +""" + +import os +import Params, Utils +from Params import debug, error, fatal + +class Node(object): + def __init__(self, name, parent): + self.m_name = name + self.m_parent = parent + self.m_cached_path = "" + + self.hash_value = None + + # Lookup dictionaries for O(1) access + self.m_dirs_lookup = {} + self.m_files_lookup = {} + self.m_build_lookup = {} + + # The checks below could be disabled for speed, if necessary + # TODO check for . .. / \ in name + + # Node name must contain only one level + if Utils.split_path(name)[0] != name: + fatal('name forbidden '+name) + + if parent: + if parent.get_file(name): + fatal('node %s exists in the parent files %s already' % (name, str(parent))) + + if parent.get_build(name): + fatal('node %s exists in the parent build %s already' % (name, str(parent))) + + def __str__(self): + if self.m_name in self.m_parent.m_build_lookup: isbld = "bld" + elif self.m_name in self.m_parent.m_dirs_lookup: isbld = "dir" + else: isbld = "src" + return "%s://%s" % (isbld, self.abspath()) + + def __repr__(self): + if self.m_name in self.m_parent.m_build_lookup: isbld = "bld" + elif self.m_name in self.m_parent.m_dirs_lookup: isbld = "dir" + else: isbld = "src" + return "%s://%s" % (isbld, self.abspath()) + + def __eq__(self, other): + # avoid collisions by looking at the parents + if not self.m_parent: + if other.m_parent: + return 0 + elif self.m_parent.hash_value != other.m_parent.hash_value: + return 0 + return self.m_name == other.m_name + + def __ne__(self, other): + return not self.__eq__(other) + + def __hash__(self): + 'hash value based on the abs path' + if not self.hash_value: + cur = self + lst = [] + while cur: + lst.append(cur.m_name) + cur = cur.m_parent + if lst[-1] == '': lst = lst[:-1] + if lst[0] =='/': lst = lst[1:] + lst.reverse() + val = os.path.join(*lst) + debug("[%s]" % val, 'node') + self.hash_value = hash(val) + return self.hash_value + + # TODO deprecated, remove this function + def equals(self, node): + return self.hash_value == node.hash_value + + def dirs(self): + return self.m_dirs_lookup.values() + + def get_dir(self, name, default=None): + return self.m_dirs_lookup.get(name, default) + + def append_dir(self, dir): + self.m_dirs_lookup[dir.m_name] = dir + + def files(self): + return self.m_files_lookup.values() + + def get_file(self, name, default=None): + return self.m_files_lookup.get(name, default) + + def append_file(self, dir): + self.m_files_lookup[dir.m_name] = dir + + def get_build(self, name, default=None): + return self.m_build_lookup.get(name, default) + + # for the build variants, the same nodes are used to save memory + # the timestamps/signatures are accessed using the following methods + + def get_tstamp_variant(self, variant): + vars = Params.g_build.m_tstamp_variants[variant] + try: return vars[variant] + except KeyError: return None + + def set_tstamp_variant(self, variant, value): + Params.g_build.m_tstamp_variants[variant][self] = value + + def get_tstamp_node(self): + try: return Params.g_build.m_tstamp_variants[0][self] + except KeyError: return None + + def set_tstamp_node(self, value): + Params.g_build.m_tstamp_variants[0][self] = value + + ## ===== BEGIN find methods ===== ## + + def find_build(self, path, create=0): + #print "find build", path + lst = Utils.split_path(path) + return self.find_build_lst(lst, create) + + def find_build_lst(self, lst, create=0): + "search a source or a build node in the filesystem, rescan intermediate folders, create if necessary" + rescan = Params.g_build.rescan + current = self + while lst: + rescan(current) + name = lst.pop(0) + prev = current + + if name == '.': + continue + elif name == '..': + current = current.m_parent + continue + if lst: + current = prev.m_dirs_lookup.get(name, None) + if not current and create: + current = Node(name, prev) + prev.m_dirs_lookup[name] = current + else: + current = prev.m_build_lookup.get(name, None) + # next line for finding source files too + if not current: current = prev.m_files_lookup.get(name, None) + # TODO do not use this for finding folders + if not current: + current = Node(name, prev) + # last item is the build file (rescan would have found the source) + prev.m_build_lookup[name] = current + return current + + def find_source(self, path, create=1): + lst = Utils.split_path(path) + return self.find_source_lst(lst, create) + + def find_source_lst(self, lst, create=1): + "search a source in the filesystem, rescan intermediate folders, create intermediate folders if necessary" + rescan = Params.g_build.rescan + current = self + while lst: + rescan(current) + name = lst.pop(0) + prev = current + + if name == '.': + continue + elif name == '..': + current = current.m_parent + continue + if lst: + current = prev.m_dirs_lookup.get(name, None) + if not current and create: + # create a directory + current = Node(name, prev) + prev.m_dirs_lookup[name] = current + else: + current = prev.m_files_lookup.get(name, None) + # try hard to find something + if not current: current = prev.m_dirs_lookup.get(name, None) + if not current: current = prev.m_build_lookup.get(name, None) + if not current: return None + return current + + def find_raw(self, path): + lst = Utils.split_path(path) + return self.find_raw_lst(lst) + + def find_raw_lst(self, lst): + "just find a node in the tree, do not rescan folders" + current = self + while lst: + name = lst.pop(0) + prev = current + if name == '.': + continue + elif name == '..': + current = current.m_parent + continue + current = prev.m_dirs_lookup[name] + if not current: current=prev.m_files_lookup[name] + if not current: current=prev.m_build_lookup[name] + if not current: return None + return current + + def ensure_node_from_lst(self, plst): + curnode = self + for dirname in plst: + if not dirname: continue + if dirname == '.': continue + if dirname == '..': + curnode = curnode.m_parent + continue + #found=None + found = curnode.get_dir(dirname, None) + #for cand in curnode.m_dirs: + # if cand.m_name == dirname: + # found = cand + # break + if not found: + found = Node(dirname, curnode) + curnode.append_dir(found) + curnode = found + return curnode + + def find_dir(self, path): + lst = Utils.split_path(path) + return self.find_dir_lst(lst) + + def find_dir_lst(self, lst): + "search a folder in the filesystem, do not scan, create if necessary" + current = self + while lst: + name = lst.pop(0) + prev = current + + if name == '.': + continue + elif name == '..': + current = current.m_parent + else: + current = prev.m_dirs_lookup.get(name, None) + if not current: + current = Node(name, prev) + # create a directory + prev.m_dirs_lookup[name] = current + return current + + + ## ===== END find methods ===== ## + + + ## ===== BEGIN relpath-related methods ===== ## + + # same as pathlist3, but do not append './' at the beginning + def pathlist4(self, node): + #print "pathlist4 called" + if self == node: return [] + if self.m_parent == node: return [self.m_name] + return [self.m_name, os.sep] + self.m_parent.pathlist4(node) + + def relpath(self, parent): + "path relative to a direct parent, as string" + lst = [] + p = self + h1 = parent.height() + h2 = p.height() + while h2 > h1: + h2 -= 1 + lst.append(p.m_name) + p = p.m_parent + if lst: + lst.reverse() + ret = os.path.join(*lst) + else: + ret = '' + return ret + + # find a common ancestor for two nodes - for the shortest path in hierarchy + def find_ancestor(self, node): + dist = self.height() - node.height() + if dist < 0: return node.find_ancestor(self) + # now the real code + cand = self + while dist > 0: + cand = cand.m_parent + dist -= 1 + if cand == node: return cand + cursor = node + while cand.m_parent: + cand = cand.m_parent + cursor = cursor.m_parent + if cand == cursor: return cand + + # prints the amount of "../" between two nodes + def invrelpath(self, parent): + lst = [] + cand = self + while not cand == parent: + cand = cand.m_parent + lst += ['..', os.sep] + return lst + + # TODO: do this in a single function (this one uses invrelpath, find_ancestor and pathlist4) + # string representing a relative path between two nodes, we are at relative_to + def relpath_gen(self, going_to): + if self == going_to: return '.' + if going_to.m_parent == self: return '..' + + # up_path is '../../../' and down_path is 'dir/subdir/subdir/file' + ancestor = self.find_ancestor(going_to) + up_path = going_to.invrelpath(ancestor) + down_path = self.pathlist4(ancestor) + down_path.reverse() + return "".join(up_path + down_path) + + def nice_path(self, env=None): + "printed in the console, open files easily from the launch directory" + tree = Params.g_build + ln = tree.launch_node() + name = self.m_name + x = self.m_parent.get_file(name) + if x: return self.relative_path(ln) + else: return os.path.join(tree.m_bldnode.relative_path(ln), env.variant(), self.relative_path(tree.m_srcnode)) + + def relative_path(self, folder): + "relative path between a node and a directory node" + hh1 = h1 = self.height() + hh2 = h2 = folder.height() + p1 = self + p2 = folder + while h1 > h2: + p1 = p1.m_parent + h1 -= 1 + while h2 > h1: + p2 = p2.m_parent + h2 -= 1 + + # now we have two nodes of the same height + ancestor = None + if p1.m_name == p2.m_name: + ancestor = p1 + while p1.m_parent: + p1 = p1.m_parent + p2 = p2.m_parent + if p1.m_name != p2.m_name: + ancestor = None + elif not ancestor: + ancestor = p1 + + anh = ancestor.height() + n1 = hh1-anh + n2 = hh2-anh + + lst = [] + tmp = self + while n1: + n1 -= 1 + lst.append(tmp.m_name) + tmp = tmp.m_parent + + lst.reverse() + up_path = os.sep.join(lst) + down_path = (".."+os.sep) * n2 + + return "".join(down_path + up_path) + + ## ===== END relpath-related methods ===== ## + + def debug(self): + print "========= debug node =============" + print "dirs are ", self.dirs() + print "files are", self.files() + print "======= end debug node ===========" + + def is_child_of(self, node): + "does this node belong to the subtree node" + p = self + diff = self.height() - node.height() + while diff > 0: + diff -= 1 + p = p.m_parent + return p == node + + def variant(self, env): + "variant, or output directory for this node, a source has for variant 0" + if not env: return 0 + i = self.m_parent.get_file(self.m_name) + if i: return 0 + return env.variant() + + def size_subtree(self): + "for debugging, returns the amount of subnodes" + l_size = 1 + for i in self.dirs(): l_size += i.size_subtree() + l_size += len(self.files()) + return l_size + + def height(self): + "amount of parents" + # README a cache can be added here if necessary + d = self + val = 0 + while d.m_parent: + d = d.m_parent + val += 1 + return val + + # helpers for building things + + def abspath(self, env=None): + "absolute path" + variant = self.variant(env) + try: + ret = Params.g_build.m_abspath_cache[variant][self] + return ret + except KeyError: + if not variant: + cur = self + lst = [] + while cur: + lst.append(cur.m_name) + cur = cur.m_parent + lst.reverse() + val = os.path.join(*lst) + else: + val = os.path.join(Params.g_build.m_bldnode.abspath(), env.variant(), + self.relpath(Params.g_build.m_srcnode)) + Params.g_build.m_abspath_cache[variant][self]=val + return val + + def change_ext(self, ext): + "node of the same path, but with a different extension" + name = self.m_name + k = name.rfind('.') + if k >= 0: + newname = name[:k] + ext + else: + newname = name + ext + + p = self.m_parent + n = p.m_files_lookup.get(newname, None) + if not n: n = p.m_build_lookup.get(newname, None) + if n: return n + + newnode = Node(newname, p) + p.m_build_lookup[newnode.m_name] = newnode + + return newnode + + def bld_dir(self, env): + "build path without the file name" + return self.m_parent.bldpath(env) + + def bldbase(self, env): + "build path without the extension: src/dir/foo(.cpp)" + l = len(self.m_name) + n = self.m_name + while l > 0: + l -= 1 + if n[l] == '.': break + s = n[:l] + return os.path.join(self.bld_dir(env), s) + + def bldpath(self, env=None): + "path seen from the build dir default/src/foo.cpp" + x = self.m_parent.get_file(self.m_name) + + if x: return self.relpath_gen(Params.g_build.m_bldnode) + if self.relpath(Params.g_build.m_srcnode) is not '': + return os.path.join(env.variant(), self.relpath(Params.g_build.m_srcnode)) + return env.variant() + + def srcpath(self, env): + "path in the srcdir from the build dir ../src/foo.cpp" + x = self.m_parent.get_build(self.m_name) + if x: return self.bldpath(env) + return self.relpath_gen(Params.g_build.m_bldnode) + + diff -Nru zyn-1+git.20100609/wafadmin/Object.py zyn-1+git.20100609+dfsg0/wafadmin/Object.py --- zyn-1+git.20100609/wafadmin/Object.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Object.py 2008-03-25 21:02:39.000000000 +0000 @@ -0,0 +1,516 @@ +#! /usr/bin/env python +# encoding: utf-8 +import sys +if sys.hexversion < 0x020400f0: from sets import Set as set +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2005-2008 (ita) + +""" +The class task_gen encapsulates the creation of task objects (low-level code) +The instances can have various parameters, but the creation of task nodes +is delayed. To achieve this, various methods are called from the method "apply" + +The class task_gen contains lots of methods, and a configuration table: +* the methods to call (self.meths) can be specified dynamically (removing, adding, ..) +* the order of the methods (self.prec or by default task_gen.prec) is configurable +* new methods can be inserted dynamically without pasting old code + +Additionally, task_gen provides the method apply_core +* file extensions are mapped to methods: def meth(self, name_or_node) +* if a mapping is not found in self.mappings, it is searched in task_gen.mappings +* when called, the functions may modify self.allnodes to re-add source to process +* the mappings can map an extension or a filename (see the code below) + +WARNING 1 subclasses must reimplement the clone method to avoid problems with 'deepcopy' +WARNING 2 find a new name for this file (naming it 'Object' was never a good idea) +""" + +import os, types, traceback, sys, copy +import Params, Task, Common, Node, Utils, Action +from Params import debug, error, fatal + +typos = { +'sources':'source', +'targets':'target', +'include':'includes', +'define':'defines', +'importpath':'importpaths', +'install_var':'inst_var', +'install_subdir':'inst_dir', +} + +g_allobjs = [] +"contains all objects, provided they are created (not in distclean or in dist)" +#TODO part of the refactoring to eliminate the static stuff (Utils.reset) + +g_name_to_obj = {} + +def name_to_obj(name): + global g_name_to_obj + if not g_name_to_obj: + for x in g_allobjs: + if x.name: + g_name_to_obj[x.name] = x + elif not x.target in g_name_to_obj.keys(): + g_name_to_obj[x.target] = x + return g_name_to_obj.get(name, None) + +def flush(all=1): + "object instances under the launch directory create the tasks now" + global g_allobjs + global g_name_to_obj + + # force the initialization of the mapping name->object in flush + # name_to_obj can be used in userland scripts, in that case beware of incomplete mapping + g_name_to_obj = {} + name_to_obj(None) + + tree = Params.g_build + debug("delayed operation Object.flush() called", 'object') + + # post only objects below a particular folder (recursive make behaviour) + launch_dir_node = tree.m_root.find_dir(Params.g_cwd_launch) + if launch_dir_node.is_child_of(tree.m_bldnode): + launch_dir_node = tree.m_srcnode + if not launch_dir_node.is_child_of(tree.m_srcnode): + launch_dir_node = tree.m_srcnode + + if Params.g_options.compile_targets: + debug('posting objects listed in compile_targets', 'object') + + # ensure the target names exist, fail before any post() + targets_objects = {} + for target_name in Params.g_options.compile_targets.split(','): + # trim target_name (handle cases when the user added spaces to targets) + target_name = target_name.strip() + targets_objects[target_name] = name_to_obj(target_name) + if all and not targets_objects[target_name]: fatal("target '%s' does not exist" % target_name) + + for target_obj in targets_objects.values(): + if target_obj and not target_obj.m_posted: + target_obj.post() + else: + debug('posting objects (normal)', 'object') + for obj in g_allobjs: + if launch_dir_node and not obj.path.is_child_of(launch_dir_node): continue + if not obj.m_posted: obj.post() + +class register_obj(type): + """no decorators for classes, so we use a metaclass + we store into task_gen.classes the classes that inherit task_gen + and whose names end in 'obj' + """ + def __init__(cls, name, bases, dict): + super(register_obj, cls).__init__(name, bases, dict) + name = cls.__name__ + if name != 'task_gen' and not name.endswith('_abstract'): + task_gen.classes[name.replace('_taskgen', '')] = cls + +class task_gen(object): + """ + Most methods are of the form 'def meth(self):' without any parameters + there are many of them, and they do many different things: + * task creation + * task results installation + * environment modification + * attribute addition/removal + + The inheritance approach is complicated + * mixing several languages at once + * subclassing is needed even for small changes + * inserting new methods is complicated + + This new class uses a configuration table: + * adding new methods easily + * obtaining the order in which to call the methods + * postponing the method calls (post() -> apply) + + Additionally, a 'traits' static attribute is provided: + * this list contains methods + * the methods can remove or add methods from self.meths + Example1: the attribute 'staticlib' is set on an instance + a method set in the list of traits is executed when the + instance is posted, it finds that flag and adds another method for execution + Example2: a method set in the list of traits finds the msvc + compiler (from self.env['MSVC']==1); more methods are added to self.meths + """ + + __metaclass__ = register_obj + mappings = {} + mapped = {} + prec = {} + traits = {} + classes = {} + + def __init__(self): + self.prec = {} + "map precedence of function names to call" + # so we will have to play with directed acyclic graphs + # detect cycles, etc + + self.source = '' + self.target = '' + + # list of methods to execute - in general one does not touch it by hand + self.meths = set(['apply_core']) + + # list of mappings extension -> function + self.mappings = {} + + # list of features (see the documentation on traits) + self.features = [] + + # not always a good idea + self.m_tasks = [] + + self.chmod = 0644 + self.inst_var = 0 # 0 to prevent installation + self.inst_dir = '' + + if Params.g_install: + self.inst_files = [] # lazy list of tuples representing the files to install + + # kind of private, beware of what you put in it, also, the contents are consumed + self.allnodes = [] + + self.env = Params.g_build.m_allenvs['default'].copy() + + self.m_posted = 0 + self.path = Params.g_build.m_curdirnode # emulate chdir when reading scripts + self.name = '' # give a name to the target (static+shlib with the same targetname ambiguity) + g_allobjs.append(self) + + def __str__(self): + return ("" + % (self.name or self.target, self.__class__.__name__, str(self.path))) + + def __setattr__(self, name, attr): + real = typos.get(name, name) + if real != name: + Params.warning('typo %s -> %s' % (name, real)) + if Params.g_verbose > 0: + traceback.print_stack() + object.__setattr__(self, real, attr) + + def to_list(self, value): + "helper: returns a list" + if type(value) is types.StringType: return value.split() + else: return value + + def addflags(self, var, value): + "utility function add self.cxxflags -> env['CXXFLAGS']" + self.env.append_value(var, self.to_list(value)) + + def add_method(self, name): + "add a method to execute" + # TODO adding functions ? + self.meths.append(name) + + def install(self): + # FIXME + # ambiguity with the install functions + # it is often better to install the targets right after they are up-to_date + # but this means attaching the install to the task objects + if not Params.g_install: return + for (name, var, dir, chmod) in self.inst_files: + print name, var, dir, chmod + + # TODO ugly code + def install_results(self, var, subdir, task, chmod=0644): + debug('install results called', 'object') + if not task: return + current = Params.g_build.m_curdirnode + lst = [a.relpath_gen(current) for a in task.m_outputs] + Common.install_files(var, subdir, lst, chmod=chmod, env=self.env) + + def meth_order(self, *k): + "this one adds the methods to the list of methods" + assert(len(k) > 1) + n = len(k) - 1 + for i in xrange(n): + f1 = k[i] + f2 = k[i+1] + try: self.prec[f2].append(f1) + except: self.prec[f2] = [f1] + if not f1 in self.meths: self.meths.append(f1) + if not f2 in self.meths: self.meths.append(f2) + + def apply_core(self): + # get the list of folders to use by the scanners + # all our objects share the same include paths anyway + tree = Params.g_build + lst = self.to_list(self.source) + find_source_lst = self.path.find_source_lst + + for filename in lst: + # if self.mappings or task_gen.mappings contains a file of the same name + x = self.get_hook(filename) + if x: x(self, filename) + + node = find_source_lst(Utils.split_path(filename)) + if not node: fatal("source not found: %s in %s" % (filename, str(self.path))) + self.allnodes.append(node) + + while self.allnodes: + node = self.allnodes.pop() + # self.mappings or task_gen.mappings map the file extension to a function + filename = node.m_name + k = max(0, filename.rfind('.')) + x = self.get_hook(filename[k:]) + + if not x: + raise TypeError, "Do not know how to process %s in %s, mappings are %s" % \ + (str(node), str(self.__class__), str(self.__class__.mappings)) + x(self, node) + + def apply(self): + "order the methods to execute using self.prec or task_gen.prec" + dct = self.__class__.__dict__ + keys = self.meths + + # add the methods listed in the features + for x in self.features: + keys.update(task_gen.traits[x]) + + # copy the precedence table with the keys in self.meths + prec = {} + prec_tbl = self.prec or task_gen.prec + for x in prec_tbl: + if x in keys: + prec[x] = prec_tbl[x] + + # elements disconnected + tmp = [] + for a in prec: + for x in prec.values(): + if a in x: break + else: + tmp.append(a) + + # topological sort + out = [] + while tmp: + e = tmp.pop() + if e in keys: out.append(e) + try: + nlst = prec[e] + except KeyError: + pass + else: + del prec[e] + for x in nlst: + for y in prec: + if x in prec[y]: + break + else: + tmp.append(x) + + if prec: fatal("graph has a cycle" % str(prec)) + out.reverse() + self.meths = out + + # then we run the methods in order + for x in out: + v = self.get_meth(x) + debug("apply "+x, 'task_gen') + v() + + def post(self): + "runs the code to create the tasks, do not subclass" + if not self.name: self.name = self.target + + if self.m_posted: + error("OBJECT ALREADY POSTED") + return + self.apply() + debug("posted %s" % self.name, 'object') + self.m_posted = 1 + + def get_hook(self, ext): + map = self.mappings + for x in self.mappings: + if x == ext: + return map[x] + + map = task_gen.mappings + for x in map: + if x == ext: + return map[x] + + return None + + def get_meth(self, name): + try: + return getattr(self, name) + except AttributeError: + raise AttributeError, "tried to retrieve %s which is not a valid method" % name + + def create_task(self, type, env=None, nice=None): + task = Task.Task(type, env or self.env) + if nice: task.prio = nice + self.m_tasks.append(task) + return task + + def find_sources_in_dirs(self, dirnames, excludes=[], exts=[]): + "subclass if necessary" + lst = [] + excludes = self.to_list(excludes) + #make sure dirnames is a list helps with dirnames with spaces + dirnames = self.to_list(dirnames) + + ext_lst = exts or self.mappings.keys() + task_gen.mappings.keys() + + # FIXME the following two lines should be removed + try: ext_lst += self.s_default_ext + except AttributeError: pass + + for name in dirnames: + anode = self.path.ensure_node_from_lst(Utils.split_path(name)) + Params.g_build.rescan(anode) + + for file in anode.files(): + (base, ext) = os.path.splitext(file.m_name) + if ext in ext_lst: + s = file.relpath(self.path) + if not s in lst: + if s in excludes: continue + lst.append(s) + + lst.sort() + self.source = self.to_list(self.source) + if not self.source: self.source = lst + else: self.source += lst + + def clone(self, env): + newobj = copy.deepcopy(self) + newobj.path = self.path + + if type(env) is types.StringType: + newobj.env = Params.g_build.m_allenvs[env] + else: + newobj.env = env + + g_allobjs.append(newobj) + + return newobj + +def declare_extension(var, func): + if type(var) is types.ListType: + for x in var: + task_gen.mappings[x] = func + elif type(var) is types.StringType: + task_gen.mappings[var] = func + else: + raise TypeError('declare extension takes either a list or a string %s' % str(var)) + task_gen.mapped[func.__name__] = func + +def declare_order(*k): + assert(len(k) > 1) + n = len(k) - 1 + for i in xrange(n): + f1 = k[i] + f2 = k[i+1] + try: + if not f1 in task_gen.prec[f2]: task_gen.prec[f2].append(f1) + except: + task_gen.prec[f2] = [f1] + +def declare_chain(name='', action='', ext_in=[], ext_out='', reentrant=1, color='BLUE', prio=40, install=0): + """ + see Tools/flex.py for an example + while i do not like such wrappers, some people really do + """ + + if type(action) == types.StringType: + Action.simple_action(name, action, color=color, prio=prio) + else: + name = action.name + + def x_file(self, node): + if type(ext_out) == types.StringType: + ext = ext_out + else: + ext = ext_out(self, node) + + if type(ext) == types.StringType: + out_source = node.change_ext(ext) + if reentrant: + self.allnodes.append(out_source) + elif type(ext) == types.ListType: + out_source = [node.change_ext(x) for x in ext] + if reentrant: + for i in xrange(reentrant): + self.allnodes.append(out_source[i]) + else: + fatal("do not know how to process %s" % str(ext)) + + tsk = self.create_task(name) + tsk.set_inputs(node) + tsk.set_outputs(out_source) + + if Params.g_install and install: + tsk.install = install + + declare_extension(ext_in, x_file) + +def add_feature(name, methods): + lst = Utils.to_list(methods) + try: + l = task_gen.traits[name] + except KeyError: + l = set() + task_gen.traits[name] = l + l.update(lst) + +# decorators follow + +def taskgen(f): + setattr(task_gen, f.__name__, f) + +def feature(name): + def deco(f): + #print name, f + try: + l = task_gen.traits[name] + except KeyError: + l = set() + task_gen.traits[name] = l + l.update([f.__name__]) + return f + return deco + +def before(fun_name): + def deco(f): + try: + if not f.__name__ in task_gen.prec[fun_name]: task_gen.prec[fun_name].append(f.__name__) + except KeyError: + task_gen.prec[fun_name] = [f.__name__] + return f + return deco + +def after(fun_name): + def deco(f): + try: + if not fun_name in task_gen.prec[f.__name__]: task_gen.prec[f.__name__].append(fun_name) + except KeyError: + task_gen.prec[f.__name__] = [fun_name] + return f + return deco + +def extension(var): + if type(var) is types.ListType: + pass + elif type(var) is types.StringType: + var = [var] + else: + raise TypeError('declare extension takes either a list or a string %s' % str(var)) + + def deco(f): + for x in var: + task_gen.mappings[x] = f + task_gen.mapped[f.__name__] = f + return f + return deco + + diff -Nru zyn-1+git.20100609/wafadmin/Options.py zyn-1+git.20100609+dfsg0/wafadmin/Options.py --- zyn-1+git.20100609/wafadmin/Options.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Options.py 2008-03-25 20:07:40.000000000 +0000 @@ -0,0 +1,217 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Scott Newton, 2005 (scottn) +# Thomas Nagy, 2006 (ita) + +"Custom command-line options" + +import os, sys, imp, types, tempfile +from optparse import OptionParser +import Params, Utils +from Params import debug, fatal, warning, error +from Constants import * + +# Such a command-line should work: PREFIX=/opt/ DESTDIR=/tmp/ahoj/ waf configure +default_prefix = os.environ.get('PREFIX') +if not default_prefix: + if sys.platform == 'win32': default_prefix=tempfile.gettempdir() + else: default_prefix = '/usr/local/' + +default_destdir = os.environ.get('DESTDIR', '') + +def create_parser(): + debug("create_parser is called", 'options') + + parser = OptionParser(usage = """waf [options] [commands ...] + +* Main commands: configure build install clean dist distclean uninstall distcheck +* Example: ./waf build -j4""", version = 'waf %s' % Params.g_version) + + p=parser.add_option + + p('-j', '--jobs', + type = 'int', + default = 1, + help = 'specify the number of parallel jobs [Default: 1]', + dest = 'jobs') + + p('', '--daemon', + action = 'store_true', + default = False, + help = 'run as a daemon [Default: False]', + dest = 'daemon') + + p('-f', '--force', + action = 'store_true', + default = False, + help = 'force the files installation', + dest = 'force') + + p('-k', '--keep', + action = 'store_true', + default = False, + help = 'keep running happily on independant task groups', + dest = 'keep') + + p('-p', '--progress', + action = 'count', + default = 0, + help = '-p: progress bar; -pp: ide output', + dest = 'progress_bar') + + p('-v', '--verbose', + action = 'count', + default = 0, + help = 'show verbose output [Default: False]', + dest = 'verbose') + + p('--prefix', + help = "installation prefix [Default: '%s']" % default_prefix, + default = default_prefix, + dest = 'prefix') + + p('--destdir', + help = "installation root [Default: '%s']" % default_destdir, + default = default_destdir, + dest = 'destdir') + + p('--nocache', + action = 'store_true', + default = False, + help = 'compile everything, even if WAFCACHE is set', + dest = 'nocache') + + if 'configure' in sys.argv: + p('-b', '--blddir', + action = 'store', + default = '', + help = 'build dir for the project (configuration)', + dest = 'blddir') + + p('-s', '--srcdir', + action = 'store', + default = '', + help = 'src dir for the project (configuration)', + dest = 'srcdir') + + p('--zones', + action = 'store', + default = '', + help = 'debugging zones', + dest = 'zones') + + p('--targets', + action = 'store', + default = '', + help = 'compile the targets given only [targets in CSV format, e.g. "target1,target2"]', + dest = 'compile_targets') + + return parser + +def parse_args_impl(parser, _args=None): + (Params.g_options, args) = parser.parse_args(args=_args) + #print Params.g_options, " ", args + + # By default, 'waf' is equivalent to 'waf build' + lst='dist configure clean distclean build install uninstall check distcheck'.split() + Params.g_commands = {} + for var in lst: Params.g_commands[var] = 0 + if len(args) == 0: Params.g_commands['build'] = 1 + + # Parse the command arguments + for arg in args: + arg = arg.strip() + if arg in lst: + Params.g_commands[arg]=True + else: + print 'Error: Invalid command specified ',arg + parser.print_help() + sys.exit(1) + if Params.g_commands['check']: + Params.g_commands['build'] = True + + if Params.g_commands['install'] or Params.g_commands['uninstall']: + Params.g_install = 1 + + # TODO -k => -j0 + if Params.g_options.keep: Params.g_options.jobs = 1 + + Params.g_verbose = Params.g_options.verbose + Params.g_zones = Params.g_options.zones.split(',') + if Params.g_verbose>1: Params.set_trace(1,1,1) + else: Params.set_trace(0,0,1) + +class Handler(object): + "loads wscript modules in folders for adding options" + def __init__(self): + self.parser = create_parser() + self.cwd = os.getcwd() + global g_parser + g_parser = self + + def add_option(self, *kw, **kwargs): + self.parser.add_option(*kw, **kwargs) + + def add_option_group(self, *args, **kwargs): + return self.parser.add_option_group(*args, **kwargs) + + def get_option_group(self, opt_str): + return self.parser.get_option_group(opt_str) + + def sub_options(self, dir, option_group=None): + """set options defined by wscripts: + - run by Scripting to set the options defined by main wscript. + - run by wscripts to set options in sub directories.""" + try: + current = self.cwd + + self.cwd = os.path.join(self.cwd, dir) + cur = os.path.join(self.cwd, WSCRIPT_FILE) + + debug("cur is "+str(cur), 'options') + + try: + mod = Utils.load_module(cur) + except AttributeError: + msg = "no module was found for wscript (sub_options)\n[%s]:\n * make sure such a function is defined \n * run configure from the root of the project" + fatal(msg % self.cwd) + try: + fun = mod.set_options + except AttributeError: + msg = "no set_options function was found in wscript\n[%s]:\n * make sure such a function is defined \n * run configure from the root of the project" + fatal(msg % self.cwd) + else: + fun(option_group or self) + + finally: + self.cwd = current + + def tool_options(self, tool, tooldir=None, option_group=None): + if type(tool) is types.ListType: + for i in tool: self.tool_options(i, tooldir, option_group) + return + + if not tooldir: tooldir = Params.g_tooldir + tooldir = Utils.to_list(tooldir) + try: + file,name,desc = imp.find_module(tool, tooldir) + except ImportError: + fatal("no tool named '%s' found" % tool) + module = imp.load_module(tool,file,name,desc) + try: + fun = module.set_options + except AttributeError: + warning("tool %s has no function set_options" % tool) + else: + fun(option_group or self) + + def parse_args(self, args=None): + parse_args_impl(self.parser, args) + +g_parser = None +"Last Handler instance in use" + + diff -Nru zyn-1+git.20100609/wafadmin/Params.py zyn-1+git.20100609+dfsg0/wafadmin/Params.py --- zyn-1+git.20100609/wafadmin/Params.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Params.py 2008-03-23 19:05:48.000000000 +0000 @@ -0,0 +1,260 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2005-2008 (ita) + +"Main parameters" + +import os, sys, types, inspect, base64, time +try: from hashlib import md5 +except ImportError: from md5 import md5 +import Constants, Utils + +# updated from the top-level wscript +g_version="1.3.3" + +g_rootname = '' +g_progress = '\x1b[K%s%s%s\r' +if sys.platform=='win32': + # get the first two letters (c:) + g_rootname = os.getcwd()[:2] + g_progress = '\x1b[A\x1b[K%s%s%s\r' + +g_autoconfig = 0 +"reconfigure the project automatically" + +sig_nil = 'iluvcuteoverload' + +# =================================== # +# Constants set on runtime + +g_cwd_launch = None +"directory from which waf was called" + +g_tooldir='' +"Tools directory (used in particular by Environment.py)" + +g_options = None +"Parsed command-line arguments in the options module" + +g_commands = {} +"build, configure, .." + +g_verbose = 0 +"-v: warnings, -vv: developer info, -vvv: all info" + +g_build = None +"only one build object is active at a time" + +g_platform = sys.platform +"current platform" + +g_cache_global = '' +"config cache directory" + +g_conf_name = 'conf-runs-%s-%d.pickle' % (sys.platform, Constants.ABI) + +g_install = 0 +"true if install or uninstall is set" + +try: g_cache_global = os.path.abspath(os.environ['WAFCACHE']) +except KeyError: pass + +try: g_lockfile = os.environ['WAFLOCK'] +except KeyError: g_lockfile = '.lock-wscript' + +# =================================== # +# HELPERS + +#g_col_names = ['BOLD', 'RED', 'REDP', 'GREEN', 'YELLOW', 'BLUE', 'CYAN', 'NORMAL'] +#"color names" + +g_col_scheme = [1, 91, 33, 92, 93, 94, 96, 0] + +g_colors = { +'BOLD' :'\033[01;1m', +'RED' :'\033[01;91m', +'REDP' :'\033[01;33m', +'GREEN' :'\033[01;92m', +'YELLOW':'\033[00;33m', +'PINK' :'\033[00;35m', +'BLUE' :'\033[01;34m', +'CYAN' :'\033[01;36m', +'NORMAL':'\033[0m' +} +"colors used for printing messages" + +g_cursor_on ='\x1b[?25h' +g_cursor_off='\x1b[?25l' + +def reset_colors(): + global g_colors + for k in g_colors.keys(): + g_colors[k]='' + g_cursor_on='' + g_cursor_off='' + +if (sys.platform=='win32') or ('NOCOLOR' in os.environ) \ + or (os.environ.get('TERM', 'dumb') in ['dumb', 'emacs']) \ + or (not sys.stdout.isatty()): + reset_colors() + +def pprint(col, str, label=''): + try: mycol=g_colors[col] + except KeyError: mycol='' + print "%s%s%s %s" % (mycol, str, g_colors['NORMAL'], label) + +g_levels={ +'Action' : 'GREEN', +'Build' : 'CYAN', +'KDE' : 'REDP', +'Node' : 'GREEN', +'Object' : 'GREEN', +'Runner' : 'REDP', +'Task' : 'GREEN', +'Test' : 'GREEN', +} + +g_zones = [] + +def set_trace(a, b, c): + Utils.g_trace=a + Utils.g_debug=b + Utils.g_error=c + +def get_trace(): + return (Utils.g_trace, Utils.g_debug, Utils.g_error) + +def niceprint(msg, type='', module=''): + #if not module: + # print '%s: %s'% (type, msg) + # return + if type=='ERROR': + print '%s %s <%s> %s %s'% (type, g_colors['RED'], module, g_colors['NORMAL'], msg) + return + if type=='WARNING': + print '%s %s <%s> %s %s'% (type, g_colors['RED'], module, g_colors['NORMAL'], msg) + return + if type=='DEBUG': + print '%s %s <%s> %s %s'% (type, g_colors['CYAN'], module, g_colors['NORMAL'], msg) + return + if module in g_levels: + print '%s %s <%s> %s %s'% (type, g_colors[g_levels[module]], module, g_colors['NORMAL'], msg) + return + print 'TRACE <%s> %s'% (module, msg) + +def __get_module(): + try: return inspect.stack()[2][0].f_globals['__name__'] + except (IndexError, KeyError): return "unknown" + +def debug(msg, zone=None): + global g_zones, g_verbose + if g_zones: + if (not zone in g_zones) and (not '*' in g_zones): + return + elif not g_verbose>2: + return + module = __get_module() + + msg = time.strftime('%%X %s' % msg) + niceprint(msg, 'DEBUG', module) + +def warning(msg, zone=0): + module = __get_module() + niceprint(msg, 'WARNING', module) + +def error(msg): + if not Utils.g_error: return + module = __get_module() + niceprint(msg, 'ERROR', module) + +def fatal(msg, ret=1): + module = __get_module() + if g_verbose > 0: + pprint('RED', '%s \n (error raised in module %s)' % (msg, module)) + else: + pprint('RED', '%s' % msg) + if g_verbose > 1: + import traceback + traceback.print_stack() + sys.exit(ret) + +def view_sig(s): + "used for displaying signatures" + if type(s) is types.StringType: + n = base64.encodestring(s) + return n[:-2] + else: + return str(s) + +def hash_sig(o1, o2): + "hash two signatures" + m = md5() + m.update(o1) + m.update(o2) + return m.digest() + +def h_file(filename): + f = file(filename,'rb') + m = md5() + readBytes = 100000 + while (readBytes): + readString = f.read(readBytes) + m.update(readString) + readBytes = len(readString) + f.close() + return m.digest() + +# Another possibility, faster but less accurate +# based on the path, md5 hashing can be used for some files and timestamp for others +#def h_file(filename): +# st = os.stat(filename) +# m = md5() +# m.update(st.st_mtime) +# m.update(st.st_size) +# return m.digest() + +def h_string(str): + m = md5() + m.update(str) + return m.digest() + +def h_list(lst): + m = md5() + m.update(str(lst)) + return m.digest() + +_hash_blacklist_types = ( + types.BuiltinFunctionType, + types.ModuleType, + types.FunctionType, + types.ClassType, + types.TypeType, + types.NoneType, + ) + +def hash_function_with_globals(prevhash, func): + """ + hash a function (object) and the global vars needed from outside + ignore unhashable global variables (lists) + + prevhash -- previous hash value to be combined with this one; + if there is no previous value, zero should be used here + + func -- a Python function object. + """ + assert type(func) is types.FunctionType + for name, value in func.func_globals.iteritems(): + if type(value) in _hash_blacklist_types: + continue + try: + prevhash = hash( (prevhash, name, value) ) + except TypeError: # raised for unhashable elements + pass + #else: + # print "hashed: ", name, " => ", value, " => ", hash(value) + return hash( (prevhash, inspect.getsource(func)) ) + + diff -Nru zyn-1+git.20100609/wafadmin/pproc.py zyn-1+git.20100609+dfsg0/wafadmin/pproc.py --- zyn-1+git.20100609/wafadmin/pproc.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/pproc.py 2008-03-23 19:05:48.000000000 +0000 @@ -0,0 +1,624 @@ +#! /usr/bin/env python +# encoding: utf-8 + +# borrowed from python 2.5.2c1 +# Copyright (c) 2003-2005 by Peter Astrand +# Licensed to PSF under a Contributor Agreement. + +import sys +mswindows = (sys.platform == "win32") + +import os +import types +import traceback +import gc + +class CalledProcessError(Exception): + def __init__(self, returncode, cmd): + self.returncode = returncode + self.cmd = cmd + def __str__(self): + return "Command '%s' returned non-zero exit status %d" % (self.cmd, self.returncode) + +if mswindows: + import threading + import msvcrt + if 0: + import pywintypes + from win32api import GetStdHandle, STD_INPUT_HANDLE, \ + STD_OUTPUT_HANDLE, STD_ERROR_HANDLE + from win32api import GetCurrentProcess, DuplicateHandle, \ + GetModuleFileName, GetVersion + from win32con import DUPLICATE_SAME_ACCESS, SW_HIDE + from win32pipe import CreatePipe + from win32process import CreateProcess, STARTUPINFO, \ + GetExitCodeProcess, STARTF_USESTDHANDLES, \ + STARTF_USESHOWWINDOW, CREATE_NEW_CONSOLE + from win32event import WaitForSingleObject, INFINITE, WAIT_OBJECT_0 + else: + from _subprocess import * + class STARTUPINFO: + dwFlags = 0 + hStdInput = None + hStdOutput = None + hStdError = None + wShowWindow = 0 + class pywintypes: + error = IOError +else: + import select + import errno + import fcntl + import pickle + +__all__ = ["Popen", "PIPE", "STDOUT", "call", "check_call", "CalledProcessError"] + +try: + MAXFD = os.sysconf("SC_OPEN_MAX") +except: + MAXFD = 256 + +try: + False +except NameError: + False = 0 + True = 1 + +_active = [] + +def _cleanup(): + for inst in _active[:]: + if inst.poll(_deadstate=sys.maxint) >= 0: + try: + _active.remove(inst) + except ValueError: + pass + +PIPE = -1 +STDOUT = -2 + + +def call(*popenargs, **kwargs): + return Popen(*popenargs, **kwargs).wait() + +def check_call(*popenargs, **kwargs): + retcode = call(*popenargs, **kwargs) + cmd = kwargs.get("args") + if cmd is None: + cmd = popenargs[0] + if retcode: + raise CalledProcessError(retcode, cmd) + return retcode + + +def list2cmdline(seq): + result = [] + needquote = False + for arg in seq: + bs_buf = [] + + if result: + result.append(' ') + + needquote = (" " in arg) or ("\t" in arg) or arg == "" + if needquote: + result.append('"') + + for c in arg: + if c == '\\': + bs_buf.append(c) + elif c == '"': + result.append('\\' * len(bs_buf)*2) + bs_buf = [] + result.append('\\"') + else: + if bs_buf: + result.extend(bs_buf) + bs_buf = [] + result.append(c) + + if bs_buf: + result.extend(bs_buf) + + if needquote: + result.extend(bs_buf) + result.append('"') + + return ''.join(result) + +class Popen(object): + def __init__(self, args, bufsize=0, executable=None, + stdin=None, stdout=None, stderr=None, + preexec_fn=None, close_fds=False, shell=False, + cwd=None, env=None, universal_newlines=False, + startupinfo=None, creationflags=0): + _cleanup() + + self._child_created = False + if not isinstance(bufsize, (int, long)): + raise TypeError("bufsize must be an integer") + + if mswindows: + if preexec_fn is not None: + raise ValueError("preexec_fn is not supported on Windows platforms") + if close_fds: + raise ValueError("close_fds is not supported on Windows platforms") + else: + if startupinfo is not None: + raise ValueError("startupinfo is only supported on Windows platforms") + if creationflags != 0: + raise ValueError("creationflags is only supported on Windows platforms") + + self.stdin = None + self.stdout = None + self.stderr = None + self.pid = None + self.returncode = None + self.universal_newlines = universal_newlines + + (p2cread, p2cwrite, + c2pread, c2pwrite, + errread, errwrite) = self._get_handles(stdin, stdout, stderr) + + self._execute_child(args, executable, preexec_fn, close_fds, + cwd, env, universal_newlines, + startupinfo, creationflags, shell, + p2cread, p2cwrite, + c2pread, c2pwrite, + errread, errwrite) + + if mswindows: + if stdin is None and p2cwrite is not None: + os.close(p2cwrite) + p2cwrite = None + if stdout is None and c2pread is not None: + os.close(c2pread) + c2pread = None + if stderr is None and errread is not None: + os.close(errread) + errread = None + + if p2cwrite: + self.stdin = os.fdopen(p2cwrite, 'wb', bufsize) + if c2pread: + if universal_newlines: + self.stdout = os.fdopen(c2pread, 'rU', bufsize) + else: + self.stdout = os.fdopen(c2pread, 'rb', bufsize) + if errread: + if universal_newlines: + self.stderr = os.fdopen(errread, 'rU', bufsize) + else: + self.stderr = os.fdopen(errread, 'rb', bufsize) + + + def _translate_newlines(self, data): + data = data.replace("\r\n", "\n") + data = data.replace("\r", "\n") + return data + + + def __del__(self, sys=sys): + if not self._child_created: + return + self.poll(_deadstate=sys.maxint) + if self.returncode is None and _active is not None: + _active.append(self) + + + def communicate(self, input=None): + if [self.stdin, self.stdout, self.stderr].count(None) >= 2: + stdout = None + stderr = None + if self.stdin: + if input: + self.stdin.write(input) + self.stdin.close() + elif self.stdout: + stdout = self.stdout.read() + elif self.stderr: + stderr = self.stderr.read() + self.wait() + return (stdout, stderr) + + return self._communicate(input) + + + if mswindows: + def _get_handles(self, stdin, stdout, stderr): + if stdin is None and stdout is None and stderr is None: + return (None, None, None, None, None, None) + + p2cread, p2cwrite = None, None + c2pread, c2pwrite = None, None + errread, errwrite = None, None + + if stdin is None: + p2cread = GetStdHandle(STD_INPUT_HANDLE) + if p2cread is not None: + pass + elif stdin is None or stdin == PIPE: + p2cread, p2cwrite = CreatePipe(None, 0) + p2cwrite = p2cwrite.Detach() + p2cwrite = msvcrt.open_osfhandle(p2cwrite, 0) + elif isinstance(stdin, int): + p2cread = msvcrt.get_osfhandle(stdin) + else: + p2cread = msvcrt.get_osfhandle(stdin.fileno()) + p2cread = self._make_inheritable(p2cread) + + if stdout is None: + c2pwrite = GetStdHandle(STD_OUTPUT_HANDLE) + if c2pwrite is not None: + pass + elif stdout is None or stdout == PIPE: + c2pread, c2pwrite = CreatePipe(None, 0) + c2pread = c2pread.Detach() + c2pread = msvcrt.open_osfhandle(c2pread, 0) + elif isinstance(stdout, int): + c2pwrite = msvcrt.get_osfhandle(stdout) + else: + c2pwrite = msvcrt.get_osfhandle(stdout.fileno()) + c2pwrite = self._make_inheritable(c2pwrite) + + if stderr is None: + errwrite = GetStdHandle(STD_ERROR_HANDLE) + if errwrite is not None: + pass + elif stderr is None or stderr == PIPE: + errread, errwrite = CreatePipe(None, 0) + errread = errread.Detach() + errread = msvcrt.open_osfhandle(errread, 0) + elif stderr == STDOUT: + errwrite = c2pwrite + elif isinstance(stderr, int): + errwrite = msvcrt.get_osfhandle(stderr) + else: + errwrite = msvcrt.get_osfhandle(stderr.fileno()) + errwrite = self._make_inheritable(errwrite) + + return (p2cread, p2cwrite, + c2pread, c2pwrite, + errread, errwrite) + def _make_inheritable(self, handle): + return DuplicateHandle(GetCurrentProcess(), handle, GetCurrentProcess(), 0, 1, DUPLICATE_SAME_ACCESS) + + def _find_w9xpopen(self): + w9xpopen = os.path.join(os.path.dirname(GetModuleFileName(0)), "w9xpopen.exe") + if not os.path.exists(w9xpopen): + w9xpopen = os.path.join(os.path.dirname(sys.exec_prefix), "w9xpopen.exe") + if not os.path.exists(w9xpopen): + raise RuntimeError("Cannot locate w9xpopen.exe, which is needed for Popen to work with your shell or platform.") + return w9xpopen + + def _execute_child(self, args, executable, preexec_fn, close_fds, + cwd, env, universal_newlines, + startupinfo, creationflags, shell, + p2cread, p2cwrite, + c2pread, c2pwrite, + errread, errwrite): + + if not isinstance(args, types.StringTypes): + args = list2cmdline(args) + + if startupinfo is None: + startupinfo = STARTUPINFO() + if None not in (p2cread, c2pwrite, errwrite): + startupinfo.dwFlags |= STARTF_USESTDHANDLES + startupinfo.hStdInput = p2cread + startupinfo.hStdOutput = c2pwrite + startupinfo.hStdError = errwrite + + if shell: + startupinfo.dwFlags |= STARTF_USESHOWWINDOW + startupinfo.wShowWindow = SW_HIDE + comspec = os.environ.get("COMSPEC", "cmd.exe") + args = comspec + " /c " + args + if (GetVersion() >= 0x80000000L or + os.path.basename(comspec).lower() == "command.com"): + w9xpopen = self._find_w9xpopen() + args = '"%s" %s' % (w9xpopen, args) + creationflags |= CREATE_NEW_CONSOLE + + try: + hp, ht, pid, tid = CreateProcess(executable, args, None, None, 1, creationflags, env, cwd, startupinfo) + except pywintypes.error, e: + raise WindowsError(*e.args) + + self._child_created = True + self._handle = hp + self.pid = pid + ht.Close() + + if p2cread is not None: + p2cread.Close() + if c2pwrite is not None: + c2pwrite.Close() + if errwrite is not None: + errwrite.Close() + + + def poll(self, _deadstate=None): + if self.returncode is None: + if WaitForSingleObject(self._handle, 0) == WAIT_OBJECT_0: + self.returncode = GetExitCodeProcess(self._handle) + return self.returncode + + + def wait(self): + if self.returncode is None: + obj = WaitForSingleObject(self._handle, INFINITE) + self.returncode = GetExitCodeProcess(self._handle) + return self.returncode + + def _readerthread(self, fh, buffer): + buffer.append(fh.read()) + + def _communicate(self, input): + stdout = None + stderr = None + + if self.stdout: + stdout = [] + stdout_thread = threading.Thread(target=self._readerthread, args=(self.stdout, stdout)) + stdout_thread.setDaemon(True) + stdout_thread.start() + if self.stderr: + stderr = [] + stderr_thread = threading.Thread(target=self._readerthread, args=(self.stderr, stderr)) + stderr_thread.setDaemon(True) + stderr_thread.start() + + if self.stdin: + if input is not None: + self.stdin.write(input) + self.stdin.close() + + if self.stdout: + stdout_thread.join() + if self.stderr: + stderr_thread.join() + + if stdout is not None: + stdout = stdout[0] + if stderr is not None: + stderr = stderr[0] + + if self.universal_newlines and hasattr(file, 'newlines'): + if stdout: + stdout = self._translate_newlines(stdout) + if stderr: + stderr = self._translate_newlines(stderr) + + self.wait() + return (stdout, stderr) + + else: + def _get_handles(self, stdin, stdout, stderr): + p2cread, p2cwrite = None, None + c2pread, c2pwrite = None, None + errread, errwrite = None, None + + if stdin is None: + pass + elif stdin == PIPE: + p2cread, p2cwrite = os.pipe() + elif isinstance(stdin, int): + p2cread = stdin + else: + p2cread = stdin.fileno() + + if stdout is None: + pass + elif stdout == PIPE: + c2pread, c2pwrite = os.pipe() + elif isinstance(stdout, int): + c2pwrite = stdout + else: + c2pwrite = stdout.fileno() + + if stderr is None: + pass + elif stderr == PIPE: + errread, errwrite = os.pipe() + elif stderr == STDOUT: + errwrite = c2pwrite + elif isinstance(stderr, int): + errwrite = stderr + else: + errwrite = stderr.fileno() + + return (p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite) + + def _set_cloexec_flag(self, fd): + try: + cloexec_flag = fcntl.FD_CLOEXEC + except AttributeError: + cloexec_flag = 1 + + old = fcntl.fcntl(fd, fcntl.F_GETFD) + fcntl.fcntl(fd, fcntl.F_SETFD, old | cloexec_flag) + + def _close_fds(self, but): + for i in xrange(3, MAXFD): + if i == but: + continue + try: + os.close(i) + except: + pass + + def _execute_child(self, args, executable, preexec_fn, close_fds, + cwd, env, universal_newlines, startupinfo, creationflags, shell, + p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite): + + if isinstance(args, types.StringTypes): + args = [args] + else: + args = list(args) + + if shell: + args = ["/bin/sh", "-c"] + args + + if executable is None: + executable = args[0] + + errpipe_read, errpipe_write = os.pipe() + self._set_cloexec_flag(errpipe_write) + + gc_was_enabled = gc.isenabled() + gc.disable() + try: + self.pid = os.fork() + except: + if gc_was_enabled: + gc.enable() + raise + self._child_created = True + if self.pid == 0: + try: + if p2cwrite: + os.close(p2cwrite) + if c2pread: + os.close(c2pread) + if errread: + os.close(errread) + os.close(errpipe_read) + + if p2cread: + os.dup2(p2cread, 0) + if c2pwrite: + os.dup2(c2pwrite, 1) + if errwrite: + os.dup2(errwrite, 2) + + if p2cread and p2cread not in (0,): + os.close(p2cread) + if c2pwrite and c2pwrite not in (p2cread, 1): + os.close(c2pwrite) + if errwrite and errwrite not in (p2cread, c2pwrite, 2): + os.close(errwrite) + + if close_fds: + self._close_fds(but=errpipe_write) + + if cwd is not None: + os.chdir(cwd) + + if preexec_fn: + apply(preexec_fn) + + if env is None: + os.execvp(executable, args) + else: + os.execvpe(executable, args, env) + + except: + exc_type, exc_value, tb = sys.exc_info() + exc_lines = traceback.format_exception(exc_type, exc_value, tb) + exc_value.child_traceback = ''.join(exc_lines) + os.write(errpipe_write, pickle.dumps(exc_value)) + + os._exit(255) + + if gc_was_enabled: + gc.enable() + os.close(errpipe_write) + if p2cread and p2cwrite: + os.close(p2cread) + if c2pwrite and c2pread: + os.close(c2pwrite) + if errwrite and errread: + os.close(errwrite) + + data = os.read(errpipe_read, 1048576) + os.close(errpipe_read) + if data != "": + os.waitpid(self.pid, 0) + child_exception = pickle.loads(data) + raise child_exception + + def _handle_exitstatus(self, sts): + if os.WIFSIGNALED(sts): + self.returncode = -os.WTERMSIG(sts) + elif os.WIFEXITED(sts): + self.returncode = os.WEXITSTATUS(sts) + else: + raise RuntimeError("Unknown child exit status!") + + def poll(self, _deadstate=None): + if self.returncode is None: + try: + pid, sts = os.waitpid(self.pid, os.WNOHANG) + if pid == self.pid: + self._handle_exitstatus(sts) + except os.error: + if _deadstate is not None: + self.returncode = _deadstate + return self.returncode + + def wait(self): + if self.returncode is None: + pid, sts = os.waitpid(self.pid, 0) + self._handle_exitstatus(sts) + return self.returncode + + def _communicate(self, input): + read_set = [] + write_set = [] + stdout = None + stderr = None + + if self.stdin: + self.stdin.flush() + if input: + write_set.append(self.stdin) + else: + self.stdin.close() + if self.stdout: + read_set.append(self.stdout) + stdout = [] + if self.stderr: + read_set.append(self.stderr) + stderr = [] + + input_offset = 0 + while read_set or write_set: + rlist, wlist, xlist = select.select(read_set, write_set, []) + + if self.stdin in wlist: + bytes_written = os.write(self.stdin.fileno(), buffer(input, input_offset, 512)) + input_offset += bytes_written + if input_offset >= len(input): + self.stdin.close() + write_set.remove(self.stdin) + + if self.stdout in rlist: + data = os.read(self.stdout.fileno(), 1024) + if data == "": + self.stdout.close() + read_set.remove(self.stdout) + stdout.append(data) + + if self.stderr in rlist: + data = os.read(self.stderr.fileno(), 1024) + if data == "": + self.stderr.close() + read_set.remove(self.stderr) + stderr.append(data) + + if stdout is not None: + stdout = ''.join(stdout) + if stderr is not None: + stderr = ''.join(stderr) + + if self.universal_newlines and hasattr(file, 'newlines'): + if stdout: + stdout = self._translate_newlines(stdout) + if stderr: + stderr = self._translate_newlines(stderr) + + self.wait() + return (stdout, stderr) + + diff -Nru zyn-1+git.20100609/wafadmin/Runner.py zyn-1+git.20100609+dfsg0/wafadmin/Runner.py --- zyn-1+git.20100609/wafadmin/Runner.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Runner.py 2008-03-23 19:05:48.000000000 +0000 @@ -0,0 +1,402 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2005 (ita) + +"Execute the tasks" + +import sys, random, time, threading, Queue, traceback +import Params, Utils +import pproc as subprocess +from Params import debug, error + +g_quiet = 0 +"do not output anything" + +missing = 1 +crashed = 2 +skipped = 8 +success = 9 + +def printout(s): + sys.stdout.write(s); sys.stdout.flush() + +def progress_line(state, total, col1, task, col2): + "do not print anything if there is nothing to display" + if Params.g_options.progress_bar == 1: + return Utils.progress_line(state, total, col1, col2) + + if Params.g_options.progress_bar == 2: + try: ini = Params.g_build.ini + except AttributeError: ini = Params.g_build.ini = time.time() + ela = time.strftime('%H:%M:%S', time.gmtime(time.time() - ini)) + ins = ','.join([n.m_name for n in task.m_inputs]) + outs = ','.join([n.m_name for n in task.m_outputs]) + return '|Total %s|Current %s|Inputs %s|Outputs %s|Time %s|\n' % (total, state, ins, outs, ela) + + n = len(str(total)) + fs = "[%%%dd/%%%dd] %%s%%s%%s\n" % (n, n) + return fs % (state, total, col1, task.get_display(), col2) + +def process_cmd_output(cmd_stdout, cmd_stderr): + stdout_eof = stderr_eof = 0 + while not (stdout_eof and stderr_eof): + if not stdout_eof: + s = cmd_stdout.read() + if not s: stdout_eof = 1 + elif not g_quiet: printout(s) + if not stderr_eof: + s = cmd_stderr.read() + if not s: stderr_eof = 1 + elif not g_quiet: + sys.stderr.write('\n') + sys.stderr.write(s) + #time.sleep(0.1) + +def exec_command_normal(s): + "run commands in a portable way the subprocess module backported from python 2.4 and should work on python >= 2.2" + debug("system command -> "+ s, 'runner') + if Params.g_verbose: print s + # encase the command in double-quotes in windows + if sys.platform == 'win32' and not s.startswith('""'): + s = '"%s"' % s + proc = subprocess.Popen(s, shell=1, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + process_cmd_output(proc.stdout, proc.stderr) + stat = proc.wait() + if stat & 0xff: return stat | 0x80 + return stat >> 8 + +def exec_command_interact(s): + "this one is for the latex output, where we cannot capture the output while the process waits for stdin" + debug("system command (interact) -> "+ s, 'runner') + if Params.g_verbose: print s + # encase the command in double-quotes in windows + if sys.platform == 'win32' and not s.startswith('""'): + s = '"%s"' % s + proc = subprocess.Popen(s, shell=1) + stat = proc.wait() + if stat & 0xff: return stat | 0x80 + return stat >> 8 + +exec_command = exec_command_interact # python bug on stdout overload +def set_exec(mode): + global exec_command + if mode == 'normal': exec_command = exec_command_normal + elif mode == 'noredir': exec_command = exec_command_interact + else: error('set_runner_mode') + +class Serial(object): + def __init__(self, bld): + self.error = 0 + + self.manager = bld.task_manager + + self.curgroup = 0 + self.curprio = -1 + self.outstanding = [] # list of tasks in the current priority + + self.priolst = [] + + # progress bar + self.total = self.manager.total() + self.processed = 0 + + self.switchflag = 1 # postpone + # self.manager.debug() + + # warning, this one is recursive .. + def get_next(self): + if self.outstanding: + t = self.outstanding.pop(0) + self.processed += 1 + return t + + # handle case where only one wscript exist + # that only install files + if not self.manager.groups: + return None + + # stop condition + if self.curgroup >= len(self.manager.groups): + return None + + # increase the priority value + self.curprio += 1 + + # there is no current list + group = self.manager.groups[self.curgroup] + if self.curprio >= len(group.prio.keys()): + self.curprio = -1 + self.curgroup += 1 + return self.get_next() + + # sort keys if necessary + if self.curprio == 0: + self.priolst = group.prio.keys() + self.priolst.sort() + + # now fill outstanding + id = self.priolst[self.curprio] + self.outstanding = group.prio[id] + + if Params.g_verbose: + debug("Preparing to run prio %i tasks: [\n%s\n\t]" % + (id, ',\n'.join(["\t#%i: %s" % (tsk.m_idx, repr(tsk).strip()) + for tsk in self.outstanding])), + 'runner') + return self.get_next() + + def progress(self): + return (self.processed, self.total) + + def postpone(self, tsk): + self.processed -= 1 + # shuffle the list - why it does work is left as an exercise for the reader + self.switchflag *= -1 + if self.switchflag>0: self.outstanding.insert(0, tsk) + else: self.outstanding.append(tsk) + + # TODO FIXME + def debug(self): + debug("debugging a task: something went wrong:", 'runner') + s = " ".join([str(t.m_idx) for t in self.manager]) + debug(s, 'runner') + + # skip a group and report the failure + def skip_group(self): + self.curgroup += 1 + self.curprio = -1 + self.outstanding = [] + try: self.manager.groups[self.curgroup].prio.sort() + except KeyError: pass + + def start(self): + global g_quiet + debug("Serial start called", 'runner') + #self.debug() + while 1: + # get next Task + tsk = self.get_next() + if tsk is None: break + + debug("retrieving #%i (%r)" % (tsk.m_idx, tsk), 'runner') + + # # ======================= + #if tsk.m_hasrun: + # error("task has already run! "+str(tsk.m_idx)) + + if not tsk.may_start(): + debug("delaying #"+str(tsk.m_idx), 'runner') + self.postpone(tsk) + #self.debug() + #tsk = None + continue + # # ======================= + + tsk.prepare() + #tsk.debug() + + #debug("m_sig is "+str(tsk.m_sig), 'runner') + #debug("obj output m_sig is "+str(tsk.m_outputs[0].get_sig()), 'runner') + + #continue + if not tsk.must_run(): + tsk.m_hasrun = skipped + self.manager.add_finished(tsk) + #debug("task is up-to_date "+str(tsk.m_idx), 'runner') + continue + + debug("executing #"+str(tsk.m_idx), 'runner') + + # display the command that we are about to run + if not g_quiet: + (s, t) = self.progress() + cl = Params.g_colors + printout(progress_line(s, t, cl[tsk.color()], tsk, cl['NORMAL'])) + + # run the command + ret = tsk.run() + self.manager.add_finished(tsk) + + # non-zero means something went wrong + if ret: + self.error = 1 + tsk.m_hasrun = crashed + tsk.err_code = ret + if Params.g_options.keep: continue + else: return -1 + + try: + tsk.update_stat() + except OSError: + traceback.print_stack() + self.error = 1 + tsk.m_hasrun = missing + if Params.g_options.keep: continue + else: return -1 + else: + tsk.m_hasrun = success + + if self.error: + return -1 + +class TaskConsumer(threading.Thread): + def __init__(self, i, m): + threading.Thread.__init__(self) + self.setDaemon(1) + self.id = i + self.master = m + self.start() + + def run(self): + do_stat = getattr(self, 'do_stat', None) + m = self.master + + while 1: + tsk = m.ready.get() + if m.failed and not m.running: + m.out.put(tsk) + continue + + if do_stat: do_stat(1) + + printout(tsk.get_display()) + ret = tsk.run() + + if do_stat: do_stat(-1) + + if ret: + tsk.err_code = ret + tsk.m_hasrun = crashed + else: + try: + tsk.update_stat() + except OSError: + tsk.m_hasrun = missing + else: + tsk.m_hasrun = success + if tsk.m_hasrun != success: # TODO for now, do no keep running in parallel and not Params.g_options.keep: + m.failed = 1 + + m.out.put(tsk) + +class Parallel(object): + """ + The following is a small scheduler for making as many tasks available to the consumer threads + It uses the serial shuffling system + """ + def __init__(self, bld, j=2): + + # number of consumers + self.numjobs = j + + self.manager = bld.task_manager + + # progress bar + self.total = self.manager.total() + self.processed = 0 + + # tasks waiting to be processed - IMPORTANT + self.outstanding = [] + # tasks that are awaiting for another task to complete + self.frozen = [] + + # tasks waiting to be run by the consumers + self.ready = Queue.Queue(0) + self.out = Queue.Queue(0) + + self.count = 0 # tasks not in the producer area + self.failed = 0 # some task has failed + self.running = 0 # keep running ? + self.progress = 0 # progress indicator + + self.curgroup = 0 + self.curprio = -1 + self.priolst = [] + + def get_next_prio(self): + # stop condition + if self.curgroup >= len(self.manager.groups): + return (None, None) + + # increase the priority value + self.curprio += 1 + + # there is no current list + group = self.manager.groups[self.curgroup] + if self.curprio >= len(group.prio.keys()): + self.curprio = -1 + self.curgroup += 1 + return self.get_next_prio() + + # sort keys if necessary + if self.curprio == 0: + self.priolst = group.prio.keys() + self.priolst.sort() + + id = self.priolst[self.curprio] + return (id, group.prio[id]) + + def start(self): + for i in range(self.numjobs): TaskConsumer(i, self) + + # the current group + #group = None + + def get_out(): + self.manager.add_finished(self.out.get()) + self.count -= 1 + + lastfailput = 0 + + # iterate over all tasks at most one time for each task run + penalty = 0 + currentprio = 0 + #loop=0 + while 1: + #loop += 1 + if self.failed and not self.running: + while self.count > 0: get_out() + if self.failed: return -1 + + if 1 == currentprio % 2: + # allow only one process at a time in priority 'even' + while self.count > 0: get_out() + else: + # not too many jobs in the queue + while self.count > self.numjobs + 10: get_out() + + # empty the returned tasks as much as possible + while not self.out.empty(): get_out() + + if not self.outstanding: + if self.count > 0: get_out() + self.outstanding = self.frozen + self.frozen = [] + if not self.outstanding: + while self.count > 0: get_out() + (currentprio, self.outstanding) = self.get_next_prio() + #if self.outstanding: random.shuffle(self.outstanding) + if currentprio is None: break + + # consider the next task + tsk = self.outstanding.pop(0) + if tsk.may_start(): + tsk.prepare() + self.progress += 1 + if not tsk.must_run(): + tsk.m_hasrun = skipped + self.manager.add_finished(tsk) + continue + cl = Params.g_colors + tsk.set_display(progress_line(self.progress, self.total, cl[tsk.color()], tsk, cl['NORMAL'])) + self.count += 1 + self.ready.put(tsk) + else: + if random.randint(0,1): self.frozen.insert(0, tsk) + else: self.frozen.append(tsk) + #print loop + + diff -Nru zyn-1+git.20100609/wafadmin/Scan.py zyn-1+git.20100609+dfsg0/wafadmin/Scan.py --- zyn-1+git.20100609/wafadmin/Scan.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Scan.py 2008-03-23 19:05:48.000000000 +0000 @@ -0,0 +1,131 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2005-2008 (ita) + +"Scan for dependencies, compute task signatures" + +try: from hashlib import md5 +except ImportError: from md5 import md5 +import Params +from Params import debug, error + +g_all_scanners={} +"all instances of scanners" + +class scanner(object): + "TODO: call this a dependency manager (not a scanner), as it does scan and compute the signatures" + + def __init__(self): + global g_all_scanners + g_all_scanners[self.__class__.__name__] = self + self.vars = [] # additional vars to add in the scanning process + + # ======================================= # + # interface definition + + # this method returns a tuple containing: + # * a list of nodes corresponding to real files + # * a list of names for files not found in path_lst + # the input parameters may have more parameters that the ones used below + def scan(self, tsk, node): + "usually reimplemented" + return ([], []) + + # scans a node, the task may have additional parameters such as include paths, etc + def do_scan(self, tsk, node): + "more rarely reimplemented" + debug("do_scan(self, node, env, hashparams)", 'ccroot') + + variant = node.variant(tsk.env()) + + if not node: + error("BUG rescanning a null node") + return + + # we delegate the work to "def scan(self, tsk, node)" to avoid duplicate code + (nodes, names) = self.scan(tsk, node) + if Params.g_verbose: + if Params.g_zones: + debug('scanner for %s returned %s %s' % (node.m_name, str(nodes), str(names)), 'deps') + + tree = Params.g_build + tree.m_depends_on[variant][node] = nodes + tree.m_raw_deps[variant][node] = names + + # compute the signature, recompute it if there is no match in the cache + def get_signature(self, tsk): + "the signature obtained may not be the one if the files have changed, we do it in two steps" + tree = Params.g_build + env = tsk.env() + + # assumption: we assume that we can still get the old signature from the signature cache + try: + node = tsk.m_outputs[0] + variant = node.variant(tsk.env()) + time = tree.m_tstamp_variants[variant][node] + key = hash( (variant, node, time, self.__class__.__name__) ) + prev_sig = tree.get_sig_cache(key)[1] + except KeyError: + prev_sig = Params.sig_nil + + # we can compute and return the signature if + # * the source files have not changed (rescan is 0) + # * the computed signature has not changed + sig = self.get_signature_queue(tsk) + + # if the previous signature is the same + if sig == prev_sig: return sig + + #print "scanning the file", tsk.m_inputs[0].abspath() + + # therefore some source or some header is dirty, rescan the source files + for node in tsk.m_inputs: + self.do_scan(tsk, node) + + # recompute the signature and return it + sig = self.get_signature_queue(tsk) + + # DEBUG + #print "rescan for ", tsk.m_inputs[0], " is ", rescan, " and deps ", \ + # tree.m_depends_on[variant][node], tree.m_raw_deps[variant][node] + + return sig + + # ======================================= # + # protected methods - override if you know what you are doing + + def get_signature_queue(self, tsk): + "the basic scheme for computing signatures from .cpp and inferred .h files" + tree = Params.g_build + + rescan = 0 + seen = [] + queue = []+tsk.m_inputs + m = md5() + + # additional variables to hash (command-line defines for example) + env = tsk.env() + for x in self.vars: + m.update(str(env[x])) + + # add the hashes of all files entering into the dependency system + while queue: + node = queue.pop(0) + + if node in seen: continue + seen.append(node) + + # TODO: look at the case of stale nodes and dependencies types + variant = node.variant(env) + try: queue += tree.m_depends_on[variant][node] + except KeyError: pass + + try: m.update(tree.m_tstamp_variants[variant][node]) + except KeyError: return Params.sig_nil + + return m.digest() + + diff -Nru zyn-1+git.20100609/wafadmin/Scripting.py zyn-1+git.20100609+dfsg0/wafadmin/Scripting.py --- zyn-1+git.20100609/wafadmin/Scripting.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Scripting.py 2008-03-25 19:28:28.000000000 +0000 @@ -0,0 +1,588 @@ +#! /usr/bin/env python +# encoding: utf-8 +import sys +if sys.hexversion < 0x020400f0: from sets import Set as set +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2005 (ita) + +"Module called for configuring, compiling and installing targets" + +import os, sys, cPickle, traceback +import Params, Utils, Configure, Build, Runner, Options +import shutil +from Params import error, fatal, warning, g_lockfile +from Constants import * + +g_gz='bz2' +g_dirwatch = None +g_daemonlock = 0 +g_excludes = '.svn CVS .arch-ids {arch} SCCS BitKeeper .hg'.split() +"exclude folders from dist" +g_dist_exts = '~ .rej .orig .pyc .pyo .bak config.log .tar.bz2 .zip Makefile Makefile.in'.split() +"exclude files from dist" + +g_distclean_exts = '~ .pyc .wafpickle'.split() + +def add_subdir(dir, bld): + "each wscript calls bld.add_subdir" + try: bld.rescan(bld.m_curdirnode) + except OSError: fatal("No such directory "+bld.m_curdirnode.abspath()) + + old = bld.m_curdirnode + new = bld.m_curdirnode.ensure_node_from_lst(Utils.split_path(dir)) + if new is None: + fatal("subdir not found (%s), restore is %s" % (dir, bld.m_curdirnode)) + + bld.m_curdirnode=new + # try to open 'wscript_build' for execution + # if unavailable, open the module wscript and call the build function from it + from Common import install_files, install_as, symlink_as # do not remove + try: + file_path = os.path.join(new.abspath(), WSCRIPT_BUILD_FILE) + file = open(file_path, 'r') + exec file + if file: file.close() + except IOError: + file_path = os.path.join(new.abspath(), WSCRIPT_FILE) + module = Utils.load_module(file_path) + module.build(bld) + + # restore the old node position + bld.m_curdirnode=old + + # + #node = bld.m_curdirnode.ensure_node_from_lst(Utils.split_path(dir)) + #if node is None: + # fatal("subdir not found (%s), restore is %s" % (dir, bld.m_curdirnode)) + #bld.m_subdirs = [[node, bld.m_curdirnode]] + bld.m_subdirs + +def call_back(idxName, pathName, event): + #print "idxName=%s, Path=%s, Event=%s "%(idxName, pathName, event) + # check the daemon lock state + global g_daemonlock + if g_daemonlock: return + g_daemonlock = 1 + + # clean up existing variables, and start a new instance + Utils.reset() + main() + g_daemonlock = 0 + +def start_daemon(): + "if it does not exist already:start a new directory watcher; else: return immediately" + global g_dirwatch + if not g_dirwatch: + import DirWatch + g_dirwatch = DirWatch.DirectoryWatcher() + m_dirs=[] + for nodeDir in Params.g_build.m_srcnode.dirs(): + tmpstr = "%s" %nodeDir + tmpstr = "%s" %(tmpstr[3:])[:-1] + m_dirs.append(tmpstr) + g_dirwatch.add_watch("tmp Test", call_back, m_dirs) + # infinite loop, no need to exit except on ctrl+c + g_dirwatch.loop() + g_dirwatch = None + else: + g_dirwatch.suspend_all_watch() + m_dirs=[] + for nodeDir in Params.g_build.m_srcnode.dirs(): + tmpstr = "%s" %nodeDir + tmpstr = "%s" %(tmpstr[3:])[:-1] + m_dirs.append(tmpstr) + g_dirwatch.add_watch("tmp Test", call_back, m_dirs) + +def configure(): + # disable parallelization while configuring + jobs_save = Params.g_options.jobs + Params.g_options.jobs = 1 + + Runner.set_exec('normal') + tree = Build.Build() + + err = 'The %s is not given in %s:\n * define a top level attribute named "%s"\n * run waf configure --%s=xxx' + + src = getattr(Params.g_options, SRCDIR, None) + if not src: src = getattr(Utils.g_module, SRCDIR, None) + if not src: fatal(err % (SRCDIR, os.path.abspath('.'), SRCDIR, SRCDIR)) + + bld = getattr(Params.g_options, BLDDIR, None) + if not bld: bld = getattr(Utils.g_module, BLDDIR, None) + if not bld: fatal(err % (BLDDIR, os.path.abspath('.'), BLDDIR, BLDDIR)) + + Params.g_cachedir = os.path.join(bld, CACHE_DIR) + tree.load_dirs(src, bld, isconfigure=1) + + conf = Configure.Configure(srcdir=src, blddir=bld) + try: + # calling to main wscript's configure() + conf.sub_config('') + except Configure.ConfigurationError, e: + fatal(str(e), 2) + except Exception: + Utils.test_full() + raise + + conf.store(tree) + conf.cleanup() + + # this will write a configure lock so that subsequent run will + # consider the current path as the root directory, to remove: use 'waf distclean' + file = open(g_lockfile, 'w') + file.write + + proj = {} + proj[BLDDIR] = bld + proj[SRCDIR] = src + proj['argv'] = sys.argv[1:] + proj['hash'] = conf.hash + proj['files'] = conf.files + cPickle.dump(proj, file) + file.close() + + # restore -j option + Params.g_options.jobs = jobs_save + +def read_cache_file(filename): + file = open(g_lockfile, 'r') + proj = cPickle.load(file) + file.close() + return proj + +def prepare(): + # some command-line options can be processed immediately + if '--version' in sys.argv: + opt_obj = Options.Handler() + opt_obj.parse_args() + sys.exit(0) + + # now find the wscript file + msg1 = 'Waf: *** Nothing to do! Please run waf from a directory containing a file named "%s"' % WSCRIPT_FILE + + # Some people want to configure their projects gcc-style: + # mkdir build && cd build && ../waf configure && ../waf + # check that this is really what is wanted + build_dir_override = None + candidate = None + + cwd = Params.g_cwd_launch + lst = os.listdir(cwd) + xml = 0 + + #check if a wscript or a wscript_xml file is in current directory + if WSCRIPT_FILE in lst or WSCRIPT_BUILD_FILE in lst or 'wscript_xml' in lst: + # if a script is in current directory, use this directory as candidate (and prevent gcc-like configuration) + candidate = cwd + elif 'configure' in sys.argv: + # gcc-like configuration + build_dir_override = cwd + + try: + #check the following dirs for wscript or wscript_xml + search_for_candidate = True + if not candidate: + #check first the calldir if there is wscript or wscript_xml + #for example: /usr/src/configure the calldir would be /usr/src + calldir = os.path.abspath(os.path.dirname(sys.argv[0])) + lst_calldir = os.listdir(calldir) + if WSCRIPT_FILE in lst_calldir: + candidate = calldir + search_for_candidate = False + if 'wscript_xml' in lst_calldir: + candidate = calldir + xml = 1 + search_for_candidate = False + if "--make-waf" in sys.argv and candidate: + search_for_candidate = False + + #check all directories above current dir for wscript or wscript_xml if still not found + while search_for_candidate: + if len(cwd) <= 3: + break # stop at / or c: + dirlst = os.listdir(cwd) + if WSCRIPT_FILE in dirlst: + candidate = cwd + xml = 0 + if 'wscript_xml' in dirlst: + candidate = cwd + xml = 1 + break + if 'configure' in sys.argv and candidate: + break + if Params.g_lockfile in dirlst: + break + cwd = cwd[:cwd.rfind(os.sep)] # climb up + except Exception: + traceback.print_stack() + fatal(msg1) + + if not candidate: + # check if the user only wanted to display the help + if '-h' in sys.argv or '--help' in sys.argv: + warning('No wscript file found: the help message may be incomplete') + opt_obj = Options.Handler() + opt_obj.parse_args() + sys.exit(0) + else: + fatal(msg1) + + # We have found wscript, but there is no guarantee that it is valid + os.chdir(candidate) + + if xml: + # the xml module is not provided by default, you will have to import it yourself + from XMLScripting import compile + compile(candidate+os.sep+'wscript_xml') + else: + # define the main module containing the functions init, shutdown, .. + Utils.set_main_module(os.path.join(candidate, WSCRIPT_FILE)) + + if build_dir_override: + d = getattr(Utils.g_module, BLDDIR, None) + if d: + # test if user has set the blddir in wscript. + msg = 'Overriding build directory %s with %s' % (d, build_dir_override) + Params.niceprint(msg, 'WARNING', 'waf') + Utils.g_module.blddir = build_dir_override + + # fetch the custom command-line options recursively and in a procedural way + opt_obj = Options.Handler() + # will call to main wscript's set_options() + opt_obj.sub_options('') + opt_obj.parse_args() + + # use the parser results + if Params.g_commands['dist']: + # try to use the user-defined dist function first, fallback to the waf scheme + fun = getattr(Utils.g_module, 'dist', None) + if fun: fun(); sys.exit(0) + + appname = getattr(Utils.g_module, APPNAME, 'noname') + + get_version = getattr(Utils.g_module, 'get_version', None) + if get_version: version = get_version() + else: version = getattr(Utils.g_module, VERSION, None) + if not version: version = '1.0' + + from Scripting import Dist + Dist(appname, version) + sys.exit(0) + elif Params.g_commands['distclean']: + # try to use the user-defined distclean first, fallback to the waf scheme + fun = getattr(Utils.g_module, 'distclean', None) + if fun: fun() + else: DistClean() + sys.exit(0) + elif Params.g_commands['distcheck']: + # try to use the user-defined dist function first, fallback to the waf scheme + fun = getattr(Utils.g_module, 'dist', None) + if fun: fun(); sys.exit(0) + + appname = getattr(Utils.g_module, APPNAME, 'noname') + + get_version = getattr(Utils.g_module, 'get_version', None) + if get_version: version = get_version() + else: version = getattr(Utils.g_module, VERSION, None) + if not version: version = '1.0' + + DistCheck(appname, version) + sys.exit(0) + + fun=getattr(Utils.g_module, 'init', None) + if fun: fun() + + main() + +def main(): + import inspect + if Params.g_commands['configure']: + configure() + Params.pprint('GREEN', 'Configuration finished successfully; project is now ready to build.') + sys.exit(0) + + Runner.set_exec('noredir') + + # compile the project and/or install the files + bld = Build.Build() + try: + proj = read_cache_file(g_lockfile) + except IOError: + if Params.g_commands['clean']: + fatal("Nothing to clean (project not configured)", ret=0) + else: + warning("Run waf configure first (project not configured)") + if Params.g_autoconfig: + configure() + bld = Build.Build() + proj = read_cache_file(g_lockfile) + else: + sys.exit(0) + + if Params.g_autoconfig: + reconf = 0 + hash = 0 + try: + for file in proj['files']: + mod = Utils.load_module(file) + hash = Params.hash_function_with_globals(hash, mod.configure) + reconf = (hash != proj['hash']) + except Exception, ex: + if Params.g_verbose: + traceback.print_exc() + warning("Reconfiguring the project (an exception occured: %s)" % (str(ex),)) + reconf = 1 + + if reconf: + warning("Reconfiguring the project (the configuration has changed)") + + a1 = Params.g_commands + a2 = Params.g_options + a3 = Params.g_zones + a4 = Params.g_verbose + + Options.g_parser.parse_args(args=proj['argv']) + configure() + + Params.g_commands = a1 + Params.g_options = a2 + Params.g_zones = a3 + Params.g_verbose = a4 + + bld = Build.Build() + proj = read_cache_file(g_lockfile) + + Params.g_cachedir = os.path.join(proj[BLDDIR], CACHE_DIR) + + bld.load_dirs(proj[SRCDIR], proj[BLDDIR]) + bld.load_envs() + + try: + # calling to main wscript's build() + f = Utils.g_module.build + except AttributeError: + fatal("Could not find the function 'def build(bld):' in wscript") + else: + f(bld) + + # TODO undocumented hook + pre_build = getattr(Utils.g_module, 'pre_build', None) + if pre_build: pre_build() + + # compile + if Params.g_commands['build'] or Params.g_install: + try: + + # TODO quite ugly, no? + if not Params.g_commands['build'] and not Params.g_commands['install']: + import Task + def must_run(self): + return 0 + setattr(Task.Task, 'must_run', must_run) + + bld.compile() + #import cProfile, pstats + #cProfile.run("Params.g_build.compile()", 'profi.txt') + #p = pstats.Stats('profi.txt') + #p.sort_stats('time').print_stats(20) + + except Build.BuildError, e: + if not Params.g_options.daemon: fatal(e.get_message(), 1) + else: error(e.get_message()) + else: + if Params.g_options.progress_bar: print '' + + if Params.g_commands['install'] or Params.g_commands['uninstall']: + bld.install() + + if Params.g_commands['install']: msg = 'Compilation and installation finished successfully' + elif Params.g_commands['uninstall']: msg = 'Uninstallation finished successfully' + else: msg = 'Compilation finished successfully' + Params.pprint('GREEN', msg) + + # clean + if Params.g_commands['clean']: + try: + bld.clean() + Params.pprint('GREEN', 'Cleaning finished successfully') + finally: + bld.save() + #if ret: + # msg='Cleanup failed for a mysterious reason' + # error(msg) + + # daemon look here + if Params.g_options.daemon and Params.g_commands['build']: + start_daemon() + return + + # shutdown + fun = getattr(Utils.g_module, 'shutdown', None) + if fun: fun() + + +## Note: this is a modified version of shutil.copytree from python +## 2.5.2 library; modified for WAF purposes to exclude dot dirs and +## another list of files. +def copytree(src, dst, symlinks=False, excludes=(), build_dir=None): + names = os.listdir(src) + os.makedirs(dst) + errors = [] + for name in names: + srcname = os.path.join(src, name) + dstname = os.path.join(dst, name) + try: + if symlinks and os.path.islink(srcname): + linkto = os.readlink(srcname) + os.symlink(linkto, dstname) + elif os.path.isdir(srcname): + if name in excludes: + continue + elif name.startswith('.') or name.startswith(',,') or name.startswith('++'): + continue + elif name == build_dir: + continue + else: + ## build_dir is not passed into the recursive + ## copytree, but that is intentional; it is a + ## directory name valid only at the top level. + copytree(srcname, dstname, symlinks, excludes) + else: + ends = name.endswith + to_remove = False + if name.startswith('.') or name.startswith('++'): + to_remove = True + else: + for x in g_dist_exts: + if ends(x): + to_remove = True + break + if not to_remove: + shutil.copy2(srcname, dstname) + # XXX What about devices, sockets etc.? + except (IOError, os.error), why: + errors.append((srcname, dstname, str(why))) + # catch the Error from the recursive copytree so that we can + # continue with other files + except shutil.Error, err: + errors.extend(err.args[0]) + try: + shutil.copystat(src, dst) + except WindowsError: + # can't copy file access times on Windows + pass + except OSError, why: + errors.extend((src, dst, str(why))) + if errors: + raise shutil.Error, errors + + +def DistDir(appname, version): + "make a distribution directory with all the sources in it" + + # Our temporary folder where to put our files + TMPFOLDER=appname+'-'+version + + # Remove an old package directory + if os.path.exists(TMPFOLDER): shutil.rmtree(TMPFOLDER) + + global g_dist_exts, g_excludes + + # Remove the Build dir + build_dir = getattr(Utils.g_module, BLDDIR, None) + + # Copy everything into the new folder + copytree('.', TMPFOLDER, excludes=g_excludes, build_dir=build_dir) + + # TODO undocumented hook + dist_hook = getattr(Utils.g_module, 'dist_hook', None) + if dist_hook: + os.chdir(TMPFOLDER) + try: + dist_hook() + finally: + # go back to the root directory + os.chdir('..') + return TMPFOLDER + +def DistTarball(appname, version): + """make a tarball with all the sources in it; return (distdirname, tarballname)""" + import tarfile + + TMPFOLDER = DistDir(appname, version) + tar = tarfile.open(TMPFOLDER+'.tar.'+g_gz,'w:'+g_gz) + tar.add(TMPFOLDER) + tar.close() + Params.pprint('GREEN', 'Your archive is ready -> %s.tar.%s' % (TMPFOLDER, g_gz)) + + if os.path.exists(TMPFOLDER): shutil.rmtree(TMPFOLDER) + return (TMPFOLDER, TMPFOLDER+'.tar.'+g_gz) + +def Dist(appname, version): + """make a tarball with all the sources in it""" + DistTarball(appname, version) + sys.exit(0) + +def DistClean(): + """clean the project""" + + # remove the temporary files + # the builddir is given by lock-wscript only + # we do no try to remove it if there is no lock file (rmtree) + for (root, dirs, filenames) in os.walk('.'): + for f in list(filenames): + to_remove = 0 + if f==g_lockfile: + # removes a lock, and the builddir indicated + to_remove = True + try: + proj = read_cache_file(os.path.join(root, f)) + shutil.rmtree(os.path.join(root, proj[BLDDIR])) + except (OSError, IOError): + # ignore errors if the lockfile or the builddir not exist. + pass + else: + ends = f.endswith + for x in g_distclean_exts: + if ends(x): + to_remove = 1 + break + if to_remove: + os.remove(os.path.join(root, f)) + lst = os.listdir('.') + for f in lst: + if f.startswith('.waf-'): + shutil.rmtree(f, ignore_errors=True) + sys.exit(0) + +def DistCheck(appname, version): + """Makes some sanity checks on the waf dist generated tarball""" + import tempfile + import pproc as subprocess + + waf = os.path.abspath(sys.argv[0]) + distdir, tarball = DistTarball(appname, version) + retval = subprocess.Popen('bzip2 -dc %s | tar x' % tarball, shell=True).wait() + if retval: + Params.fatal('uncompressing the tarball failed with code %i' % (retval)) + + instdir = tempfile.mkdtemp('.inst', '%s-%s' % (appname, version)) + cwd_before = os.getcwd() + os.chdir(distdir) + try: + retval = subprocess.Popen( + '%(waf)s configure && %(waf)s ' + '&& %(waf)s check && %(waf)s install --destdir=%(instdir)s' + ' && %(waf)s uninstall --destdir=%(instdir)s' % vars(), + shell=True).wait() + if retval: + Params.fatal('distcheck failed with code %i' % (retval)) + finally: + os.chdir(cwd_before) + shutil.rmtree(distdir) + if os.path.exists(instdir): + Params.fatal("distcheck succeeded, but files were left in %s" % (instdir)) + else: + Params.pprint('GREEN', "distcheck finished successfully") + + diff -Nru zyn-1+git.20100609/wafadmin/Task.py zyn-1+git.20100609+dfsg0/wafadmin/Task.py --- zyn-1+git.20100609/wafadmin/Task.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Task.py 2008-03-23 19:05:48.000000000 +0000 @@ -0,0 +1,455 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2005-2008 (ita) + +"Atomic operations that create nodes or execute commands" + +import os, types, shutil +try: from hashlib import md5 +except ImportError: from md5 import md5 +import Params, Scan, Action, Runner, Common +from Params import debug, error, warning + +class TaskManager(object): + """The manager is attached to the build object, it holds a list of TaskGroup + Each TaskGroup contains a map(priority, list of tasks)""" + def __init__(self): + self.groups = [] + self.idx = 0 + self.tasks_done = [] + def flush(self): + for k in self.groups: + k.flush() + def add_group(self, name=''): + if not name: + size = len(self.groups) + name = 'group-%d' % size + if not self.groups: + self.groups = [TaskGroup(name)] + return + if not self.groups[0].tasks: + warning('add_group: an empty group is already present') + return + self.groups = self.groups + [TaskGroup(name)] + def add_task(self, task): + if not self.groups: self.add_group('group-0') + task.m_idx = self.idx + self.idx += 1 + self.groups[-1].add_task(task) + def total(self): + total = 0 + if not self.groups: return 0 + for group in self.groups: + total += len(group.tasks) + #for p in group.prio: + # total += len(group.prio[p]) + return total + def debug(self): + for i in self.groups: + print "-----group-------", i.name + for j in i.prio: + print "prio: ", j, str(i.prio[j]) + def add_finished(self, tsk): + self.tasks_done.append(tsk) + # TODO we could install using threads here + if Params.g_install and hasattr(tsk, 'install'): + d = tsk.install + + if type(d) is types.FunctionType: + d(tsk) + elif type(d) is types.StringType: + if not tsk.env()[d]: return + lst = [a.relpath_gen(Params.g_build.m_srcnode) for a in tsk.m_outputs] + Common.install_files(tsk.env()[d], '', lst, chmod=0644, env=tsk.env()) + else: + if not d['var']: return + lst = [a.relpath_gen(Params.g_build.m_srcnode) for a in tsk.m_outputs] + if d.get('src', 0): lst += [a.relpath_gen(Params.g_build.m_srcnode) for a in tsk.m_inputs] + # TODO ugly hack + if d.get('as', ''): + Common.install_as(d['var'], d['dir']+d['as'], lst[0], chmod=d.get('chmod', 0644), env=tsk.env()) + else: + Common.install_files(d['var'], d['dir'], lst, chmod=d.get('chmod', 0644), env=tsk.env()) + +class TaskGroup(object): + "A TaskGroup maps priorities (integers) to lists of tasks" + def __init__(self, name): + self.name = name + self.info = '' + self.tasks = [] + self.prio = {} + def add_task(self, task): + try: self.tasks.append(task) + except KeyError: self.tasks = [task] + def flush(self): + # FIXME TODO in the future we will allow to go back in the past + for x in self.tasks: + try: p = getattr(x, 'prio') + except AttributeError: + try: p = x.m_action.prio + except AttributeError: p = 100 + try: self.prio[p].append(x) + except KeyError: self.prio[p] = [x] + +class TaskBase(object): + "TaskBase is the base class for task objects" + def __init__(self, normal=1): + self.m_display = '' + self.m_hasrun=0 + + manager = Params.g_build.task_manager + if normal: + manager.add_task(self) + else: + self.m_idx = manager.idx + manager.idx += 1 + def may_start(self): + "non-zero if the task is ready" + return 1 + def must_run(self): + "0 if the task does not need to run" + return 1 + def prepare(self): + "prepare the task for further processing" + pass + def update_stat(self): + "update the dependency tree (node stats)" + pass + def debug_info(self): + "return debug info" + return '' + def debug(self): + "prints the debug info" + pass + def run(self): + "process the task" + pass + def color(self): + "color to use for the console messages" + return 'BLUE' + def set_display(self, v): + self.m_display = v + def get_display(self): + return self.m_display + +class Task(TaskBase): + "The most common task, it has input and output nodes" + def __init__(self, action_name, env, normal=1, prio=None): + TaskBase.__init__(self, normal=normal) + + # name of the action associated to this task type + self.m_action = Action.g_actions[action_name] + if not (prio is None): self.prio = prio + + # environment in use + self.m_env = env + + # inputs and outputs are nodes + # use setters when possible + self.m_inputs = [] + self.m_outputs = [] + + self.m_deps_nodes = [] + self.m_run_after = [] + + # Additionally, you may define the following + #self.dep_vars = 'PREFIX DATADIR' + #self.m_scanner = some_scanner_object + + def env(self): + # TODO IDEA in the future, attach the task generator instead of the env + return self.m_env + + def __repr__(self): + return "".join(['\n\t{task: ', self.m_action.m_name, " ", ",".join([x.m_name for x in self.m_inputs]), " -> ", ",".join([x.m_name for x in self.m_outputs]), '}']) + + def set_inputs(self, inp): + if type(inp) is types.ListType: self.m_inputs += inp + else: self.m_inputs.append(inp) + + def set_outputs(self, out): + if type(out) is types.ListType: self.m_outputs += out + else: self.m_outputs.append(out) + + def set_run_after(self, task): + "set (scheduler) dependency on another task" + # TODO: handle list or object + assert isinstance(task, TaskBase) + self.m_run_after.append(task) + + def get_run_after(self): + try: return self.m_run_after + except AttributeError: return [] + + def add_file_dependency(self, filename): + "TODO user-provided file dependencies" + node = Params.g_build.m_current.find_build(filename) + self.m_deps_nodes.append(node) + + #------------ users are probably less interested in the following methods --------------# + + def signature(self): + # compute the result one time, and suppose the scanner.get_signature will give the good result + try: return self.sign_all + except AttributeError: pass + + env = self.env() + tree = Params.g_build + + m = md5() + + # TODO maybe we could split this dep sig into two parts (nodes, dependencies) + # this would only help for debugging though + dep_sig = Params.sig_nil + scan = getattr(self, 'm_scanner', None) + if scan: + dep_sig = scan.get_signature(self) + m.update(dep_sig) + else: + # compute the signature from the inputs (no scanner) + for x in self.m_inputs: + v = tree.m_tstamp_variants[x.variant(env)][x] + dep_sig = hash( (dep_sig, v) ) + m.update(v) + + # manual dependencies, they can slow down the builds + try: + additional_deps = tree.deps_man + for x in self.m_inputs + self.m_outputs: + try: + d = additional_deps[x] + except KeyError: + continue + if callable(d): d = d() # dependency is a function, call it + dep_sig = hash( (dep_sig, d) ) + m.update(d) + except AttributeError: + pass + + # dependencies on the environment vars + fun = getattr(self.m_action, 'signature', None) + if fun: act_sig = self.m_action.signature(self) + else: act_sig = env.sign_vars(self.m_action.m_vars) + m.update(act_sig) + + # additional variable dependencies, if provided + var_sig = None + dep_vars = getattr(self, 'dep_vars', None) + if dep_vars: + var_sig = env.sign_vars(dep_vars) + m.update(var_sig) + + # additional nodes to depend on, if provided + node_sig = Params.sig_nil + dep_nodes = getattr(self, 'dep_nodes', []) + for x in dep_nodes: + variant = x.variant(env) + v = tree.m_tstamp_variants[variant][x] + node_sig = hash( (node_sig, v) ) + m.update(v) + + # we now have the array of signatures + ret = m.digest() + self.cache_sig = [ret, dep_sig, act_sig, var_sig, node_sig] + + # TODO can be dangerous + self.sign_all = ret + return ret + + def may_start(self): + "wait for other tasks to complete" + if (not self.m_inputs) or (not self.m_outputs): + if not (not self.m_inputs) and (not self.m_outputs): + error("potentially grave error, task is invalid : no inputs or outputs") + self.debug() + + # the scanner has its word to say + scan = getattr(self, 'm_scanner', None) + if scan: + fun = getattr(scan, 'may_start', None) + if fun: + if not fun(self): + return 0 + + # this is a dependency using the scheduler, as opposed to hash-based ones + for t in self.get_run_after(): + if not t.m_hasrun: + return 0 + return 1 + + def must_run(self): + "see if the task must be run or not" + #return 0 # benchmarking + + env = self.env() + tree = Params.g_build + + # tasks that have no inputs or outputs are run each time + if not self.m_inputs and not self.m_outputs: + self.m_dep_sig = Params.sig_nil + return 1 + + # look at the previous signature first + node = self.m_outputs[0] + variant = node.variant(env) + try: + time = tree.m_tstamp_variants[variant][node] + except KeyError: + debug("task #%d should run as the first node does not exist" % self.m_idx, 'task') + try: new_sig = self.signature() + except KeyError: + print "TODO - computing the signature failed" + return 1 + + ret = self.can_retrieve_cache(new_sig) + return not ret + + key = hash( (variant, node, time, getattr(self, 'm_scanner', self).__class__.__name__) ) + prev_sig = tree.m_sig_cache[key][0] + #print "prev_sig is ", prev_sig + new_sig = self.signature() + + # debug if asked to + if Params.g_zones: self.debug_why(tree.m_sig_cache[key]) + + if new_sig != prev_sig: + # try to retrieve the file from the cache + ret = self.can_retrieve_cache(new_sig) + return not ret + + return 0 + + def update_stat(self): + "called after a sucessful task run" + tree = Params.g_build + env = self.env() + sig = self.signature() + + cnt = 0 + for node in self.m_outputs: + variant = node.variant(env) + #if node in tree.m_tstamp_variants[variant]: + # print "variant is ", variant + # print "self sig is ", Params.view_sig(tree.m_tstamp_variants[variant][node]) + + # check if the node exists .. + os.stat(node.abspath(env)) + + # important, store the signature for the next run + tree.m_tstamp_variants[variant][node] = sig + + # We could re-create the signature of the task with the signature of the outputs + # in practice, this means hashing the output files + # this is unnecessary + if Params.g_cache_global: + ssig = sig.encode('hex') + dest = os.path.join(Params.g_cache_global, ssig+'-'+str(cnt)) + try: shutil.copy2(node.abspath(env), dest) + except IOError: warning('could not write the file to the cache') + cnt += 1 + + # keep the signatures in the first node + node = self.m_outputs[0] + variant = node.variant(env) + time = tree.m_tstamp_variants[variant][node] + key = hash( (variant, node, time, getattr(self, 'm_scanner', self).__class__.__name__) ) + val = self.cache_sig + tree.set_sig_cache(key, val) + + self.m_executed=1 + + def can_retrieve_cache(self, sig): + """Retrieve build nodes from the cache - the file time stamps are updated + for cleaning the least used files from the cache dir - be careful when overriding""" + if not Params.g_cache_global: return None + if Params.g_options.nocache: return None + + env = self.env() + sig = self.signature() + + cnt = 0 + for node in self.m_outputs: + variant = node.variant(env) + + ssig = sig.encode('hex') + orig = os.path.join(Params.g_cache_global, ssig+'-'+str(cnt)) + try: + shutil.copy2(orig, node.abspath(env)) + os.utime(orig, None) + # mark the cache file as used recently (modified) + except (OSError, IOError): + debug("failed retrieving file", 'task') + return None + else: + cnt += 1 + Params.g_build.m_tstamp_variants[variant][node] = sig + if not Runner.g_quiet: Params.pprint('GREEN', 'restored from cache %s' % node.bldpath(env)) + return 1 + + def prepare(self): + try: self.m_action.prepare(self) + except AttributeError: pass + + def run(self): + return self.m_action.run(self) + + def get_display(self): + if self.m_display: return self.m_display + self.m_display=self.m_action.get_str(self) + return self.m_display + + def color(self): + return self.m_action.m_color + + def debug_info(self): + ret = [] + ret.append('-- task details begin --') + ret.append('action: %s' % str(self.m_action)) + ret.append('idx: %s' % str(self.m_idx)) + ret.append('source: %s' % str(self.m_inputs)) + ret.append('target: %s' % str(self.m_outputs)) + ret.append('-- task details end --') + return '\n'.join(ret) + + def debug(self, level=0): + fun = Params.debug + if level>0: fun = Params.error + fun(self.debug_info()) + + def debug_why(self, old_sigs): + "explains why a task is run" + + new_sigs = self.cache_sig + v = Params.view_sig + + debug("Task %s must run: %s" % (self.m_idx, old_sigs[0] != new_sigs[0]), 'task') + if (new_sigs[1] != old_sigs[1]): + debug(' -> A source file (or a dependency) has changed %s %s' % (v(old_sigs[1]), v(new_sigs[1])), 'task') + if (new_sigs[2] != old_sigs[2]): + debug(' -> An environment variable has changed %s %s' % (v(old_sigs[2]), v(new_sigs[2])), 'task') + if (new_sigs[3] != old_sigs[3]): + debug(' -> A manual dependency has changed %s %s' % (v(old_sigs[3]), v(new_sigs[3])), 'task') + if (new_sigs[4] != old_sigs[4]): + debug(' -> A user-given environment variable has changed %s %s' % (v(old_sigs[4]), v(new_sigs[4])), 'task') + +class TaskCmd(TaskBase): + "TaskCmd executes commands. Instances always execute their function" + def __init__(self, fun, env): + TaskBase.__init__(self) + self.fun = fun + self.m_env = env + def prepare(self): + self.m_display = "* executing: %s" % self.fun.__name__ + def debug_info(self): + return 'TaskCmd:fun %s' % self.fun.__name__ + def debug(self): + return 'TaskCmd:fun %s' % self.fun.__name__ + def run(self): + self.fun(self) + def env(self): + return self.m_env + + diff -Nru zyn-1+git.20100609/wafadmin/Tools/ar.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/ar.py --- zyn-1+git.20100609/wafadmin/Tools/ar.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/ar.py 2008-03-23 19:05:47.000000000 +0000 @@ -0,0 +1,49 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2006-2008 (ita) +# Ralf Habacker, 2006 (rh) + +"ar and ranlib" + +import os, sys +import Action + +ar_str = '${AR} ${ARFLAGS} ${TGT} ${SRC} && ${RANLIB} ${RANLIBFLAGS} ${TGT}' + +# FIXME +if sys.platform == "win32": + ar_str = '${AR} s${ARFLAGS} ${TGT} ${SRC}' +Action.simple_action('ar_link_static', ar_str, color='YELLOW', prio=101) + +def detect(conf): + comp = conf.find_program('ar', var='AR') + if not comp: return + + ranlib = conf.find_program('ranlib', var='RANLIB') + if not ranlib: return + + v = conf.env + v['AR'] = comp + v['ARFLAGS'] = 'r' + v['RANLIB'] = ranlib + v['RANLIBFLAGS'] = '' + +def find_ar(conf): + v = conf.env + conf.check_tool('ar') + if not v['AR']: conf.fatal('ar is required for static libraries - not found') + +def find_cpp(conf): + v = conf.env + cpp = None + if v['CPP']: cpp = v['CPP'] + elif 'CPP' in os.environ: cpp = os.environ['CPP'] + if not cpp: cpp = conf.find_program('cpp', var='CPP') + if not cpp: cpp = v['CC'] + if not cpp: cpp = v['CXX'] + v['CPP'] = cpp + + diff -Nru zyn-1+git.20100609/wafadmin/Tools/batched_cc.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/batched_cc.py --- zyn-1+git.20100609/wafadmin/Tools/batched_cc.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/batched_cc.py 2008-03-23 20:35:44.000000000 +0000 @@ -0,0 +1,121 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2006 (ita) + +""" +Batched builds - compile faster +instead of compiling object files one by one, c/c++ compilers are often able to compile at once: +cc -c ../file1.c ../file2.c ../file3.c + +Files are output on the directory where the compiler is called, and dependencies are more difficult +to track (do not run the command on all source files if only one file changes) + +As such, we do as if the files were compiled one by one, but no command is actually run: +replace each cc/cpp Task by a TaskSlave +A new task called TaskMaster collects the signatures from each slave and finds out the command-line +to run. + +To set this up, the method ccroot::create_task is replaced by a new version, to enable batched builds +it is only necessary to import this module in the configuration (no other change required) +""" + +EXT_C = ['.c', '.cc', '.cpp', '.cxx'] + +import shutil, os +import Action, Object, Task, ccroot, Params +from Object import extension + +class TaskMaster(Task.Task): + def __init__(self, action_name, env, priority=92, normal=1, master=None): + Task.Task.__init__(self, action_name, env, prio=priority, normal=normal) + self.slaves=[] + self.m_inputs2=[] + self.m_outputs2=[] + + def add_slave(self, slave): + self.slaves.append(slave) + self.set_run_after(slave) + + def may_start(self): + for t in self.m_run_after: + if not t.m_hasrun: return 0 + + for t in self.slaves: + self.m_inputs.append(t.m_inputs[0]) + self.m_outputs.append(t.m_outputs[0]) + if t.m_must_run: + self.m_inputs2.append(t.m_inputs[0]) + self.m_outputs2.append(t.m_outputs[0]) + return 1 + + def run(self): + tmpinputs = self.m_inputs + self.m_inputs = self.m_inputs2 + tmpoutputs = self.m_outputs + self.m_outputs = self.m_outputs2 + + ret = self.m_action.run(self) + env = self.env() + + rootdir = Params.g_build.m_srcnode.abspath(env) + + # unfortunately building the files in batch mode outputs them in the current folder (the build dir) + # now move the files from the top of the builddir to the correct location + for i in self.m_outputs: + name = i.m_name + if name[-1] == "s": name = name[:-1] # extension for shlib is .os, remove the s + shutil.move(name, i.bldpath(env)) + + self.m_inputs = tmpinputs + self.m_outputs = tmpoutputs + + return ret + +class TaskSlave(Task.Task): + def __init__(self, action_name, env, priority=90, normal=1, master=None): + Task.Task.__init__(self, action_name, env, priority, normal) + self.m_master = master + + def get_display(self): + return "* skipping "+ self.m_inputs[0].m_name + + def update_stat(self): + self.m_executed=1 + + def must_run(self): + self.m_must_run = Task.Task.must_run(self) + return self.m_must_run + + def run(self): + return 0 + + def can_retrieve_cache(self, sig): + return None + +def create_task_cxx_new(self, node): + try: + mm = self.mastertask + except AttributeError: + mm = TaskMaster("all_"+self.m_type_initials, self.env) + self.mastertask = mm + + task = TaskSlave(self.m_type_initials, self.env, 40, master=mm) + self.m_tasks.append(task) + mm.add_slave(task) + + task.set_inputs(node) + task.set_outputs(node.change_ext('.o')) + + self.compiled_tasks.append(task) + +cc_str = '${CC} ${CCFLAGS} ${CPPFLAGS} ${_CCINCFLAGS} ${_CCDEFFLAGS} -c ${SRC}' +Action.simple_action('all_cc', cc_str, 'GREEN') + +cpp_str = '${CXX} ${CXXFLAGS} ${CPPFLAGS} ${_CXXINCFLAGS} ${_CXXDEFFLAGS} -c ${SRC}' +Action.simple_action('all_cpp', cpp_str, color='GREEN') + + +extension(EXT_C)(create_task_cxx_new) diff -Nru zyn-1+git.20100609/wafadmin/Tools/bison.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/bison.py --- zyn-1+git.20100609/wafadmin/Tools/bison.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/bison.py 2008-03-23 19:05:47.000000000 +0000 @@ -0,0 +1,33 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# John O'Meara, 2006 + +"Bison processing" + +import Object + +def decide_ext(self, node): + c_ext = '.tab.c' + if node.m_name.endswith('.yc'): c_ext = '.tab.cc' + if '-d' in self.env['BISONFLAGS']: + return [c_ext, c_ext.replace('c', 'h')] + else: + return c_ext + +Object.declare_chain( + name = 'bison', + action = 'cd ${SRC[0].bld_dir(env)} && ${BISON} ${BISONFLAGS} ${SRC[0].abspath()} -o ${TGT[0].m_name}', + ext_in = ['.y', '.yc'], + ext_out = decide_ext +) + +def detect(conf): + bison = conf.find_program('bison', var='BISON') + if not bison: conf.fatal("bison was not found") + v = conf.env + v['BISONFLAGS'] = '-d' + + diff -Nru zyn-1+git.20100609/wafadmin/Tools/boost.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/boost.py --- zyn-1+git.20100609/wafadmin/Tools/boost.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/boost.py 2008-03-23 19:05:47.000000000 +0000 @@ -0,0 +1,226 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Gernot Vormayr, 2008 + +""" +Quick n dirty boost detections +""" + +import os, glob, types +import Params, Configure +from Params import fatal + +def detect_boost(conf): + env = conf.env + opt = Params.g_options + + want_asio = 0 + + if env['WANT_BOOST']: + if type(env['WANT_BOOST']) is types.StringType: + want_libs = env['WANT_BOOST'].split() + else: + want_libs = env['WANT_BOOST'] + if want_libs.count('ASIO'): + want_libs.remove('ASIO') + want_asio=1 + if want_libs.count('ASIO_MT'): + want_libs.remove('ASIO_MT') + want_asio=2 + else: + want_libs = 0 + + boostlibs = getattr(opt, 'boostlibs', '') + boostincludes = getattr(opt, 'boostincludes', '') + asioincludes = getattr(opt, 'asioincludes', '') + boostfolder = getattr(opt, 'boostfolder', '') + + if boostfolder: + boostincludes=boostfolder+'/include' + boostlibs=boostfolder+'/lib' + + #let's try to find boost which is not easy, cause boost seems like it wants to hide :( + if not boostincludes: + boostincludes= ['/sw/include', '/usr/local/include', '/opt/include', '/opt/local/include', '/usr/include'] + else: + boostincludes=[boostincludes] + guess=[] + for dir in boostincludes: + try: + for subdir in os.listdir(dir): + # we have to check for boost or boost-version cause there are systems + # which put boost directly into a boost subdir (eg. gentoo) + if subdir=='boost': guess.append(dir) + elif subdir.startswith('boost-'): guess.append(dir+'/'+subdir) + except OSError: pass + if not guess: + fatal('boost headers not found') + return 0 + versions={} + for dir in guess: + test_obj = Configure.check_data() + test_obj.code = '#include \n#include \nint main() { std::cout << BOOST_VERSION << std::endl; return 0; }\n' + test_obj.env = env + test_obj.env['CPPPATH']=[dir] + test_obj.execute = 1 + test_obj.force_compiler='cpp' + ret=conf.run_check(test_obj) + if ret: + versions[int(ret['result'])]=dir + version=versions.keys() + + errtext='' + + if env['WANT_BOOST_MIN']: + errtext+='>= '+env['WANT_BOOST_MIN']+' ' + min_version=env['WANT_BOOST_MIN'].split('.') + min_version=int(min_version[0])*100000+int(min_version[1])*100+int(min_version[2]) + version=filter(lambda x:x>=min_version,version) + if env['WANT_BOOST_MAX']: + errtext+='<= '+env['WANT_BOOST_MAX']+' ' + max_version=env['WANT_BOOST_MAX'].split('.') + max_version=int(max_version[0])*100000+int(max_version[1])*100+int(max_version[2]) + version=filter(lambda x:x<=max_version,version) + + version.sort() + if len(version) is 0: + fatal('No boost '+errtext+'found!') + + version=version.pop() + boost_includes=versions[version] + version="%d.%d.%d" % (version/100000,version/100%1000,version%100) + conf.check_message('header','boost/version.hpp',1,'Version '+boost_includes+' ('+version+')') + env['CPPPATH_BOOST']=boost_includes + + # search vor asio + if want_asio: + errtext='' + asio_version=min_version=max_version=0 + if env['WANT_ASIO_MIN']: + errtext+='>= '+env['WANT_ASIO_MIN']+' ' + min_version=env['WANT_ASIO_MIN'].split('.') + min_version=int(min_version[0])*100000+int(min_version[1])*100+int(min_version[2]) + if env['WANT_ASIO_MAX']: + errtext+='<= '+env['WANT_ASIO_MAX']+' ' + max_version=env['WANT_ASIO_MAX'].split('.') + max_version=int(max_version[0])*100000+int(max_version[1])*100+int(max_version[2]) + #first look in the boost dir - but not when asioincludes is set + if not asioincludes: + test_obj = Configure.check_data() + test_obj.code = '#include \n#include \nint main() { std::cout << BOOST_ASIO_VERSION << std::endl; return 0; }\n' + test_obj.env = env + test_obj.env['CPPPATH']=[boost_includes] + test_obj.execute = 1 + test_obj.force_compiler='cpp' + ret=conf.run_check(test_obj) + if ret: + asio_version=int(ret['result']) + if min_version and asio_versionmax_version: + asio_version=0 + if asio_version: + conf.define('BOOST_ASIO',1) + version="%d.%d.%d" % (asio_version/100000,asio_version/100%1000,asio_version%100) + conf.check_message('header','boost/asio/version.hpp',1,'Version '+version) + if want_asio==1: + if want_libs: + try: want_libs.remove('BOOST_SYSTEM') + except ValueError: pass + want_libs.append('BOOST_SYSTEM') + else: + want_libs=['BOOST_SYSTEM'] + else: + if want_libs: + try: want_libs.remove('BOOST_SYSTEM_MT') + except ValueError: pass + want_libs.append('BOOST_SYSTEM_MT') + else: + want_libs=['BOOST_SYSTEM_MT'] + #ok not in boost dir - ahh did i say ok? na imho that's not ok! + if not asio_version: + if not asioincludes: + asioincludes= ['/sw/include', '/usr/local/include', '/opt/include', '/opt/local/include', '/usr/include'] + else: + asioincludes=[asioincludes] + versions={} + for dir in asioincludes: + test_obj = Configure.check_data() + test_obj.code = '#include \n#include \nint main() { std::cout << ASIO_VERSION << std::endl; return 0; }\n' + test_obj.env = env + test_obj.env['CPPPATH']=[dir] + test_obj.execute = 1 + test_obj.force_compiler='cpp' + ret=conf.run_check(test_obj) + if ret: + versions[int(ret['result'])]=dir + version=versions.keys() + if min_version: + version=filter(lambda x:x>=min_version,version) + if max_version: + version=filter(lambda x:x<=max_version,version) + + version.sort() + if len(version) is 0: + fatal('No asio '+errtext+'found!') + + version=version.pop() + asio_includes=versions[version] + version="%d.%d.%d" % (version/100000,version/100%1000,version%100) + conf.check_message('header','asio/version.hpp',1,'Version '+asio_includes+' ('+version+')') + env['CPPPATH_ASIO']=asio_includes + env['CPPPATH_ASIO_MT']=asio_includes + conf.undefine('BOOST_ASIO') + #well now we've found our includes - let's search for the precompiled libs + if want_libs: + def check_boost_libs(libs,lib_path): + files=glob.glob(lib_path+'/libboost_*'+env['shlib_SUFFIX']) + files=map(lambda x:x[len(lib_path)+4:-len(env['shlib_SUFFIX'])] ,filter(lambda x: x.find('-d')==-1 ,files)) + for lib in libs: + libname=lib.lower() + if libname.endswith('_mt'): + libname=libname[0:-3]+'-mt' + for file in files: + if file.startswith(libname): + conf.check_message('library',libname,1,file) + env['LIBPATH_'+lib]=lib_path + env['LIB_'+lib]=file + if lib is 'BOOST_SYSTEM': + env['LIB_ASIO']=file + env['LIBPATH_ASIO']=file + elif lib is 'BOOST_SYSTEM_MT': + env['LIB_ASIO_MT']=file + env['LIBPATH_ASIO_MT']=file + break + else: + fatal('lib '+libname+' not found!') + + if not boostlibs: + boostlibs=['/usr/lib64', '/usr/lib32', '/usr/lib', '/sw/lib', '/usr/local/lib', '/opt/lib', '/opt/local/lib'] + else: + boostlibs=[boostlibs] + + lib_path=Configure.find_file_ext('libboost_*'+version+'*',boostlibs) + if lib_path=='': + lib_path=Configure.find_file_ext('libboost_*',boostlibs) + if lib_path=='': + conf.check_message('library','boost',0,'') + else: + check_boost_libs(want_libs,lib_path) + else: + check_boost_libs(want_libs,lib_path) + return 1 + +def detect(conf): + return detect_boost(conf) + +def set_options(opt): + opt.add_option('--boost-includes', type='string', default='', dest='boostincludes', help='path to the boost directory where the includes are e.g. /usr/local/include/boost-1_34_1') + opt.add_option('--boost-libs', type='string', default='', dest='boostlibs', help='path to the directory where the boost libs are e.g. /usr/local/lib') + opt.add_option('--boost', type='string', default='', dest='boostfolder', help='path to the directory where the boost lives are e.g. /usr/local') + opt.add_option('--asio-includes', type='string', default='', dest='asioincludes', help='path to asio e.g. /usr/local/include/asio') + + diff -Nru zyn-1+git.20100609/wafadmin/Tools/cc.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/cc.py --- zyn-1+git.20100609/wafadmin/Tools/cc.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/cc.py 2008-03-25 21:02:39.000000000 +0000 @@ -0,0 +1,123 @@ +#! /usr/bin/env python +# encoding: utf-8 +import sys +if sys.hexversion < 0x020400f0: from sets import Set as set +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2006 (ita) + +"Base for c programs/libraries" + +import sys +import Object, Params, Action, Utils +from Params import debug +import ccroot # <- do not remove +from Object import taskgen, before, extension + +g_cc_flag_vars = [ +'FRAMEWORK', 'FRAMEWORKPATH', +'STATICLIB', 'LIB', 'LIBPATH', 'LINKFLAGS', 'RPATH', +'INCLUDE', +'CCFLAGS', 'CPPPATH', 'CPPFLAGS', 'CCDEFINES'] + +EXT_CC = ['.c', '.cc'] +CC_METHS = ['init_cc', 'apply_type_vars', 'apply_incpaths', 'apply_dependencies', 'apply_defines_cc', +'apply_core', 'apply_lib_vars', 'apply_obj_vars_cc'] + +Object.add_feature('cc', CC_METHS) + +g_cc_type_vars = ['CCFLAGS', 'LINKFLAGS'] + +# TODO get rid of this +class cc_taskgen(ccroot.ccroot_abstract): + def __init__(self, type='program', subtype=None): + ccroot.ccroot_abstract.__init__(self, type, subtype) + self.m_type_initials = 'cc' + + self.ccflags='' + self.cppflags='' + + self.features.append('cc') + + global g_cc_type_vars + self.p_type_vars = g_cc_type_vars + +def init_cc(self): + if hasattr(self, 'p_flag_vars'): self.p_flag_vars = set(self.p_flag_vars).union(g_cc_flag_vars) + else: self.p_flag_vars = g_cc_flag_vars + + if hasattr(self, 'p_type_vars'): self.p_type_vars = set(self.p_type_vars).union(g_cc_type_vars) + else: self.p_type_vars = g_cc_type_vars + +def apply_obj_vars_cc(self): + debug('apply_obj_vars_cc', 'ccroot') + env = self.env + app = env.append_unique + cpppath_st = self.env['CPPPATH_ST'] + + self.addflags('CCFLAGS', self.ccflags) + + # local flags come first + # set the user-defined includes paths + for i in self.bld_incpaths_lst: + app('_CCINCFLAGS', cpppath_st % i.bldpath(env)) + app('_CCINCFLAGS', cpppath_st % i.srcpath(env)) + + # set the library include paths + for i in env['CPPPATH']: + app('_CCINCFLAGS', cpppath_st % i) + + # this is usually a good idea + app('_CCINCFLAGS', cpppath_st % '.') + app('_CCINCFLAGS', cpppath_st % env.variant()) + tmpnode = self.path + app('_CCINCFLAGS', cpppath_st % tmpnode.bldpath(env)) + app('_CCINCFLAGS', cpppath_st % tmpnode.srcpath(env)) + +def apply_defines_cc(self): + tree = Params.g_build + lst = self.to_list(self.defines)+self.to_list(self.env['CCDEFINES']) + milst = [] + + # now process the local defines + for defi in lst: + if not defi in milst: + milst.append(defi) + + # CCDEFINES_ + libs = self.to_list(self.uselib) + for l in libs: + val = self.env['CCDEFINES_'+l] + if val: milst += val + self.env['DEFLINES'] = ["%s %s" % (x[0], Utils.trimquotes('='.join(x[1:]))) for x in [y.split('=') for y in milst]] + y = self.env['CCDEFINES_ST'] + self.env['_CCDEFFLAGS'] = [y%x for x in milst] + +def c_hook(self, node): + # create the compilation task: cpp or cc + task = self.create_task('cc', self.env) + try: obj_ext = self.obj_ext + except AttributeError: obj_ext = '_%s.o' % self.m_type[:2] + + task.m_scanner = ccroot.g_c_scanner + task.path_lst = self.inc_paths + task.defines = self.scanner_defines + + task.m_inputs = [node] + task.m_outputs = [node.change_ext(obj_ext)] + self.compiled_tasks.append(task) + +cc_str = '${CC} ${CCFLAGS} ${CPPFLAGS} ${_CCINCFLAGS} ${_CCDEFFLAGS} ${CC_SRC_F}${SRC} ${CC_TGT_F}${TGT}' +link_str = '${LINK_CC} ${CCLNK_SRC_F}${SRC} ${CCLNK_TGT_F}${TGT} ${LINKFLAGS} ${_LIBDIRFLAGS} ${_LIBFLAGS}' + +Action.simple_action('cc', cc_str, 'GREEN', prio=100) +Action.simple_action('cc_link', link_str, color='YELLOW', prio=111) + +Object.declare_order('apply_dependencies', 'apply_defines_cc', 'apply_core', 'apply_lib_vars', 'apply_obj_vars_cc', 'apply_obj_vars') + + +taskgen(init_cc) +before('apply_type_vars')(init_cc) +taskgen(apply_obj_vars_cc) +taskgen(apply_defines_cc) +extension(EXT_CC)(c_hook) diff -Nru zyn-1+git.20100609/wafadmin/Tools/ccroot.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/ccroot.py --- zyn-1+git.20100609/wafadmin/Tools/ccroot.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/ccroot.py 2008-03-25 21:02:39.000000000 +0000 @@ -0,0 +1,453 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2005-2008 (ita) + +"base for all c/c++ programs and libraries" + +import os, sys, re +import Action, Object, Params, Scan, Common, Utils, preproc +from Params import error, debug, fatal, warning +from Object import taskgen, after, before, feature + +class DEBUG_LEVELS: + ULTRADEBUG = "ultradebug" + DEBUG = "debug" + RELEASE = "release" + OPTIMIZED = "optimized" + CUSTOM = "custom" + + ALL = [ULTRADEBUG, DEBUG, RELEASE, OPTIMIZED, CUSTOM] + +class c_scanner(Scan.scanner): + "scanner for c/c++ files" + def __init__(self): + Scan.scanner.__init__(self) + self.vars = ('CCDEFINES', 'CXXDEFINES') + + def scan(self, task, node): + "look for .h the .cpp need" + debug("_scan_preprocessor(self, node, env, path_lst)", 'ccroot') + gruik = preproc.c_parser(nodepaths = task.path_lst, defines = task.defines) + gruik.start(node, task.env()) + if Params.g_verbose: + debug("nodes found for %s: %s %s" % (str(node), str(gruik.m_nodes), str(gruik.m_names)), 'deps') + debug("deps found for %s: %s" % (str(node), str(gruik.deps)), 'deps') + return (gruik.m_nodes, gruik.m_names) + +g_c_scanner = c_scanner() +"scanner for c programs" + +class ccroot_abstract(Object.task_gen): + "Parent class for programs and libraries in languages c, c++ and moc (Qt)" + def __init__(self, type='program', subtype=None): + Object.task_gen.__init__(self) + + # TODO obsolete + self.m_type = type + + if self.m_type == 'objects': + self.features.append(type) + else: + self.features.append('normal') + + # includes, seen from the current directory + self.includes='' + + # list of directories to enable when scanning + # #include directives in source files for automatic + # dependency tracking. If left empty, scanning the + # whole project tree is enabled. If non-empty, only + # the indicated directories (which must be relative + # paths), plus the directories in obj.includes, are + # scanned for #includes. + self.dependencies = '' + + self.defines='' + self.rpaths='' + + self.uselib='' + + # new scheme: provide the names of the local libraries to link with + # the objects found will be post()-ed + self.uselib_local='' + + # add .o files produced by another task_gen class + self.add_objects = '' + + # version number for shared libraries + #self.vnum='1.2.3' # + #self.soname='.so.3' # else soname is computed from vnum + + #self.program_chmod = 0755 # by default: 0755 + + # do not forget to set the following variables in a subclass + self.p_flag_vars = [] + self.p_type_vars = [] + + # TODO ??? + self.m_type_initials = '' + + # these are kind of private, do not touch + self.incpaths_lst=[] + self.inc_paths = [] + self.scanner_defines = {} + self.bld_incpaths_lst=[] + + self.subtype = subtype + + self.compiled_tasks = [] + self.link_task = None + + self.inst_var = '' # mark as installable TODO + + # characteristics of what we want to build: cc, cpp, program, staticlib, shlib, etc + #self.features = ['program'] + +def get_target_name(self): + name = self.target + pattern = self.env[self.m_type+'_PATTERN'] + if not pattern: pattern = '%s' + + # name can be src/mylib + k = name.rfind('/') + return name[0:k+1] + pattern % name[k+1:] + +def apply_verif(self): + if not hasattr(self, 'nochecks'): + if not (self.source or self.add_objects): + fatal('no source files specified for %s' % self) + if not self.target and self.m_type != 'objects': + fatal('no target for %s' % self) + +def install_shlib(task): + nums = task.vnum.split('.') + + dest_var = task.dest_var + dest_subdir = task.dest_subdir + + libname = task.m_outputs[0].m_name + + name3 = libname+'.'+task.vnum + name2 = libname+'.'+nums[0] + name1 = libname + + filename = task.m_outputs[0].relpath_gen(Params.g_build.m_curdirnode) + Common.install_as(dest_var, dest_subdir+'/'+name3, filename, env=task.env()) + Common.symlink_as(dest_var, name3, dest_subdir+'/'+name2) + Common.symlink_as(dest_var, name3, dest_subdir+'/'+name1) + +def install_target(self): + # FIXME too complicated + if not Params.g_install: return + + dest_var = self.inst_var + dest_subdir = self.inst_dir + if dest_var == 0: return + + if not dest_var: + dest_var = 'PREFIX' + if self.m_type == 'program': dest_subdir = 'bin' + else: dest_subdir = 'lib' + + if (self.m_type == 'shlib' or self.m_type == 'plugin') and getattr(self, 'vnum', '') and sys.platform != 'win32': + # shared libraries on linux + tsk = self.link_task + tsk.vnum = self.vnum + tsk.dest_var = dest_var + tsk.dest_subdir = dest_subdir + tsk.install = install_shlib + else: + # program or staticlib + try: mode = self.program_chmod + except AttributeError: + if self.m_type == 'program': mode = 0755 + else: mode = 0644 + install = {'var':dest_var,'dir':dest_subdir,'chmod':mode} + self.link_task.install = install + +def apply_dependencies(self): + if self.dependencies: + dep_lst = (self.to_list(self.dependencies) + self.to_list(self.includes)) + self.inc_paths = [] + for directory in dep_lst: + if os.path.isabs(directory): + Params.fatal("Absolute paths not allowed in obj.dependencies") + return + + node = self.path.find_dir_lst(Utils.split_path(directory)) + if not node: + Params.fatal("node not found in ccroot:apply_dependencies " + str(directory), 'ccroot') + return + if node not in self.inc_paths: + self.inc_paths.append(node) + else: + # by default, we include the whole project tree + lst = [self.path] + for obj in Object.g_allobjs: + if obj.path not in lst: + lst.append(obj.path) + self.inc_paths = lst + self.incpaths_lst + +def apply_incpaths(self): + lst = [] + for i in self.to_list(self.uselib): + if self.env['CPPPATH_'+i]: + lst += self.to_list(self.env['CPPPATH_'+i]) + inc_lst = self.to_list(self.includes) + lst + lst = self.incpaths_lst + + # add the build directory + self.incpaths_lst.append(Params.g_build.m_bldnode) + self.incpaths_lst.append(Params.g_build.m_srcnode) + + # now process the include paths + tree = Params.g_build + for dir in inc_lst: + if os.path.isabs(dir): + self.env.append_value('CPPPATH', dir) + continue + + node = self.path.find_dir_lst(Utils.split_path(dir)) + if not node: + debug("node not found in ccroot:apply_incpaths "+str(dir), 'ccroot') + continue + if not node in lst: lst.append(node) + Params.g_build.rescan(node) + self.bld_incpaths_lst.append(node) + # now the nodes are added to self.incpaths_lst + +def apply_type_vars(self): + + # the subtype, used for all sorts of evil things + if not self.subtype: + if self.m_type in 'program staticlib plugin'.split(): + self.subtype = self.m_type + else: + self.subtype = 'shlib' + + # if the subtype defines uselib to add, add them + st = self.env[self.subtype+'_USELIB'] + if st: self.uselib = self.uselib + ' ' + st + + # each compiler defines variables like 'shlib_CXXFLAGS', 'shlib_LINKFLAGS', etc + # so when we make a cppobj of the type shlib, CXXFLAGS are modified accordingly + for var in self.p_type_vars: + compvar = '_'.join([self.m_type, var]) + #print compvar + value = self.env[compvar] + if value: self.env.append_value(var, value) + +def apply_link(self): + if self.m_type=='staticlib': + linktask = self.create_task('ar_link_static', self.env) + else: + linktask = self.create_task(self.m_type_initials+'_link', self.env) + outputs = [t.m_outputs[0] for t in self.compiled_tasks] + linktask.set_inputs(outputs) + linktask.set_outputs(self.path.find_build(get_target_name(self))) + + self.link_task = linktask + +def apply_lib_vars(self): + env = self.env + + # 1. the case of the libs defined in the project (visit ancestors first) + # the ancestors external libraries (uselib) will be prepended + uselib = self.to_list(self.uselib) + seen = [] + names = [] + self.to_list(self.uselib_local) # consume a copy of the list of names + while names: + x = names.pop(0) + + # visit dependencies only once + if x in seen: + continue + + # object does not exist ? + y = Object.name_to_obj(x) + if not y: + fatal('object not found in uselib_local: obj %s uselib %s' % (self.name, x)) + continue + + # object has ancestors to process: add them to the end of the list + if y.uselib_local: + lst = y.to_list(y.uselib_local) + for u in lst: + if u in seen: continue + names.append(u) + + # safe to process the current object + if not y.m_posted: y.post() + seen.append(x) + + if y.m_type == 'shlib': + env.append_value('LIB', y.target) + elif y.m_type == 'plugin': + if sys.platform == 'darwin': env.append_value('PLUGIN', y.target) + else: env.append_value('LIB', y.target) + elif y.m_type == 'staticlib': + env.append_value('STATICLIB', y.target) + elif y.m_type == 'objects': + pass + else: + error('%s has unknown object type %s, in apply_lib_vars, uselib_local.' + % (y.name, y.m_type)) + + # add the link path too + tmp_path = y.path.bldpath(self.env) + if not tmp_path in env['LIBPATH']: env.prepend_value('LIBPATH', tmp_path) + + # set the dependency over the link task + if y.link_task is not None: + self.link_task.set_run_after(y.link_task) + dep_nodes = getattr(self.link_task, 'dep_nodes', []) + self.link_task.dep_nodes = dep_nodes + y.link_task.m_outputs + + # add ancestors uselib too + # TODO potential problems with static libraries ? + morelibs = y.to_list(y.uselib) + for v in morelibs: + if v in uselib: continue + uselib = [v]+uselib + + # 2. the case of the libs defined outside + for x in uselib: + for v in self.p_flag_vars: + val = self.env[v+'_'+x] + if val: self.env.append_value(v, val) + +def apply_objdeps(self): + "add the .o files produced by some other object files in the same manner as uselib_local" + seen = [] + names = self.to_list(self.add_objects) + while names: + x = names[0] + + # visit dependencies only once + if x in seen: + names = names[1:] + continue + + # object does not exist ? + y = Object.name_to_obj(x) + if not y: + error('object not found in add_objects: obj %s add_objects %s' % (self.name, x)) + names = names[1:] + continue + + # object has ancestors to process first ? update the list of names + if y.add_objects: + added = 0 + lst = y.to_list(y.add_objects) + lst.reverse() + for u in lst: + if u in seen: continue + added = 1 + names = [u]+names + if added: continue # list of names modified, loop + + # safe to process the current object + if not y.m_posted: y.post() + seen.append(x) + + self.link_task.m_inputs += y.out_nodes + +def apply_obj_vars(self): + lib_st = self.env['LIB_ST'] + staticlib_st = self.env['STATICLIB_ST'] + libpath_st = self.env['LIBPATH_ST'] + staticlibpath_st = self.env['STATICLIBPATH_ST'] + + # FIXME + self.addflags('CPPFLAGS', self.cppflags) + + app = self.env.append_unique + + for i in self.env['RPATH']: + app('LINKFLAGS', i) + + for i in self.env['LIBPATH']: + app('LINKFLAGS', libpath_st % i) + + for i in self.env['LIBPATH']: + app('LINKFLAGS', staticlibpath_st % i) + + if self.env['STATICLIB']: + self.env.append_value('LINKFLAGS', self.env['STATICLIB_MARKER']) + k = [(staticlib_st % i) for i in self.env['STATICLIB']] + app('LINKFLAGS', k) + + # fully static binaries ? + if not self.env['FULLSTATIC']: + if self.env['STATICLIB'] or self.env['LIB']: + self.env.append_value('LINKFLAGS', self.env['SHLIB_MARKER']) + + app('LINKFLAGS', [lib_st % i for i in self.env['LIB']]) + +def apply_vnum(self): + "use self.vnum and self.soname to modify the command line (un*x)" + try: vnum = self.vnum + except AttributeError: return + # this is very unix-specific + if sys.platform != 'darwin' and sys.platform != 'win32': + nums = self.vnum.split('.') + try: name3 = self.soname + except AttributeError: name3 = self.link_task.m_outputs[0].m_name+'.'+self.vnum.split('.')[0] + self.env.append_value('LINKFLAGS', '-Wl,-h,'+name3) + +def process_obj_files(self): + if not hasattr(self, 'obj_files'): return + for x in self.obj_files: + node = self.path.find_source(x) + self.link_task.m_inputs.append(node) + +def add_obj_file(self, file): + """Small example on how to link object files as if they were source + obj = bld.create_obj('cc') + obj.add_obj_file('foo.o')""" + if not hasattr(self, 'obj_files'): self.obj_files = [] + if not 'process_obj_files' in self.meths: self.meths.add('process_obj_files') + self.obj_files.append(file) + +def make_objects_available(self): + """when we do not link; make the .o files available + if we are only building .o files, tell which ones we built""" + self.out_nodes = [] + app = self.out_nodes.append + for t in self.compiled_tasks: app(t.m_outputs[0]) + + +taskgen(apply_verif) +taskgen(install_target) +feature('normal')(install_target) +after('apply_objdeps')(install_target) +taskgen(apply_dependencies) +after('apply_incpaths')(apply_dependencies) +before('apply_core')(apply_dependencies) +taskgen(apply_incpaths) +after('apply_type_vars')(apply_incpaths) +taskgen(apply_type_vars) +taskgen(apply_link) +feature('normal')(apply_link) +after('apply_core')(apply_link) +taskgen(apply_lib_vars) +after('apply_vnum')(apply_lib_vars) +taskgen(apply_objdeps) +feature('normal')(apply_objdeps) +after('apply_obj_vars')(apply_objdeps) +after('apply_vnum')(apply_objdeps) +taskgen(apply_obj_vars) +feature('normal')(apply_obj_vars) +after('apply_lib_vars')(apply_obj_vars) +taskgen(apply_vnum) +feature('normal')(apply_vnum) +after('apply_link')(apply_vnum) +taskgen(process_obj_files) +after('apply_link')(process_obj_files) +taskgen(add_obj_file) +taskgen(make_objects_available) +feature('objects')(make_objects_available) +after('apply_core')(make_objects_available) diff -Nru zyn-1+git.20100609/wafadmin/Tools/checks.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/checks.py --- zyn-1+git.20100609/wafadmin/Tools/checks.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/checks.py 2008-03-23 19:05:47.000000000 +0000 @@ -0,0 +1,278 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2006 (ita) + +"Additional configuration checks hooked on the configuration class" + +import Utils, Configure, config_c +from Params import error, fatal + +endian_str = ''' +#include +int is_big_endian() +{ + long one = 1; + return !(*((char *)(&one))); +} +int main() +{ + if (is_big_endian()) printf("bigendian=1\\n"); + else printf("bigendian=0\\n"); + return 0; +} +''' + +class compile_configurator(config_c.configurator_base): + "inheritance demo" + def __init__(self, conf): + config_c.configurator_base.__init__(self, conf) + self.name = '' + self.code = '' + self.flags = '' + self.define = '' + self.uselib = '' + self.want_message = 0 + self.msg = '' + self.force_compiler = None + + def error(self): + fatal('test program would not run') + + def run_cache(self, retval): + if self.want_message: + self.conf.check_message('compile code (cached)', '', not (retval is False), option=self.msg) + + def validate(self): + if not self.code: + fatal('test configurator needs code to compile and run!') + + def run_test(self): + obj = config_c.check_data() + obj.code = self.code + obj.env = self.env + obj.uselib = self.uselib + obj.flags = self.flags + if self.force_compiler: obj.force_compiler = self.force_compiler + ret = self.conf.run_check(obj) + + if self.want_message: + self.conf.check_message('compile code', '', not (ret is False), option=self.msg) + + return ret + +def create_compile_configurator(self): + return compile_configurator(self) + +def checkEndian(self, define='', pathlst=[]): + if define == '': define = 'IS_BIGENDIAN' + + if self.is_defined(define): return self.get_define(define) + + global endian + + test = self.create_test_configurator() + test.code = endian_str + code = test.run()['result'] + + t = Utils.to_hashtable(code) + try: + is_big = int(t['bigendian']) + except KeyError: + raise Configure.ConfigurationError('endian test failed '+code) + + if is_big: strbig = 'big endian' + else: strbig = 'little endian' + self.check_message_custom('endianness', '', strbig) + + self.define_cond(define, is_big) + return is_big + +features_str = ''' +#include +int is_big_endian() +{ + long one = 1; + return !(*((char *)(&one))); +} +int main() +{ + if (is_big_endian()) printf("bigendian=1\\n"); + else printf("bigendian=0\\n"); + printf("int_size=%d\\n", sizeof(int)); + printf("long_int_size=%d\\n", sizeof(long int)); + printf("long_long_int_size=%d\\n", sizeof(long long int)); + printf("double_size=%d\\n", sizeof(double)); + return 0; +} +''' + +def checkFeatures(self, lst=[], pathlst=[]): + + global endian + + test = self.create_test_configurator() + test.code = features_str + code = test.run()['result'] + + t = Utils.to_hashtable(code) + try: + is_big = int(t['bigendian']) + except KeyError: + raise Configure.ConfigurationError('endian test failed '+code) + + if is_big: strbig = 'big endian' + else: strbig = 'little endian' + self.check_message_custom('endianness', '', strbig) + + self.check_message_custom('int size', '', t['int_size']) + self.check_message_custom('long int size', '', t['long_int_size']) + self.check_message_custom('long long int size', '', t['long_long_int_size']) + self.check_message_custom('double size', '', t['double_size']) + + self.define_cond('IS_BIGENDIAN', is_big) + self.define_cond('INT_SIZE', int(t['int_size'])) + self.define_cond('LONG_INT_SIZE', int(t['long_int_size'])) + self.define_cond('LONG_LONG_INT_SIZE', int(t['long_long_int_size'])) + self.define_cond('DOUBLE_SIZE', int(t['double_size'])) + + return is_big + +def detect_platform(self): + """adapted from scons""" + import os, sys + if os.name == 'posix': + if sys.platform == 'cygwin': + return 'cygwin' + if str.find(sys.platform, 'linux') != -1: + return 'linux' + if str.find(sys.platform, 'irix') != -1: + return 'irix' + if str.find(sys.platform, 'sunos') != -1: + return 'sunos' + if str.find(sys.platform, 'hp-ux') != -1: + return 'hpux' + if str.find(sys.platform, 'aix') != -1: + return 'aix' + if str.find(sys.platform, 'darwin') != -1: + return 'darwin' + return 'posix' + elif os.name == 'os2': + return 'os2' + elif os.name == 'java': + return 'java' + else: + return sys.platform + +def find_header(self, header, define='', paths=''): + if not define: + define = 'HAVE_' + header.upper().replace('/', '_').replace('.', '_') + test = self.create_header_enumerator() + test.mandatory = 1 + test.name = header + test.path = paths + test.define = define + return test.run() + +def check_header(self, header, define='', mandatory=0): + if not define: + define = 'HAVE_' + header.upper().replace('/', '_').replace('.', '_') + + test = self.create_header_configurator() + test.name = header + test.define = define + test.mandatory = mandatory + return test.run() + +def try_build_and_exec(self, code, uselib=''): + test = self.create_test_configurator() + test.uselib = uselib + test.code = code + ret = test.run() + if ret: return ret['result'] + return None + +def try_build(self, code, uselib='', msg='', force_compiler = ''): + test = self.create_compile_configurator() + test.uselib = uselib + test.code = code + if force_compiler: + test.force_compiler = force_compiler + if msg: + test.want_message = 1 + test.msg = msg + ret = test.run() + return ret + +def check_flags(self, flags, uselib='', options='', msg=1): + test = self.create_test_configurator() + test.uselib = uselib + test.code = 'int main() {return 0;}\n' + test.flags = flags + ret = test.run() + + if msg: self.check_message('flags', flags, not (ret is False)) + + if ret: return 1 + return None + +# function wrappers for convenience +def check_header2(self, name, mandatory=1, define=''): + import os + ck_hdr = self.create_header_configurator() + if define: ck_hdr.define = define + # header provides no fallback for define: + else: ck_hdr.define = 'HAVE_' + os.path.basename(name).replace('.','_').upper() + ck_hdr.mandatory = mandatory + ck_hdr.name = name + return ck_hdr.run() + +def check_library2(self, name, mandatory=1, uselib=''): + ck_lib = self.create_library_configurator() + if uselib: ck_lib.uselib = uselib + ck_lib.mandatory = mandatory + ck_lib.name = name + return ck_lib.run() + +def check_pkg2(self, name, version, mandatory=1, uselib=''): + ck_pkg = self.create_pkgconfig_configurator() + if uselib: ck_pkg.uselib = uselib + ck_pkg.mandatory = mandatory + ck_pkg.version = version + ck_pkg.name = name + return ck_pkg.run() + +def check_cfg2(self, name, mandatory=1, define='', uselib=''): + ck_cfg = self.create_cfgtool_configurator() + if uselib: ck_cfg.uselib = uselib + # cfgtool provides no fallback for uselib: + else: ck_cfg.uselib = name.upper() + ck_cfg.mandatory = mandatory + ck_cfg.binary = name + '-config' + return ck_cfg.run() + +def detect(conf): + "attach the checks to the conf object" + + conf.hook(find_header) + conf.hook(check_header) + conf.hook(create_compile_configurator) + conf.hook(try_build) + conf.hook(try_build_and_exec) + conf.hook(check_flags) + + # additional methods + conf.hook(check_header2) + conf.hook(check_library2) + conf.hook(check_pkg2) + conf.hook(check_cfg2) + + # the point of checkEndian is to make an example, the following is better + # if sys.byteorder == "little": + conf.hook(checkEndian) + conf.hook(checkFeatures) + conf.hook(detect_platform) + + diff -Nru zyn-1+git.20100609/wafadmin/Tools/compiler_cc.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/compiler_cc.py --- zyn-1+git.20100609/wafadmin/Tools/compiler_cc.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/compiler_cc.py 2008-03-23 19:05:47.000000000 +0000 @@ -0,0 +1,57 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Matthias Jahn , 2007 (pmarat) + +import os, sys, imp, types +import optparse +import Utils, Action, Params, checks, Configure + +def __list_possible_compiler(plattform): + c_compiler = { +'win32': ['msvc', 'gcc'], +'cygwin': ['gcc'], +'darwin': ['gcc'], +'aix5': ['gcc'], +'linux': ['gcc', 'suncc'], +'sunos': ['suncc', 'gcc'], +'irix': ['gcc'], +'hpux': ['gcc'], +'default': ['gcc'] + } + try: + return c_compiler[plattform] + except KeyError: + return c_compiler["default"] + +def detect(conf): + try: test_for_compiler = Params.g_options.check_c_compiler + except AttributeError: raise Configure.ConfigurationError("Add set_options(opt): opt.tool_options('compiler_cc')") + for c_compiler in test_for_compiler.split(): + conf.check_tool(c_compiler) + if conf.env['CC']: + conf.check_message("%s" %c_compiler, '', True) + conf.env["COMPILER_CC"] = "%s" % c_compiler #store the choosed c compiler + return + conf.check_message("%s" %c_compiler, '', False) + conf.env["COMPILER_CC"] = None + +def set_options(opt): + detected_plattform = checks.detect_platform(None) + possible_compiler_list = __list_possible_compiler(detected_plattform) + test_for_compiler = str(" ").join(possible_compiler_list) + cc_compiler_opts = opt.add_option_group("C Compiler Options") + try: + cc_compiler_opts.add_option('--check-c-compiler', default="%s" % test_for_compiler, + help='On this platform (%s) the following C-Compiler will be checked by default: "%s"' % + (detected_plattform, test_for_compiler), + dest="check_c_compiler") + except optparse.OptionConflictError: + pass + + for c_compiler in test_for_compiler.split(): + opt.tool_options('%s' % c_compiler, option_group=cc_compiler_opts) + + diff -Nru zyn-1+git.20100609/wafadmin/Tools/compiler_cxx.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/compiler_cxx.py --- zyn-1+git.20100609/wafadmin/Tools/compiler_cxx.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/compiler_cxx.py 2008-03-25 19:28:28.000000000 +0000 @@ -0,0 +1,56 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Matthias Jahn , 2007 (pmarat) + +import os, sys, imp, types +import optparse +import Utils, Action, Params, checks, Configure + +def __list_possible_compiler(plattform): + c_compiler = { +'win32': ['msvc', 'g++'], +'cygwin': ['g++'], +'darwin': ['g++'], +'aix5': ['g++'], +'linux': ['g++', 'sunc++'], +'sunos': ['sunc++', 'g++'], +'irix': ['g++'], +'hpux': ['g++'], +'default': ['g++'] + } + try: + return(c_compiler[plattform]) + except KeyError: + return(c_compiler["default"]) + +def detect(conf): + try: test_for_compiler = Params.g_options.check_cxx_compiler + except AttributeError: raise Configure.ConfigurationError("Add set_options(opt): opt.tool_options('compiler_cxx')") + for cxx_compiler in test_for_compiler.split(): + conf.check_tool(cxx_compiler) + if conf.env['CXX']: + conf.check_message("%s" %cxx_compiler, '', True) + conf.env["COMPILER_CXX"] = "%s" %cxx_compiler #store the choosen c++ compiler + return + conf.check_message("%s" %cxx_compiler, '', False) + conf.env["COMPILER_CXX"] = None + +def set_options(opt): + detected_plattform = checks.detect_platform(None) + possible_compiler_list = __list_possible_compiler(detected_plattform) + test_for_compiler = str(" ").join(possible_compiler_list) + cxx_compiler_opts = opt.add_option_group("C++ Compiler Options") + try: + cxx_compiler_opts.add_option('--check-cxx-compiler', default="%s" % test_for_compiler, + help='On this platform (%s) the following C++ Compiler will be checked by default: "%s"' % + (detected_plattform, test_for_compiler), + dest="check_cxx_compiler") + except optparse.OptionConflictError: + pass + for cxx_compiler in test_for_compiler.split(): + opt.tool_options('%s' % cxx_compiler, option_group=cxx_compiler_opts) + + diff -Nru zyn-1+git.20100609/wafadmin/Tools/compiler_d.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/compiler_d.py --- zyn-1+git.20100609/wafadmin/Tools/compiler_d.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/compiler_d.py 2008-03-23 19:05:47.000000000 +0000 @@ -0,0 +1,35 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Carlos Rafael Giani, 2007 (dv) + +import os, sys, imp, types +import Utils, Action, Params, checks, Configure + +def detect(conf): + if getattr(Params.g_options, 'check_dmd_first', None): + test_for_compiler = ['dmd', 'gdc'] + else: + test_for_compiler = ['gdc', 'dmd'] + + for d_compiler in test_for_compiler: + conf.check_tool(d_compiler) + if conf.env['D_COMPILER']: + conf.check_message("%s" % d_compiler, '', True) + conf.env["COMPILER_D"] = d_compiler + return + conf.check_message("%s" % d_compiler, '', False) + +def set_options(opt): + d_compiler_opts = opt.add_option_group("D Compiler Options") + try: + d_compiler_opts.add_option('--check-dmd-first', action = "store_true", help = 'checks for the gdc compiler before dmd (default is the other way round)', dest = 'check_dmd_first',default = False) + except Exception: + pass + + for d_compiler in ['gdc', 'dmd']: + opt.tool_options('%s' % d_compiler, option_group=d_compiler_opts) + + diff -Nru zyn-1+git.20100609/wafadmin/Tools/config_c.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/config_c.py --- zyn-1+git.20100609/wafadmin/Tools/config_c.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/config_c.py 2008-03-25 19:28:28.000000000 +0000 @@ -0,0 +1,1149 @@ +#! /usr/bin/env python +# encoding: utf-8 +import sys +if sys.hexversion < 0x020400f0: from sets import Set as set +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2005-2008 (ita) + +""" +the c/c++ configuration routines +""" + +import os, types, imp, cPickle, sys, shlex, warnings +try: from hashlib import md5 +except ImportError: from md5 import md5 +import Action, Params, Environment, Runner, Build, Utils, Object, Configure +from Params import fatal, warning +from Constants import * + +def wrap(cls): + def foo(self): + x = globals()[cls.__name__](self) + #print x + return x + setattr(Configure.Configure, 'create_'+cls.__name__, foo) + +class enumerator_base(object): + def __init__(self, conf): + self.conf = conf + self.env = conf.env + self.define = '' + self.mandatory = 0 + self.message = '' + + def error(self): + if self.message: + fatal(self.message) + else: + fatal('A mandatory check failed. Make sure all dependencies are ok and can be found.') + + def update_hash(self, md5hash): + classvars = vars(self) + for (var, value) in classvars.iteritems(): + # TODO comparing value to env is fast or slow ? + if callable(var): continue + if value == self: continue + if value == self.env: continue + if value == self.conf: continue + md5hash.update(str(value)) + + def update_env(self, hashtable): + # skip this if hashtable is only a string + if not type(hashtable) is types.StringType: + for name in hashtable.keys(): + self.env.append_value(name, hashtable[name]) + + def validate(self): + pass + + def hash(self): + m = md5() + self.update_hash(m) + return m.digest() + + def run_cache(self, retvalue): + # interface, do not remove + pass + + def run(self): + self.validate() + if Params.g_cache_global and not Params.g_options.nocache: + newhash = self.hash() + try: + ret = self.conf.m_cache_table[newhash] + except KeyError: + pass # go to A1 just below + else: + self.run_cache(ret) + if self.mandatory and not ret: self.error() + return ret + + # A1 - no cache or new test + ret = self.run_test() + if self.mandatory and not ret: self.error() + + if Params.g_cache_global: + self.conf.m_cache_table[newhash] = ret + return ret + + # Override this method, not run()! + def run_test(self): + return not Configure.TEST_OK + +class configurator_base(enumerator_base): + def __init__(self, conf): + enumerator_base.__init__(self, conf) + self.uselib = '' + +class program_enumerator(enumerator_base): + def __init__(self,conf): + enumerator_base.__init__(self, conf) + + self.name = '' + self.path = [] + self.var = None + + def error(self): + errmsg = 'program %s cannot be found' % self.name + if self.message: errmsg += '\n%s' % self.message + fatal(errmsg) + + def run_cache(self, retval): + self.conf.check_message('program %s (cached)' % self.name, '', retval, option=retval) + if self.var: self.env[self.var] = retval + + def run_test(self): + ret = Configure.find_program_impl(self.env, self.name, self.path, self.var) + self.conf.check_message('program', self.name, ret, ret) + if self.var: self.env[self.var] = ret + return ret +wrap(program_enumerator) + +class function_enumerator(enumerator_base): + def __init__(self,conf): + enumerator_base.__init__(self, conf) + + self.function = '' + self.define = '' + + self.headers = [] + self.header_code = '' + self.custom_code = '' + + self.include_paths = [] + self.libs = [] + self.lib_paths = [] + + def error(self): + errmsg = 'function %s cannot be found' % self.function + if self.message: errmsg += '\n%s' % self.message + fatal(errmsg) + + def validate(self): + if not self.define: + self.define = self.function.upper() + + def run_cache(self, retval): + self.conf.check_message('function %s (cached)' % self.function, '', retval, option='') + if retval: + self.conf.define(self.define, retval) + else: + self.conf.undefine(self.define) + + def run_test(self): + ret = not Configure.TEST_OK + + oldlibpath = self.env['LIBPATH'] + oldlib = self.env['LIB'] + + code = [] + code.append(self.header_code) + code.append('\n') + for header in self.headers: + code.append('#include <%s>\n' % header) + + if self.custom_code: + code.append('int main(){%s\nreturn 0;}\n' % self.custom_code) + else: + code.append('int main(){\nvoid *p;\np=(void*)(%s);\nreturn 0;\n}\n' % self.function) + + self.env['LIB'] = self.libs + self.env['LIBPATH'] = self.lib_paths + + obj = check_data() + obj.code = "\n".join(code) + obj.includes = self.include_paths + obj.env = self.env + + ret = int(self.conf.run_check(obj)) + self.conf.check_message('function %s' % self.function, '', ret, option='') + + if ret: + self.conf.define(self.define, ret) + else: + self.conf.undefine(self.define) + + self.env['LIB'] = oldlib + self.env['LIBPATH'] = oldlibpath + + return ret +wrap(function_enumerator) + +class library_enumerator(enumerator_base): + "find a library in a list of paths" + def __init__(self, conf): + enumerator_base.__init__(self, conf) + + self.name = '' + self.path = [] + self.code = 'int main() {return 0;}\n' + self.uselib = '' # to set the LIB_NAME and LIBPATH_NAME + self.nosystem = 0 # do not use standard lib paths + self.want_message = 1 + + def error(self): + errmsg = 'library %s cannot be found' % self.name + if self.message: errmsg += '\n%s' % self.message + fatal(errmsg) + + def run_cache(self, retval): + if self.want_message: + self.conf.check_message('library %s (cached)' % self.name, '', retval, option=retval) + self.update_env(retval) + + def validate(self): + if not self.path: + self.path = Configure.g_stdlibpath + else: + if not self.nosystem: + self.path += Configure.g_stdlibpath + + def run_test(self): + ret = '' # returns a string + + patterns = [self.env['shlib_PATTERN'], 'lib%s.dll.a', 'lib%s.lib', self.env['staticlib_PATTERN']] + for x in patterns: + name = x % self.name + ret = Configure.find_file(name, self.path) + if ret: break + + if self.want_message: + self.conf.check_message('library '+self.name, '', ret, option=ret) + + if self.uselib: + self.env['LIB_'+self.uselib] += [ self.name ] + self.env['LIBPATH_'+self.uselib] += [ ret ] + + return ret +wrap(library_enumerator) + +class header_enumerator(enumerator_base): + "find a header in a list of paths" + def __init__(self,conf): + enumerator_base.__init__(self, conf) + + self.name = [] + self.path = [] + self.define = [] + self.nosystem = 0 + self.want_message = 1 + + def validate(self): + if not self.path: + self.path = Configure.g_stdincpath + else: + if not self.nosystem: + self.path += Configure.g_stdincpath + + def error(self): + errmsg = 'cannot find %s in %s' % (self.name, str(self.path)) + if self.message: errmsg += '\n%s' % self.message + fatal(errmsg) + + def run_cache(self, retval): + if self.want_message: + self.conf.check_message('header %s (cached)' % self.name, '', retval, option=retval) + if self.define: self.env[self.define] = retval + + def run_test(self): + ret = Configure.find_file(self.name, self.path) + if self.want_message: + self.conf.check_message('header', self.name, ret, ret) + if self.define: self.env[self.define] = ret + return ret +wrap(header_enumerator) + +## ENUMERATORS END +################### + +################### +## CONFIGURATORS + +class cfgtool_configurator(configurator_base): + def __init__(self,conf): + configurator_base.__init__(self, conf) + + self.uselib = '' + self.define = '' + self.binary = '' + + self.tests = {} + + def error(self): + errmsg = '%s cannot be found' % self.binary + if self.message: errmsg += '\n%s' % self.message + fatal(errmsg) + + def validate(self): + if not self.binary: + raise ValueError, "no binary given in cfgtool!" + if not self.uselib: + raise ValueError, "no uselib given in cfgtool!" + if not self.define and self.uselib: + self.define = 'HAVE_'+self.uselib + + if not self.tests: + self.tests['--cflags'] = 'CCFLAGS' + self.tests['--cflags'] = 'CXXFLAGS' + self.tests['--libs'] = 'LINKFLAGS' + + def run_cache(self, retval): + if retval: + self.update_env(retval) + self.conf.define(self.define, 1) + else: + self.conf.undefine(self.define) + self.conf.check_message('config-tool %s (cached)' % self.binary, '', retval, option='') + + def run_test(self): + retval = {} + found = Configure.TEST_OK + + null='2>/dev/null' + if sys.platform == "win32": null='2>nul' + try: + ret = os.popen('%s %s %s' % (self.binary, self.tests.keys()[0], null)).close() + if ret: raise ValueError, "error" + + for flag in self.tests: + var = self.tests[flag] + '_' + self.uselib + cmd = '%s %s %s' % (self.binary, flag, null) + retval[var] = [os.popen(cmd).read().strip()] + + self.update_env(retval) + except ValueError: + retval = {} + found = not Configure.TEST_OK + + if found: + self.conf.define(self.define, found) + else: + self.conf.undefine(self.define) + self.conf.check_message('config-tool ' + self.binary, '', found, option = '') + return retval +wrap(cfgtool_configurator) + +class pkgconfig_configurator(configurator_base): + """ pkgconfig_configurator is a frontend to pkg-config variables: + - name: name of the .pc file (has to be set at least) + - version: atleast-version to check for + - path: override the pkgconfig path (PKG_CONFIG_PATH) + - uselib: name that could be used in tasks with obj.uselib if not set uselib = upper(name) + - define: name that will be used in config.h if not set define = HAVE_+uselib + - variables: list of addional variables to be checked for, for example variables='prefix libdir' + """ + def __init__(self, conf): + configurator_base.__init__(self,conf) + + self.name = '' # name of the .pc file + self.version = '' # version to check + self.pkgpath = os.path.join(Params.g_options.prefix, 'lib', 'pkgconfig') # pkg config path + self.uselib = '' # can be set automatically + self.define = '' # can be set automatically + self.binary = '' # name and path for pkg-config + + # You could also check for extra values in a pkg-config file. + # Use this value to define which values should be checked + # and defined. Several formats for this value are supported: + # - string with spaces to separate a list + # - list of values to check (define name will be upper(uselib"_"value_name)) + # - a list of [value_name, override define_name] + self.variables = [] + self.defines = {} + + def error(self): + if self.version: + errmsg = 'pkg-config cannot find %s >= %s' % (self.name, self.version) + else: + errmsg = 'pkg-config cannot find %s' % self.name + if self.message: errmsg += '\n%s' % self.message + fatal(errmsg) + + + def validate(self): + if not self.uselib: + self.uselib = self.name.upper() + if not self.define: + self.define = 'HAVE_'+self.uselib + + def run_cache(self, retval): + if self.version: + self.conf.check_message('package %s >= %s (cached)' % (self.name, self.version), '', retval, option='') + else: + self.conf.check_message('package %s (cached)' % self.name, '', retval, option='') + if retval: + self.conf.define(self.define, 1) + else: + self.conf.undefine(self.define) + self.update_env(retval) + + def _setup_pkg_config_path(self): + pkgpath = self.pkgpath + if not pkgpath: + return "" + + if sys.platform == 'win32': + if hasattr(self, 'pkgpath_win32_setup'): + return "" + pkgpath_env=os.getenv('PKG_CONFIG_PATH') + + if pkgpath_env: + pkgpath_env = pkgpath_env + ';' +pkgpath + else: + pkgpath_env = pkgpath + + os.putenv('PKG_CONFIG_PATH',pkgpath_env) + setattr(self,'pkgpath_win32_setup',True) + return "" + + pkgpath = 'PKG_CONFIG_PATH=$PKG_CONFIG_PATH:' + pkgpath + return pkgpath + + def run_test(self): + pkgpath = self.pkgpath + pkgbin = self.binary + uselib = self.uselib + + # check if self.variables is a string with spaces + # to separate the variables to check for + # if yes convert variables to a list + if type(self.variables) is types.StringType: + self.variables = str(self.variables).split() + + if not pkgbin: + pkgbin = 'pkg-config' + pkgpath = self._setup_pkg_config_path() + pkgcom = '%s %s' % (pkgpath, pkgbin) + + for key, val in self.defines.items(): + pkgcom += ' --define-variable=%s=%s' % (key, val) + + g_defines = self.env['PKG_CONFIG_DEFINES'] + if type(g_defines) is types.DictType: + for key, val in g_defines.items(): + if self.defines and self.defines.has_key(key): + continue + pkgcom += ' --define-variable=%s=%s' % (key, val) + + retval = {} + + try: + if self.version: + cmd = "%s --atleast-version=%s \"%s\"" % (pkgcom, self.version, self.name) + ret = os.popen(cmd).close() + Params.debug("pkg-config cmd '%s' returned %s" % (cmd, ret)) + self.conf.check_message('package %s >= %s' % (self.name, self.version), '', not ret) + if ret: raise ValueError, "error" + else: + cmd = "%s \"%s\"" % (pkgcom, self.name) + ret = os.popen(cmd).close() + Params.debug("pkg-config cmd '%s' returned %s" % (cmd, ret)) + self.conf.check_message('package %s' % (self.name), '', not ret) + if ret: + raise ValueError, "error" + + cflags_I = shlex.split(os.popen('%s --cflags-only-I \"%s\"' % (pkgcom, self.name)).read()) + cflags_other = shlex.split(os.popen('%s --cflags-only-other \"%s\"' % (pkgcom, self.name)).read()) + retval['CCFLAGS_'+uselib] = cflags_other + retval['CXXFLAGS_'+uselib] = cflags_other + retval['CPPPATH_'+uselib] = [] + for incpath in cflags_I: + assert incpath[:2] == '-I' or incpath[:2] == '/I' + retval['CPPPATH_'+uselib].append(incpath[2:]) # strip '-I' or '/I' + + #env['LINKFLAGS_'+uselib] = os.popen('%s --libs %s' % (pkgcom, self.name)).read().strip() + # Store the library names: + modlibs = os.popen('%s --libs-only-l \"%s\"' % (pkgcom, self.name)).read().strip().split() + retval['LIB_'+uselib] = [] + for item in modlibs: + retval['LIB_'+uselib].append( item[2:] ) #Strip '-l' + + # Store the library paths: + modpaths = os.popen('%s --libs-only-L \"%s\"' % (pkgcom, self.name)).read().strip().split() + retval['LIBPATH_'+uselib] = [] + for item in modpaths: + retval['LIBPATH_'+uselib].append( item[2:] ) #Strip '-l' + + # Store only other: + modother = os.popen('%s --libs-only-other \"%s\"' % (pkgcom, self.name)).read().strip().split() + retval['LINKFLAGS_'+uselib] = [] + for item in modother: + if str(item).endswith(".la"): + import libtool + la_config = libtool.libtool_config(item) + libs_only_L = la_config.get_libs_only_L() + libs_only_l = la_config.get_libs_only_l() + for entry in libs_only_l: + retval['LIB_'+uselib].append( entry[2:] ) #Strip '-l' + for entry in libs_only_L: + retval['LIBPATH_'+uselib].append( entry[2:] ) #Strip '-L' + else: + retval['LINKFLAGS_'+uselib].append( item ) #do not strip anything + + for variable in self.variables: + var_defname = '' + # check if variable is a list + if (type(variable) is types.ListType): + # is it a list of [value_name, override define_name] ? + if len(variable) == 2 and variable[1]: + # if so use the overrided define_name as var_defname + var_defname = variable[1] + # convert variable to a string that name the variable to check for. + variable = variable[0] + + # if var_defname was not overrided by the list containing the define_name + if not var_defname: + var_defname = uselib + '_' + variable.upper() + + retval[var_defname] = os.popen('%s --variable=%s \"%s\"' % (pkgcom, variable, self.name)).read().strip() + + self.conf.define(self.define, 1) + self.update_env(retval) + except ValueError: + retval = {} + self.conf.undefine(self.define) + + return retval +wrap(pkgconfig_configurator) + +class test_configurator(configurator_base): + def __init__(self, conf): + configurator_base.__init__(self, conf) + self.name = '' + self.code = '' + self.flags = '' + self.define = '' + self.uselib = '' + self.want_message = 0 + + def error(self): + errmsg = 'test program would not run' + if self.message: errmsg += '\n%s' % self.message + fatal(errmsg) + + def run_cache(self, retval): + if self.want_message: + self.conf.check_message('custom code (cached)', '', 1, option=retval['result']) + + def validate(self): + if not self.code: + fatal('test configurator needs code to compile and run!') + + def run_test(self): + obj = check_data() + obj.code = self.code + obj.env = self.env + obj.uselib = self.uselib + obj.flags = self.flags + obj.execute = 1 + ret = self.conf.run_check(obj) + + if self.want_message: + if ret: data = ret['result'] + else: data = '' + self.conf.check_message('custom code', '', ret, option=data) + + return ret +wrap(test_configurator) + +class library_configurator(configurator_base): + def __init__(self,conf): + configurator_base.__init__(self,conf) + + self.name = '' + self.path = [] + self.define = '' + self.uselib = '' + + self.code = 'int main(){return 0;}\n' + + def error(self): + errmsg = 'library %s cannot be linked' % self.name + if self.message: errmsg += '\n%s' % self.message + fatal(errmsg) + + def run_cache(self, retval): + self.conf.check_message('library %s (cached)' % self.name, '', retval) + if retval: + self.update_env(retval) + self.conf.define(self.define, 1) + else: + self.conf.undefine(self.define) + + def validate(self): + if not self.path: + self.path = ['/usr/lib/', '/usr/local/lib', '/lib'] + + if not self.uselib: + self.uselib = self.name.upper() + if not self.define: + self.define = 'HAVE_'+self.uselib + + if not self.uselib: + fatal('uselib is not defined') + if not self.code: + fatal('library enumerator must have code to compile') + + def run_test(self): + oldlibpath = self.env['LIBPATH'] + oldlib = self.env['LIB'] + + olduselibpath = self.env['LIBPATH_'+self.uselib] + olduselib = self.env['LIB_'+self.uselib] + + # try the enumerator to find the correct libpath + test = self.conf.create_library_enumerator() + test.name = self.name + test.want_message = 0 + test.path = self.path + test.env = self.env + ret = test.run() + + if ret: + self.env['LIBPATH_'+self.uselib] += [ ret ] + + self.env['LIB_'+self.uselib] += [ self.name ] + + + #self.env['LIB'] = self.name + #self.env['LIBPATH'] = self.lib_paths + + obj = check_data() + obj.code = self.code + obj.env = self.env + obj.uselib = self.uselib + obj.libpath = self.path + + ret = int(self.conf.run_check(obj)) + self.conf.check_message('library %s' % self.name, '', ret) + + if ret: + self.conf.define(self.define, ret) + else: + self.conf.undefine(self.define) + + val = {} + if ret: + val['LIBPATH_'+self.uselib] = self.env['LIBPATH_'+self.uselib] + val['LIB_'+self.uselib] = self.env['LIB_'+self.uselib] + val[self.define] = ret + else: + self.env['LIBPATH_'+self.uselib] = olduselibpath + self.env['LIB_'+self.uselib] = olduselib + + self.env['LIB'] = oldlib + self.env['LIBPATH'] = oldlibpath + + return val +wrap(library_configurator) + +class framework_configurator(configurator_base): + def __init__(self,conf): + configurator_base.__init__(self,conf) + + self.name = '' + self.custom_code = '' + self.code = 'int main(){return 0;}\n' + + self.define = '' # HAVE_something + + self.path = [] + self.uselib = '' + self.remove_dot_h = False + + def error(self): + errmsg = 'framework %s cannot be found via compiler, try pass -F' % self.name + if self.message: errmsg += '\n%s' % self.message + fatal(errmsg) + + def validate(self): + if not self.uselib: + self.uselib = self.name.upper() + if not self.define: + self.define = 'HAVE_'+self.uselib + if not self.code: + self.code = "#include <%s>\nint main(){return 0;}\n" + if not self.uselib: + self.uselib = self.name.upper() + + def run_cache(self, retval): + self.conf.check_message('framework %s (cached)' % self.name, '', retval) + self.update_env(retval) + if retval: + self.conf.define(self.define, 1) + else: + self.conf.undefine(self.define) + + def run_test(self): + oldlkflags = [] + oldccflags = [] + oldcxxflags = [] + + oldlkflags += self.env['LINKFLAGS'] + oldccflags += self.env['CCFLAGS'] + oldcxxflags += self.env['CXXFLAGS'] + + code = [] + if self.remove_dot_h: + code.append('#include <%s/%s>\n' % (self.name, self.name)) + else: + code.append('#include <%s/%s.h>\n' % (self.name, self.name)) + + code.append('int main(){%s\nreturn 0;}\n' % self.custom_code) + + linkflags = [] + linkflags += ['-framework', self.name] + linkflags += ['-F%s' % p for p in self.path] + cflags = ['-F%s' % p for p in self.path] + + myenv = self.env.copy() + myenv['LINKFLAGS'] += linkflags + + obj = check_data() + obj.code = "\n".join(code) + obj.env = myenv + obj.uselib = self.uselib + + obj.flags += " ".join (cflags) + + ret = int(self.conf.run_check(obj)) + self.conf.check_message('framework %s' % self.name, '', ret, option='') + if ret: + self.conf.define(self.define, ret) + else: + self.conf.undefine(self.define) + + val = {} + if ret: + val["LINKFLAGS_" + self.uselib] = linkflags + val["CCFLAGS_" + self.uselib] = cflags + val["CXXFLAGS_" + self.uselib] = cflags + val[self.define] = ret + + self.env['LINKFLAGS'] = oldlkflags + self.env['CCFLAGS'] = oldccflags + self.env['CXXFLAGS'] = oldcxxflags + + self.update_env(val) + + return val +wrap(framework_configurator) + +class header_configurator(configurator_base): + def __init__(self, conf): + configurator_base.__init__(self,conf) + + self.name = '' + self.path = [] + self.header_code = '' + self.custom_code = '' + self.code = 'int main() {return 0;}\n' + + self.define = '' # HAVE_something + + self.libs = [] + self.lib_paths = [] + self.uselib = '' + + def error(self): + errmsg = 'header %s cannot be found via compiler' % self.name + if self.message: errmsg += '\n%s' % self.message + fatal(errmsg) + + def validate(self): + # self.names = self.names.split() + if not self.define: + if self.name: self.define = 'HAVE_'+ Utils.quote_define_name(self.name) + elif self.uselib: self.define = 'HAVE_'+self.uselib + + if not self.code: + self.code = "#include <%s>\nint main(){return 0;}\n" + if not self.define: + fatal('no define given') + + def run_cache(self, retvalue): + self.conf.check_message('header %s (cached)' % self.name, '', retvalue) + if retvalue: + self.update_env(retvalue) + self.conf.define(self.define, 1) + else: + self.conf.undefine(self.define) + + def run_test(self): + ret = {} # not found + + oldlibpath = self.env['LIBPATH'] + oldlib = self.env['LIB'] + + # try the enumerator to find the correct includepath + if self.uselib: + test = self.conf.create_header_enumerator() + test.name = self.name + test.want_message = 0 + test.path = self.path + test.env = self.env + ret = test.run() + + if ret: + self.env['CPPPATH_'+self.uselib] = ret + + code = [] + code.append(self.header_code) + code.append('\n') + code.append('#include <%s>\n' % self.name) + + code.append('int main(){%s\nreturn 0;}\n' % self.custom_code) + + self.env['LIB'] = self.libs + self.env['LIBPATH'] = self.lib_paths + + obj = check_data() + obj.code = "\n".join(code) + obj.includes = self.path + obj.env = self.env + obj.uselib = self.uselib + + ret = int(self.conf.run_check(obj)) + self.conf.check_message('header %s' % self.name, '', ret, option='') + + if ret: + self.conf.define(self.define, ret) + else: + self.conf.undefine(self.define) + + self.env['LIB'] = oldlib + self.env['LIBPATH'] = oldlibpath + + val = {} + if ret: + val['CPPPATH_'+self.uselib] = self.env['CPPPATH_'+self.uselib] + val[self.define] = ret + + if not ret: return {} + return val +wrap(header_configurator) + +class common_include_configurator(header_enumerator): + """Looks for a given header. If found, it will be written later by write_config_header() + + Forced include files are headers that are being used by all source files. + One can include files this way using gcc '-include file.h' or msvc '/fi file.h'. + The alternative suggested here (common includes) is: + Make all files include 'config.h', then add these forced-included headers to + config.h (good for compilers that don't have have this feature and + for further flexibility). + """ + def run_test(self): + # if a header was found, header_enumerator returns its directory. + header_dir = header_enumerator.run_test(self) + + if header_dir: + # if the header was found, add its path to set of forced_include files + # to be using later in write_config_header() + header_path = os.path.join(header_dir, self.name) + + # if this header was not stored already, add it to the list of common headers. + self.env.append_unique(COMMON_INCLUDES, header_path) + + # the return value of all enumerators is checked by enumerator_base.run() + return header_dir +wrap(common_include_configurator) + +# CONFIGURATORS END +#################### + +class check_data(object): + def __init__(self): + + self.env = '' # environment to use + + self.code = '' # the code to execute + + self.flags = '' # the flags to give to the compiler + + self.uselib = '' # uselib + self.includes = '' # include paths + + self.function_name = '' # function to check for + + self.lib = [] + self.libpath = [] # libpath for linking + + self.define = '' # define to add if run is successful + + self.header_name = '' # header name to check for + + self.execute = 0 # execute the program produced and return its output + self.options = '' # command-line options + + self.force_compiler= None + self.build_type = 'program' +setattr(Configure, 'check_data', check_data) # warning, attached to the module + +def define(self, define, value): + """store a single define and its state into an internal list for later + writing to a config header file. Value can only be + a string or int; other types not supported. String + values will appear properly quoted in the generated + header file.""" + assert define and isinstance(define, str) + + tbl = self.env[DEFINES] + if not tbl: tbl = {} + + # the user forgot to tell if the value is quoted or not + if isinstance(value, str): + tbl[define] = '"%s"' % str(value) + elif isinstance(value, int): + tbl[define] = value + else: + raise TypeError + + # add later to make reconfiguring faster + self.env[DEFINES] = tbl + self.env[define] = value +setattr(Configure.Configure, "define", define) + +def undefine(self, define): + """store a single define and its state into an internal list + for later writing to a config header file""" + assert define and isinstance(define, str) + + tbl = self.env[DEFINES] + if not tbl: tbl = {} + + value = UNDEFINED + tbl[define] = value + + # add later to make reconfiguring faster + self.env[DEFINES] = tbl + self.env[define] = value +setattr(Configure.Configure, "undefine", undefine) + +def define_cond(self, name, value): + """Conditionally define a name. + Formally equivalent to: if value: define(name, 1) else: undefine(name)""" + if value: + self.define(name, 1) + else: + self.undefine(name) +setattr(Configure.Configure, "define_cond", define_cond) + +def is_defined(self, define): + defines = self.env[DEFINES] + if not defines: + return False + try: + value = defines[define] + except KeyError: + return False + else: + return (value is not UNDEFINED) +setattr(Configure.Configure, "is_defined", is_defined) + +def get_define(self, define): + "get the value of a previously stored define" + try: return self.env[DEFINES][define] + except KeyError: return None +setattr(Configure.Configure, "get_define", get_define) + +def write_config_header(self, configfile='config.h', env=''): + "save the defines into a file" + if configfile == '': configfile = self.configheader + + lst=Utils.split_path(configfile) + base = lst[:-1] + + if not env: env = self.env + base = [self.m_blddir, env.variant()]+base + dir = os.path.join(*base) + if not os.path.exists(dir): + os.makedirs(dir) + + dir = os.path.join(dir, lst[-1]) + + # remember config files - do not remove them on "waf clean" + self.env.append_value('waf_config_files', os.path.abspath(dir)) + + inclusion_guard_name = '_%s_WAF' % Utils.quote_define_name(configfile) + + dest = open(dir, 'w') + dest.write('/* Configuration header created by Waf - do not edit */\n') + dest.write('#ifndef %s\n#define %s\n\n' % (inclusion_guard_name, inclusion_guard_name)) + + # yes, this is special + if not configfile in self.env['dep_files']: + self.env['dep_files'] += [configfile] + if not env[DEFINES]: env[DEFINES]={'missing':'"code"'} + for key, value in env[DEFINES].iteritems(): + if value is None: + dest.write('#define %s\n' % key) + elif value is UNDEFINED: + dest.write('/* #undef %s */\n' % key) + else: + dest.write('#define %s %s\n' % (key, value)) + + # Adds common-includes to config header. Should come after defines, + # so they will be defined for the common include files too. + for include_file in self.env[COMMON_INCLUDES]: + dest.write('\n#include "%s"' % include_file) + + dest.write('\n#endif /* %s */\n' % (inclusion_guard_name,)) + dest.close() +setattr(Configure.Configure, "write_config_header", write_config_header) + +def set_config_header(self, header): + "set a config header file" + self.configheader = header +setattr(Configure.Configure, "set_config_header", set_config_header) + +def run_check(self, obj): + """compile, link and run if necessary + @param obj: data of type check_data + @return: (False if a error during build happens) or ( (True if build ok) or (a {'result': ''} if execute was set)) + """ + # first make sure the code to execute is defined + if not obj.code: + raise ConfigurationError('run_check: no code to process in check') + + # create a small folder for testing + dir = os.path.join(self.m_blddir, '.wscript-trybuild') + + # if the folder already exists, remove it + for (root, dirs, filenames) in os.walk(dir): + for f in list(filenames): + os.remove(os.path.join(root, f)) + + bdir = os.path.join( dir, '_testbuild_') + + if (not obj.force_compiler and Action.g_actions.get('cpp', None)) or obj.force_compiler == "cpp": + tp = 'cpp' + test_f_name = 'test.cpp' + else: + tp = 'cc' + test_f_name = 'test.c' + + # FIXME: by default the following lines are called more than once + # we have to make sure they get called only once + if not os.path.exists(dir): + os.makedirs(dir) + + if not os.path.exists(bdir): + os.makedirs(bdir) + + if obj.env: env = obj.env + else: env = self.env.copy() + + dest=open(os.path.join(dir, test_f_name), 'w') + dest.write(obj.code) + dest.close() + + # very important + Utils.reset() + + back=os.path.abspath('.') + + bld = Build.Build() + bld.m_allenvs.update(self.m_allenvs) + bld.m_allenvs['default'] = env + bld._variants=bld.m_allenvs.keys() + bld.load_dirs(dir, bdir, isconfigure=1) + + os.chdir(dir) + + # not sure yet when to call this: + #bld.rescan(bld.m_srcnode) + + o = Object.task_gen.classes[tp](obj.build_type) + o.source = test_f_name + o.target = 'testprog' + o.uselib = obj.uselib + o.cppflags = obj.flags + o.includes = obj.includes + + # compile the program + self.mute_logging() + try: + ret = bld.compile() + except Build.BuildError: + ret = 1 + self.restore_logging() + + # keep the name of the program to execute + if obj.execute: + lastprog = o.link_task.m_outputs[0].abspath(o.env) + + #if runopts is not None: + # ret = os.popen(obj.link_task.m_outputs[0].abspath(obj.env)).read().strip() + + os.chdir(back) + Utils.reset() + + # if we need to run the program, try to get its result + if obj.execute: + if ret: return not ret + data = os.popen('"%s"' %lastprog).read().strip() + ret = {'result': data} + return ret + + return not ret +setattr(Configure.Configure, "run_check", run_check) + +# TODO OBSOLETE remove for waf 1.4 +def add_define(self, define, value, quote=-1, comment=''): + fatal("DEPRECATED use conf.define() / conf.undefine() / conf.define_cond() instead") +setattr(Configure.Configure, "add_define", add_define) + +def check_features(self, kind='cc'): + v = self.env + # check for compiler features: programs, shared and static libraries + test = Configure.check_data() + test.code = 'int main() {return 0;}\n' + test.env = v + test.execute = 1 + test.force_compiler = kind + ret = self.run_check(test) + self.check_message('compiler could create', 'programs', not (ret is False)) + if not ret: self.fatal("no programs") + + lib_obj = Configure.check_data() + lib_obj.code = "int k = 3;\n" + lib_obj.env = v + lib_obj.build_type = "shlib" + lib_obj.force_compiler = kind + ret = self.run_check(lib_obj) + self.check_message('compiler could create', 'shared libs', not (ret is False)) + if not ret: self.fatal("no shared libs") + + lib_obj = Configure.check_data() + lib_obj.code = "int k = 3;\n" + lib_obj.env = v + lib_obj.build_type = "staticlib" + lib_obj.force_compiler = kind + ret = self.run_check(lib_obj) + self.check_message('compiler could create', 'static libs', not (ret is False)) + if not ret: self.fatal("no static libs") +setattr(Configure.Configure, "check_features", check_features) + + diff -Nru zyn-1+git.20100609/wafadmin/Tools/cs.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/cs.py --- zyn-1+git.20100609/wafadmin/Tools/cs.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/cs.py 2008-03-25 21:02:39.000000000 +0000 @@ -0,0 +1,79 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2006 (ita) + +"C# support" + +import Params, Action, Object, Utils +from Params import error + +g_types_lst = ['program', 'library'] +class cs_taskgen(Object.task_gen): + def __init__(self, type): + Object.task_gen.__init__(self) + + self.m_type = type + + self.source = '' + self.target = '' + + self.flags = '' + self.assemblies = '' + self.resources = '' + + self.uselib = '' + + self._flag_vars = ['FLAGS', 'ASSEMBLIES'] + + if not self.env: self.env = Params.g_build.env().copy() + + if not type in g_types_lst: + error('type for csobj is undefined '+type) + type='program' + + def apply(self): + self.apply_uselib() + + # process the flags for the assemblies + assemblies_flags = [] + for i in self.to_list(self.assemblies) + self.env['ASSEMBLIES']: + assemblies_flags += '/r:'+i + self.env['_ASSEMBLIES'] += assemblies_flags + + # process the flags for the resources + for i in self.to_list(self.resources): + self.env['_RESOURCES'].append('/resource:'+i) + + # additional flags + self.env['_FLAGS'] += self.to_list(self.flags) + self.env['FLAGS'] + + curnode = self.path + + # process the sources + nodes = [] + for i in self.to_list(self.source): + nodes.append(curnode.find_source(i)) + + # create the task + task = self.create_task('mcs', self.env) + task.m_inputs = nodes + task.set_outputs(self.path.find_build(self.target)) + + def apply_uselib(self): + if not self.uselib: + return + for var in self.to_list(self.uselib): + for v in self._flag_vars: + val = self.env[v+'_'+var] + if val: self.env.append_value(v, val) + +Action.simple_action('mcs', '${MCS} ${SRC} /out:${TGT} ${_FLAGS} ${_ASSEMBLIES} ${_RESOURCES}', color='YELLOW', prio=101) + +def detect(conf): + mcs = conf.find_program('mcs', var='MCS') + if not mcs: mcs = conf.find_program('gmcs', var='MCS') + + diff -Nru zyn-1+git.20100609/wafadmin/Tools/cxx.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/cxx.py --- zyn-1+git.20100609/wafadmin/Tools/cxx.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/cxx.py 2008-03-25 21:02:39.000000000 +0000 @@ -0,0 +1,124 @@ +#! /usr/bin/env python +# encoding: utf-8 +import sys +if sys.hexversion < 0x020400f0: from sets import Set as set +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2005 (ita) + +"Base for c++ programs and libraries" + +import sys +import Object, Params, Action, Utils +from Params import debug, fatal +import ccroot # <- do not remove +from Object import taskgen, before, extension + +g_cpp_flag_vars = [ +'FRAMEWORK', 'FRAMEWORKPATH', +'STATICLIB', 'LIB', 'LIBPATH', 'LINKFLAGS', 'RPATH', +'INCLUDE', +'CXXFLAGS', 'CCFLAGS', 'CPPPATH', 'CPPFLAGS', 'CXXDEFINES'] +"main cpp variables" + +EXT_CXX = ['.cpp', '.cc', '.cxx', '.C'] +CXX_METHS = ['init_cxx', 'apply_type_vars', 'apply_incpaths', 'apply_dependencies', 'apply_defines_cxx', +'apply_core', 'apply_lib_vars', 'apply_obj_vars_cxx'] + +Object.add_feature('cxx', CXX_METHS) + +# TODO get rid of that class +g_cpp_type_vars=['CXXFLAGS', 'LINKFLAGS'] +class cpp_taskgen(ccroot.ccroot_abstract): + def __init__(self, type='program', subtype=None): + ccroot.ccroot_abstract.__init__(self, type, subtype) + self.m_type_initials = 'cpp' + + self.cxxflags='' + self.cppflags='' + + self.features.append('cxx') + +def init_cxx(self): + self.mappings['.c'] = Object.task_gen.mappings['.cxx'] + if hasattr(self, 'p_flag_vars'): self.p_flag_vars = set(self.p_flag_vars).union(g_cpp_flag_vars) + else: self.p_flag_vars = g_cpp_flag_vars + + if hasattr(self, 'p_type_vars'): self.p_type_vars = set(self.p_type_vars).union(g_cpp_type_vars) + else: self.p_type_vars = g_cpp_type_vars + +def apply_obj_vars_cxx(self): + debug('apply_obj_vars_cxx', 'ccroot') + env = self.env + app = self.env.append_unique + cpppath_st = self.env['CPPPATH_ST'] + + self.addflags('CXXFLAGS', self.cxxflags) + + # local flags come first + # set the user-defined includes paths + for i in self.bld_incpaths_lst: + app('_CXXINCFLAGS', cpppath_st % i.bldpath(env)) + app('_CXXINCFLAGS', cpppath_st % i.srcpath(env)) + + # set the library include paths + for i in self.env['CPPPATH']: + app('_CXXINCFLAGS', cpppath_st % i) + #print self.env['_CXXINCFLAGS'] + #print " appending include ",i + + # this is usually a good idea + app('_CXXINCFLAGS', cpppath_st % '.') + app('_CXXINCFLAGS', cpppath_st % self.env.variant()) + tmpnode = Params.g_build.m_curdirnode + app('_CXXINCFLAGS', cpppath_st % tmpnode.bldpath(env)) + app('_CXXINCFLAGS', cpppath_st % tmpnode.srcpath(env)) + +def apply_defines_cxx(self): + tree = Params.g_build + lst = self.to_list(self.defines)+self.to_list(self.env['CXXDEFINES']) + milst = [] + + # now process the local defines + for defi in lst: + if not defi in milst: + milst.append(defi) + + # CXXDEFINES_USELIB + libs = self.to_list(self.uselib) + for l in libs: + val = self.env['CXXDEFINES_'+l] + if val: milst += self.to_list(val) + + self.env['DEFLINES'] = ["%s %s" % (x[0], Utils.trimquotes('='.join(x[1:]))) for x in [y.split('=') for y in milst]] + y = self.env['CXXDEFINES_ST'] + self.env['_CXXDEFFLAGS'] = [y%x for x in milst] + +def cxx_hook(self, node): + # create the compilation task: cpp or cc + task = self.create_task('cpp', self.env) + try: obj_ext = self.obj_ext + except AttributeError: obj_ext = '_%s.o' % self.m_type[:2] + + task.m_scanner = ccroot.g_c_scanner + task.path_lst = self.inc_paths + task.defines = self.scanner_defines + + task.m_inputs = [node] + task.m_outputs = [node.change_ext(obj_ext)] + self.compiled_tasks.append(task) + +cpp_str = '${CXX} ${CXXFLAGS} ${CPPFLAGS} ${_CXXINCFLAGS} ${_CXXDEFFLAGS} ${CXX_SRC_F}${SRC} ${CXX_TGT_F}${TGT}' +link_str = '${LINK_CXX} ${CXXLNK_SRC_F}${SRC} ${CXXLNK_TGT_F}${TGT} ${LINKFLAGS} ${_LIBDIRFLAGS} ${_LIBFLAGS}' + +Action.simple_action('cpp', cpp_str, color='GREEN', prio=100) +Action.simple_action('cpp_link', link_str, color='YELLOW', prio=111) + +Object.declare_order('apply_dependencies', 'apply_defines_cxx', 'apply_core', 'apply_lib_vars', 'apply_obj_vars_cxx', 'apply_obj_vars') + + +taskgen(init_cxx) +before('apply_type_vars')(init_cxx) +taskgen(apply_obj_vars_cxx) +taskgen(apply_defines_cxx) +extension(EXT_CXX)(cxx_hook) diff -Nru zyn-1+git.20100609/wafadmin/Tools/dang.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/dang.py --- zyn-1+git.20100609/wafadmin/Tools/dang.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/dang.py 2008-03-23 19:05:47.000000000 +0000 @@ -0,0 +1,23 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2006 (ita) + +"Demo: '.coin' files are converted into cpp files using 'cat': {.coin -> .cpp -> .o}" + +import Object + +Object.declare_chain( + name = 'dang', + action = '${DANG} ${SRC} > ${TGT}', + ext_in = '.coin', + ext_out = '.cpp' +) + +def detect(conf): + dang = conf.find_program('cat', var='DANG') + if not dang: conf.fatal('cannot find the program "cat"') + + diff -Nru zyn-1+git.20100609/wafadmin/Tools/dmd.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/dmd.py --- zyn-1+git.20100609/wafadmin/Tools/dmd.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/dmd.py 2008-03-23 19:05:47.000000000 +0000 @@ -0,0 +1,69 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Carlos Rafael Giani, 2007 (dv) +# Thomas Nagy, 2008 (ita) + +import sys +import ar + +def find_dmd(conf): + v = conf.env + d_compiler = None + if v['D_COMPILER']: + d_compiler = v['D_COMPILER'] + if not d_compiler: d_compiler = conf.find_program('dmd', var='D_COMPILER') + if not d_compiler: return 0 + v['D_COMPILER'] = d_compiler + +def common_flags(conf): + v = conf.env + + # _DFLAGS _DIMPORTFLAGS _DLIBDIRFLAGS _DLIBFLAGS + + # Compiler is dmd so 'gdc' part will be ignored, just + # ensure key is there, so wscript can append flags to it + v['DFLAGS'] = {'gdc': [], 'dmd': ['-version=Posix']} + + v['D_SRC_F'] = '' + v['D_TGT_F'] = '-c -of' + v['DPATH_ST'] = '-I%s' # template for adding import paths + + # linker + v['D_LINKER'] = v['D_COMPILER'] + v['DLNK_SRC_F'] = '' + v['DLNK_TGT_F'] = '-of' + + v['DLIB_ST'] = '-L-l%s' # template for adding libs + v['DLIBPATH_ST'] = '-L-L%s' # template for adding libpaths + + # linker debug levels + v['DFLAGS_OPTIMIZED'] = ['-O'] + v['DFLAGS_DEBUG'] = ['-g', '-debug'] + v['DFLAGS_ULTRADEBUG'] = ['-g', '-debug'] + v['DLINKFLAGS'] = ['-quiet'] + + v['D_shlib_DFLAGS'] = [] + v['D_shlib_LINKFLAGS'] = [] + + if sys.platform == "win32": + v['D_program_PATTERN'] = '%s.exe' + v['D_shlib_PATTERN'] = 'lib%s.dll' + v['D_staticlib_PATTERN'] = 'lib%s.a' + else: + v['D_program_PATTERN'] = '%s' + v['D_shlib_PATTERN'] = 'lib%s.so' + v['D_staticlib_PATTERN'] = 'lib%s.a' + +def detect(conf): + v = conf.env + find_dmd(conf) + ar.find_ar(conf) + conf.check_tool('d') + common_flags(conf) + +def set_options(opt): + pass + diff -Nru zyn-1+git.20100609/wafadmin/Tools/d.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/d.py --- zyn-1+git.20100609/wafadmin/Tools/d.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/d.py 2008-03-25 21:02:39.000000000 +0000 @@ -0,0 +1,513 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Carlos Rafael Giani, 2007 (dv) +# Thomas Nagy, 2007-2008 (ita) + +import os, sys, re, optparse +import ccroot # <- leave this +import Object, Utils, Action, Params, checks, Configure, Scan +from Params import debug, error +from Object import taskgen, feature, after, before, extension + +EXT_D = ['.d', '.di', '.D'] +D_METHS = ['apply_core', 'apply_vnum', 'apply_objdeps', 'install_target'] # additional d methods + +def filter_comments(filename): + f = open(filename, 'r') + txt = f.read() + f.close() + buf = [] + + i = 0 + max = len(txt) + while i < max: + c = txt[i] + # skip a string + if c == '"': + i += 1 + c = '' + while i < max: + p = c + c = txt[i] + i += 1 + if i == max: return buf + if c == '"': + cnt = 0 + while i < cnt and i < max: + #print "cntcnt = ", str(cnt), self.txt[self.i-2-cnt] + if txt[i-2-cnt] == '\\': cnt+=1 + else: break + #print "cnt is ", str(cnt) + if (cnt%2)==0: break + # i -= 1 # <- useless in practice + # skip a char + elif c == "'": + i += 1 + if i == max: return buf + c = txt[i] + if c == '\\': + i += 1 + if i == max: return buf + c = txt[i] + if c == 'x': + i += 2 # skip two chars + i += 1 + if i == max: return buf + c = txt[i] + if c != '\'': print "uh-oh, invalid character" + + # skip a comment + elif c == '/': + if i == max: break + c = txt[i+1] + # eat /+ +/ comments + if c == '+': + i += 1 + nesting = 1 + prev = 0 + while i < max: + c = txt[i] + if c == '+': + prev = 1 + elif c == '/': + if prev: + nesting -= 1 + if nesting == 0: break + else: + if i < max: + i += 1 + c = txt[i] + if c == '+': + nesting += 1 + else: + return buf + else: + prev = 0 + i += 1 + # eat /* */ comments + elif c == '*': + i += 1 + while i < max: + c = txt[i] + if c == '*': + prev = 1 + elif c == '/': + if prev: break + else: + prev = 0 + i += 1 + # eat // comments + elif c == '/': + i += 1 + c = txt[i] + while i < max and c != '\n': + i += 1 + c = txt[i] + # a valid char, add it to the buffer + else: + buf.append(c) + i += 1 + return buf + +class d_parser(object): + def __init__(self, env, incpaths): + #self.code = '' + #self.module = '' + #self.imports = [] + + self.allnames = [] + + self.re_module = re.compile("module\s+([^;]+)") + self.re_import = re.compile("import\s+([^;]+)") + self.re_import_bindings = re.compile("([^:]+):(.*)") + self.re_import_alias = re.compile("[^=]+=(.+)") + + self.env = env + + self.m_nodes = [] + self.m_names = [] + + self.incpaths = incpaths + + def tryfind(self, filename): + found = 0 + for n in self.incpaths: + found = n.find_source(filename.replace('.', '/')+'.d', create=0) + if found: + self.m_nodes.append(found) + self.waiting.append(found) + break + if not found: + if not filename in self.m_names: + self.m_names.append(filename) + + def get_strings(self, code): + #self.imports = [] + self.module = '' + lst = [] + + # get the module name (if present) + + mod_name = self.re_module.search(code) + if mod_name: + self.module = re.sub('\s+', '', mod_name.group(1)) # strip all whitespaces + + # go through the code, have a look at all import occurrences + + # first, lets look at anything beginning with "import" and ending with ";" + import_iterator = self.re_import.finditer(code) + if import_iterator: + for import_match in import_iterator: + import_match_str = re.sub('\s+', '', import_match.group(1)) # strip all whitespaces + + # does this end with an import bindings declaration? + # (import bindings always terminate the list of imports) + bindings_match = self.re_import_bindings.match(import_match_str) + if bindings_match: + import_match_str = bindings_match.group(1) + # if so, extract the part before the ":" (since the module declaration(s) is/are located there) + + # split the matching string into a bunch of strings, separated by a comma + matches = import_match_str.split(',') + + for match in matches: + alias_match = self.re_import_alias.match(match) + if alias_match: + # is this an alias declaration? (alias = module name) if so, extract the module name + match = alias_match.group(1) + + lst.append(match) + return lst + + def start(self, node): + self.waiting = [node] + # while the stack is not empty, add the dependencies + while self.waiting: + nd = self.waiting.pop(0) + self.iter(nd) + + def iter(self, node): + path = node.abspath(self.env) # obtain the absolute path + code = "".join(filter_comments(path)) # read the file and filter the comments + names = self.get_strings(code) # obtain the import strings + for x in names: + # optimization + if x in self.allnames: continue + self.allnames.append(x) + + # for each name, see if it is like a node or not + self.tryfind(x) + +class d_scanner(Scan.scanner): + "scanner for d files" + def __init__(self): + Scan.scanner.__init__(self) + + def scan(self, task, node): + "look for .d/.di the .d source need" + debug("_scan_preprocessor(self, node, env, path_lst)", 'ccroot') + gruik = d_parser(task.env(), task.path_lst) + gruik.start(node) + + if Params.g_verbose: + debug("nodes found for %s: %s %s" % (str(node), str(gruik.m_nodes), str(gruik.m_names)), 'deps') + #debug("deps found for %s: %s" % (str(node), str(gruik.deps)), 'deps') + return (gruik.m_nodes, gruik.m_names) + +g_d_scanner = d_scanner() +"scanner for d programs" + +def get_target_name(self): + "for d programs and libs" + v = self.env + return v['D_%s_PATTERN' % self.m_type] % self.target + +class d_taskgen(Object.task_gen): + def __init__(self, type='program'): + Object.task_gen.__init__(self) + + self.m_type = type + self.subtype = type + + self.dflags = {'gdc':'', 'dmd':''} + self.importpaths = '' + self.libs = '' + self.libpaths = '' + self.uselib = '' + self.uselib_local = '' + self.inc_paths = [] + + self.compiled_tasks = [] + + self.add_objects = [] + self.features.append('d') + + self.inst_var = '' # mark as installable TODO + self.vnum = '1.0.0' + +Object.add_feature('d', D_METHS) + +def apply_d_libs(self): + uselib = self.to_list(self.uselib) + seen = [] + local_libs = self.to_list(self.uselib_local) + libs = [] + libpaths = [] + env = self.env + while local_libs: + x = local_libs.pop() + + # visit dependencies only once + if x in seen: + continue + else: + seen.append(x) + + # object does not exist ? + y = Object.name_to_obj(x) + if not y: + fatal('object not found in uselib_local: obj %s uselib %s' % (self.name, x)) + + # object has ancestors to process first ? update the list of names + if y.uselib_local: + added = 0 + lst = y.to_list(y.uselib_local) + lst.reverse() + for u in lst: + if u in seen: continue + added = 1 + local_libs = [u]+local_libs + if added: continue # list of names modified, loop + + # safe to process the current object + if not y.m_posted: y.post() + seen.append(x) + + if y.m_type == 'shlib' or y.m_type == 'staticlib': + libs.append(y.target) + elif y.m_type == 'objects': + pass + else: + error('%s has unknown object type %s, in apply_d_lib_vars, uselib_local.' % (y.name, y.m_type)) + + # add the link path too + tmp_path = y.path.bldpath(env) + if not tmp_path in libpaths: libpaths = [tmp_path] + libpaths + + # set the dependency over the link task + if y.link_task is not None: + self.link_task.set_run_after(y.link_task) + dep_nodes = getattr(self.link_task, 'dep_nodes', []) + self.link_task.dep_nodes = dep_nodes + y.link_task.m_outputs + + # add ancestors uselib too + # TODO potential problems with static libraries ? + morelibs = y.to_list(y.uselib) + for v in morelibs: + if v in uselib: continue + uselib = [v]+uselib + self.uselib = uselib + +def apply_d_link(self): + # if we are only building .o files, tell which ones we build + if self.m_type == 'objects': + self.out_nodes = [] + app = self.out_nodes.append + for t in self.compiled_tasks: app(t.m_outputs[0]) + return + + if self.m_type=='staticlib': + linktask = self.create_task('ar_link_static', self.env) + else: + linktask = self.create_task('d_link', self.env) + outputs = [] + app = outputs.append + for t in self.compiled_tasks: app(t.m_outputs[0]) + linktask.set_inputs(outputs) + linktask.set_outputs(self.path.find_build(get_target_name(self))) + + self.link_task = linktask + +def apply_d_vars(self): + env = self.env + dpath_st = env['DPATH_ST'] + lib_st = env['DLIB_ST'] + libpath_st = env['DLIBPATH_ST'] + + dflags = {'gdc':[], 'dmd':[]} + importpaths = self.to_list(self.importpaths) + libpaths = [] + libs = [] + uselib = self.to_list(self.uselib) + + # add compiler flags + for i in uselib: + if env['DFLAGS_' + i]: + for dflag in self.to_list(env['DFLAGS_' + i][env['COMPILER_D']]): + if not dflag in dflags[env['COMPILER_D']]: + dflags[env['COMPILER_D']] += [dflag] + dflags[env['COMPILER_D']] = self.to_list(self.dflags[env['COMPILER_D']]) + dflags[env['COMPILER_D']] + + for dflag in dflags[env['COMPILER_D']]: + if not dflag in env['DFLAGS'][env['COMPILER_D']]: + env['DFLAGS'][env['COMPILER_D']] += [dflag] + + d_shlib_dflags = env['D_' + self.m_type + '_DFLAGS'] + if d_shlib_dflags: + for dflag in d_shlib_dflags: + if not dflag in env['DFLAGS'][env['COMPILER_D']]: + env['DFLAGS'][env['COMPILER_D']] += [dflag] + + env['_DFLAGS'] = env['DFLAGS'][env['COMPILER_D']] + + # add import paths + for i in uselib: + if env['DPATH_' + i]: + for entry in self.to_list(env['DPATH_' + i]): + if not entry in importpaths: + importpaths.append(entry) + + # now process the import paths + for path in importpaths: + if os.path.isabs(path): + env.append_unique('_DIMPORTFLAGS', dpath_st % path) + else: + node = self.path.find_source_lst(Utils.split_path(path)) + self.inc_paths.append(node) + env.append_unique('_DIMPORTFLAGS', dpath_st % node.srcpath(env)) + env.append_unique('_DIMPORTFLAGS', dpath_st % node.bldpath(env)) + + # add library paths + for i in uselib: + if env['LIBPATH_' + i]: + for entry in self.to_list(env['LIBPATH_' + i]): + if not entry in libpaths: + libpaths += [entry] + libpaths = self.to_list(self.libpaths) + libpaths + + # now process the library paths + for path in libpaths: + env.append_unique('_DLIBDIRFLAGS', libpath_st % path) + + # add libraries + for i in uselib: + if env['LIB_' + i]: + for entry in self.to_list(env['LIB_' + i]): + if not entry in libs: + libs += [entry] + libs = libs + self.to_list(self.libs) + + # now process the libraries + for lib in libs: + env.append_unique('_DLIBFLAGS', lib_st % lib) + + # add linker flags + for i in uselib: + dlinkflags = env['DLINKFLAGS_' + i] + if dlinkflags: + for linkflag in dlinkflags: + env.append_unique('DLINKFLAGS', linkflag) + + d_shlib_linkflags = env['D_' + self.m_type + '_LINKFLAGS'] + if d_shlib_linkflags: + for linkflag in d_shlib_linkflags: + env.append_unique('DLINKFLAGS', linkflag) + +def d_hook(self, node): + # create the compilation task: cpp or cc + task = self.create_task('d', self.env) + try: obj_ext = self.obj_ext + except AttributeError: obj_ext = '_%s.o' % self.m_type[:2] + + global g_d_scanner + task.m_scanner = g_d_scanner + task.path_lst = self.inc_paths + #task.defines = self.scanner_defines + + task.m_inputs = [node] + task.m_outputs = [node.change_ext(obj_ext)] + self.compiled_tasks.append(task) + +d_str = '${D_COMPILER} ${_DFLAGS} ${_DIMPORTFLAGS} ${D_SRC_F}${SRC} ${D_TGT_F}${TGT}' +link_str = '${D_LINKER} ${DLNK_SRC_F}${SRC} ${DLNK_TGT_F}${TGT} ${DLINKFLAGS} ${_DLIBDIRFLAGS} ${_DLIBFLAGS}' + +Action.simple_action('d', d_str, 'GREEN', prio=100) +Action.simple_action('d_link', link_str, color='YELLOW', prio=101) + +# for feature request #104 +def generate_header(self, filename, inst_var, inst_dir): + if not hasattr(self, 'header_lst'): self.header_lst = [] + self.meths.add('process_header') + self.header_lst.append([filename, inst_var, inst_dir]) + +def process_header(self): + env = self.env + for i in getattr(self, 'header_lst', []): + node = self.path.find_source(i[0]) + + if not node: + fatal('file not found on d obj '+i[0]) + + task = self.create_task('d_header', env, 2) + task.set_inputs(node) + task.set_outputs(node.change_ext('.di')) + +d_header_str = '${D_COMPILER} ${D_HEADER} ${SRC}' +Action.simple_action('d_header', d_header_str, color='BLUE', prio=80) + + +# quick test # +if __name__ == "__main__": + #Params.g_verbose = 2 + #Params.g_zones = ['preproc'] + #class dum: + # def __init__(self): + # self.parse_cache_d = {} + #Params.g_build = dum() + + try: arg = sys.argv[1] + except IndexError: arg = "file.d" + + print "".join(filter_comments(arg)) + # TODO + paths = ['.'] + + #gruik = filter() + #gruik.start(arg) + + #code = "".join(gruik.buf) + + #print "we have found the following code" + #print code + + #print "now parsing" + #print "-------------------------------------------" + """ + parser_ = d_parser() + parser_.start(arg) + + print "module: %s" % parser_.module + print "imports: ", + for imp in parser_.imports: + print imp + " ", + print +""" + + +taskgen(apply_d_libs) +feature('d')(apply_d_libs) +after('apply_d_link')(apply_d_libs) +before('apply_vnum')(apply_d_libs) +taskgen(apply_d_link) +feature('d')(apply_d_link) +after('apply_core')(apply_d_link) +taskgen(apply_d_vars) +feature('d')(apply_d_vars) +after('apply_core')(apply_d_vars) +extension(EXT_D)(d_hook) +taskgen(generate_header) +taskgen(process_header) +before('apply_core')(process_header) diff -Nru zyn-1+git.20100609/wafadmin/Tools/flex.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/flex.py --- zyn-1+git.20100609/wafadmin/Tools/flex.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/flex.py 2008-03-23 19:05:47.000000000 +0000 @@ -0,0 +1,30 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# John O'Meara, 2006 +# Thomas Nagy, 2006-2008 + +"Flex processing" + +import Object + +def decide_ext(self, node): + if 'cxx' in self.features: return '.lex.cc' + else: return '.lex.c' + +Object.declare_chain( + name = 'flex', + action = '${FLEX} -o${TGT} ${FLEXFLAGS} ${SRC}', + ext_in = '.l', + ext_out = decide_ext +) + +def detect(conf): + flex = conf.find_program('flex', var='FLEX') + if not flex: conf.fatal("flex was not found") + v = conf.env + v['FLEXFLAGS'] = '' + + diff -Nru zyn-1+git.20100609/wafadmin/Tools/gcc.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/gcc.py --- zyn-1+git.20100609/wafadmin/Tools/gcc.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/gcc.py 2008-03-23 19:05:47.000000000 +0000 @@ -0,0 +1,214 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2006-2008 (ita) +# Ralf Habacker, 2006 (rh) + +import os, optparse, sys +import Params, Configure +import ccroot, ar + +STOP = "stop" +CONTINUE = "continue" + + +""" +Configuration issues: + +The first problem is that some exceptions are critical +(compiler not found, ..) while others are not (the ar +program is only needed for static libraries) + +The second problem is about the branching: how to extend +the configuration functions without hard-coding the names +and calling the functions + +A third problem is to reuse the code and not copy-paste +everything each time a new compiler is added + +The refactoring will be performed in three steps: +1 the code will be split into small functions +2 the irrelevant variables will be eliminated +3 a stack-based system will be used for calling the configuration functions +4 the user logic will go into the error recovery (for example, making some errors non-fatal) + +Another solution to avoid an excessive amount of configuration variables is +to create platform-specific methods, in this case the following problems must be solved first: +attach functions dynamically to the c/c++ classes (without importing cxx.py or cc.py) +""" + +def on_error(func_name, exc): + if func_name == 'not_critical': + env['foo'] = 'blah' + return CONTINUE + return STOP + +def eval_rules(conf, rules, err_handler): + for x in rules: + try: + # TODO check pre/post conditions + x(conf) + except Exception, e: + raise + if err_handler(x.__name__, e) == STOP: + break + else: + raise + +def find_cc(conf): + v = conf.env + cc = None + if v['CC']: cc = v['CC'] + elif 'CC' in os.environ: cc = os.environ['CC'] + if not cc: cc = conf.find_program('gcc', var='CC') + if not cc: cc = conf.find_program('cc', var='CC') + if not cc: conf.fatal('gcc was not found') + v['CC'] = cc + +def common_flags(conf): + v = conf.env + + # CPPFLAGS CCDEFINES _CCINCFLAGS _CCDEFFLAGS _LIBDIRFLAGS _LIBFLAGS + + v['CC_SRC_F'] = '' + v['CC_TGT_F'] = '-c -o ' + v['CPPPATH_ST'] = '-I%s' # template for adding include paths + + # linker + if not v['LINK_CC']: v['LINK_CC'] = v['CC'] + v['CCLNK_SRC_F'] = '' + v['CCLNK_TGT_F'] = '-o ' + + v['LIB_ST'] = '-l%s' # template for adding libs + v['LIBPATH_ST'] = '-L%s' # template for adding libpaths + v['STATICLIB_ST'] = '-l%s' + v['STATICLIBPATH_ST'] = '-L%s' + v['CCDEFINES_ST'] = '-D%s' + + v['SHLIB_MARKER'] = '-Wl,-Bdynamic' + v['STATICLIB_MARKER'] = '-Wl,-Bstatic' + + # program + v['program_PATTERN'] = '%s' + + # shared library + v['shlib_CCFLAGS'] = ['-fPIC', '-DPIC'] + v['shlib_LINKFLAGS'] = ['-shared'] + v['shlib_PATTERN'] = 'lib%s.so' + + # static lib + v['staticlib_LINKFLAGS'] = ['-Wl,-Bstatic'] + v['staticlib_PATTERN'] = 'lib%s.a' + +def modifier_win32(conf): + v = conf.env + v['program_PATTERN'] = '%s.exe' + + v['shlib_PATTERN'] = 'lib%s.dll' + v['shlib_CCFLAGS'] = [] + + v['staticlib_LINKFLAGS'] = [] + +def modifier_cygwin(conf): + v = conf.env + v['program_PATTERN'] = '%s.exe' + + v['shlib_PATTERN'] = 'lib%s.dll' + v['shlib_CCFLAGS'] = [] + + v['staticlib_LINKFLAGS'] = [] + +def modifier_darwin(conf): + v = conf.env + v['shlib_CCFLAGS'] = ['-fPIC'] + v['shlib_LINKFLAGS'] = ['-dynamiclib'] + v['shlib_PATTERN'] = 'lib%s.dylib' + + v['staticlib_LINKFLAGS'] = [] + + v['SHLIB_MARKER'] = '' + v['STATICLIB_MARKER'] = '' + +def modifier_aix5(conf): + v = conf.env + v['program_LINKFLAGS'] = ['-Wl,-brtl'] + + v['shlib_LINKFLAGS'] = ['-shared','-Wl,-brtl,-bexpfull'] + + v['SHLIB_MARKER'] = '' + +def modifier_plugin(conf): + v = conf.env + # TODO this will disappear somehow + # plugins. We handle them exactly as shlibs + # everywhere except on osx, where we do bundles + if sys.platform == 'darwin': + v['plugin_LINKFLAGS'] = ['-bundle', '-undefined dynamic_lookup'] + v['plugin_CCFLAGS'] = ['-fPIC'] + v['plugin_PATTERN'] = '%s.bundle' + else: + v['plugin_CCFLAGS'] = v['shlib_CCFLAGS'] + v['plugin_LINKFLAGS'] = v['shlib_LINKFLAGS'] + v['plugin_PATTERN'] = v['shlib_PATTERN'] + +def modifier_debug(conf): + v = conf.env + # compiler debug levels + if conf.check_flags('-O2'): + v['CCFLAGS_OPTIMIZED'] = ['-O2'] + v['CCFLAGS_RELEASE'] = ['-O2'] + if conf.check_flags('-g -DDEBUG'): + v['CCFLAGS_DEBUG'] = ['-g', '-DDEBUG'] + if conf.check_flags('-g3 -O0 -DDEBUG'): + v['CCFLAGS_ULTRADEBUG'] = ['-g3', '-O0', '-DDEBUG'] + if conf.check_flags('-Wall'): + for x in 'OPTIMIZED RELEASE DEBUG ULTRADEBUG'.split(): v.append_unique('CCFLAGS_'+x, '-Wall') + try: + debug_level = Params.g_options.debug_level.upper() + except AttributeError: + debug_level = ccroot.DEBUG_LEVELS.CUSTOM + v.append_value('CCFLAGS', v['CCFLAGS_'+debug_level]) + +def detect(conf): + + # TODO FIXME later it will start from eval_rules + # funcs = [find_cc, find_cpp, find_ar, common_flags, modifier_win32] + #eval_rules(conf, funcs, on_error) + + find_cc(conf) + ar.find_cpp(conf) + ar.find_ar(conf) + + conf.check_tool('cc') + + common_flags(conf) + if sys.platform == 'win32': modifier_win32(conf) + elif sys.platform == 'cygwin': modifier_cygwin(conf) + elif sys.platform == 'darwin': modifier_darwin(conf) + elif sys.platform == 'aix5': modifier_aix5(conf) + modifier_plugin(conf) + + conf.check_tool('checks') + conf.check_features() + + modifier_debug(conf) + + conf.add_os_flags('CFLAGS', 'CCFLAGS') + conf.add_os_flags('CPPFLAGS') + conf.add_os_flags('LINKFLAGS') + +def set_options(opt): + try: + opt.add_option('-d', '--debug-level', + action = 'store', + default = ccroot.DEBUG_LEVELS.RELEASE, + help = "Specify the debug level, does nothing if CFLAGS is set in the environment. [Allowed Values: '%s']" % "', '".join(ccroot.DEBUG_LEVELS.ALL), + choices = ccroot.DEBUG_LEVELS.ALL, + dest = 'debug_level') + except optparse.OptionConflictError: + # the g++ tool might have added that option already + pass + + diff -Nru zyn-1+git.20100609/wafadmin/Tools/gdc.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/gdc.py --- zyn-1+git.20100609/wafadmin/Tools/gdc.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/gdc.py 2008-03-23 19:05:47.000000000 +0000 @@ -0,0 +1,67 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Carlos Rafael Giani, 2007 (dv) + +import sys +import ar + +def find_gdc(conf): + v = conf.env + d_compiler = None + if v['D_COMPILER']: + d_compiler = v['D_COMPILER'] + if not d_compiler: d_compiler = conf.find_program('gdc', var='D_COMPILER') + if not d_compiler: return 0 + v['D_COMPILER'] = d_compiler + +def common_flags(conf): + v = conf.env + + # _DFLAGS _DIMPORTFLAGS _DLIBDIRFLAGS _DLIBFLAGS + + # for mory info about the meaning of this dict see dmd.py + v['DFLAGS'] = {'gdc':[], 'dmd':[]} + + v['D_SRC_F'] = '' + v['D_TGT_F'] = '-c -o ' + v['DPATH_ST'] = '-I%s' # template for adding import paths + + # linker + v['D_LINKER'] = v['D_COMPILER'] + v['DLNK_SRC_F'] = '' + v['DLNK_TGT_F'] = '-o ' + + v['DLIB_ST'] = '-l%s' # template for adding libs + v['DLIBPATH_ST'] = '-L%s' # template for adding libpaths + + # debug levels + v['DLINKFLAGS'] = [] + v['DFLAGS_OPTIMIZED'] = ['-O3'] + v['DFLAGS_DEBUG'] = ['-O0'] + v['DFLAGS_ULTRADEBUG'] = ['-O0'] + + v['D_shlib_DFLAGS'] = [] + v['D_shlib_LINKFLAGS'] = ['-shared'] + + if sys.platform == "win32": + v['D_program_PATTERN'] = '%s.exe' + v['D_shlib_PATTERN'] = 'lib%s.dll' + v['D_staticlib_PATTERN'] = 'lib%s.a' + else: + v['D_program_PATTERN'] = '%s' + v['D_shlib_PATTERN'] = 'lib%s.so' + v['D_staticlib_PATTERN'] = 'lib%s.a' + +def detect(conf): + v = conf.env + find_gdc(conf) + ar.find_ar(conf) + conf.check_tool('d') + common_flags(conf) + +def set_options(opt): + pass + diff -Nru zyn-1+git.20100609/wafadmin/Tools/gnome.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/gnome.py --- zyn-1+git.20100609/wafadmin/Tools/gnome.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/gnome.py 2008-03-25 21:02:39.000000000 +0000 @@ -0,0 +1,366 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2006-2008 (ita) + +"Gnome support" + +import os, re +import Object, Action, Params, Common, Scan, Utils, Runner +import cc +from Params import fatal, error +from Object import taskgen, before, after + +n1_regexp = re.compile('(.*)', re.M) +n2_regexp = re.compile('(.*)', re.M) + +def postinstall_schemas(prog_name): + if Params.g_commands['install']: + dir = Common.path_install('PREFIX', 'etc/gconf/schemas/%s.schemas' % prog_name) + if not Params.g_options.destdir: + # add the gconf schema + Params.pprint('YELLOW', "Installing GConf schema.") + command = 'gconftool-2 --install-schema-file=%s 1> /dev/null' % dir + ret = Runner.exec_command(command) + else: + Params.pprint('YELLOW', "GConf schema not installed. After install, run this:") + Params.pprint('YELLOW', "gconftool-2 --install-schema-file=%s" % dir) + +def postinstall_icons(): + dir = Common.path_install('DATADIR', 'icons/hicolor') + if Params.g_commands['install']: + if not Params.g_options.destdir: + # update the pixmap cache directory + Params.pprint('YELLOW', "Updating Gtk icon cache.") + command = 'gtk-update-icon-cache -q -f -t %s' % dir + ret = Runner.exec_command(command) + else: + Params.pprint('YELLOW', "Icon cache not updated. After install, run this:") + Params.pprint('YELLOW', "gtk-update-icon-cache -q -f -t %s" % dir) + +def postinstall_scrollkeeper(prog_name): + if Params.g_commands['install']: + # now the scrollkeeper update if we can write to the log file + if os.path.iswriteable('/var/log/scrollkeeper.log'): + dir1 = Common.path_install('PREFIX', 'var/scrollkeeper') + dir2 = Common.path_install('DATADIR', 'omf/%s' % prog_name) + command = 'scrollkeeper-update -q -p %s -o %s' % (dir1, dir2) + ret = Runner.exec_command(command) + +def postinstall(prog_name='myapp', schemas=1, icons=1, scrollkeeper=1): + if schemas: postinstall_schemas(prog_name) + if icons: postinstall_icons() + if scrollkeeper: postinstall_scrollkeeper(prog_name) + +# give specs +class xml_to_taskgen(Object.task_gen): + def __init__(self): + Object.task_gen(self) + self.source = 'xmlfile' + self.xslt = 'xlsltfile' + self.target = 'hey' + self.inst_var = 'PREFIX' + self.inst_dir = '' + self.task_created = None + def apply(self): + self.env = self.env.copy() + tree = Params.g_build + current = tree.m_curdirnode + xmlfile = self.path.find_source(self.source) + xsltfile = self.path.find_source(self.xslt) + tsk = self.create_task('xmlto', self.env, 6) + tsk.set_inputs([xmlfile, xsltfile]) + tsk.set_outputs(xmlfile.change_ext('html')) + tsk.install = {'var':self.inst_var, 'dir':self.inst_dir} + +class sgml_man_scanner(Scan.scanner): + def __init__(self): + Scan.scanner.__init__(self) + def scan(self, task, node): + env = task.env() + variant = node.variant(env) + + fi = open(node.abspath(env), 'r') + content = fi.read() + fi.close() + + name = n1_regexp.findall(content)[0] + num = n2_regexp.findall(content)[0] + + doc_name = name+'.'+num + return ([], [doc_name]) + + def do_scan(self, task, node): + Scan.scanner.do_scan(self, task, node) + + variant = node.variant(task.env()) + tmp_lst = Params.g_build.m_raw_deps[variant][node] + name = tmp_lst[0] + task.set_outputs(Params.g_build.m_curdirnode.find_build(name)) + +sgml_scanner = sgml_man_scanner() + +class gnome_sgml2manobj(Object.task_gen): + def __init__(self, appname): + Object.task_gen.__init__(self) + self.m_tasks=[] + self.m_appname = appname + def apply(self): + + def install_result(task): + out = task.m_outputs[0] + name = out.m_name + ext = name[-1] + env = task.env() + Common.install_files('DATADIR', 'man/man%s/' % ext, out.abspath(env), env) + + tree = Params.g_build + tree.rescan(self.path) + for node in self.path.files(): + base, ext = os.path.splitext(node.m_name) + if ext != '.sgml': continue + + task = self.create_task('sgml2man', self.env, 2) + task.set_inputs(node) + if Params.g_install: task.install = install_results + # no outputs, the scanner does it + # no caching for now, this is not a time-critical feature + # in the future the scanner can be used to do more things (find dependencies, etc) + sgml_scanner.do_scan(task, node) + +# Unlike the sgml and doc processing, the dbus and marshal beast +# generate c/c++ code that we want to mix +# here we attach new methods to Object.task_gen + +def add_marshal_file(self, filename, prefix, mode): + if not hasattr(self, 'marshal_lst'): self.marshal_lst = [] + self.meths.add('process_marshal') + self.marshal_lst.append([filename, prefix, mode]) + +def process_marshal(self): + for i in getattr(self, 'marshal_lst', []): + env = self.env.copy() + node = self.path.find_source(i[0]) + + if not node: + fatal('file not found on gnome obj '+i[0]) + + if i[2] == '--header': + + env['GGM_PREFIX'] = i[1] + env['GGM_MODE'] = i[2] + + task = self.create_task('glib_genmarshal', env, 2) + task.set_inputs(node) + task.set_outputs(node.change_ext('.h')) + + elif i[2] == '--body': + env['GGM_PREFIX'] = i[1] + env['GGM_MODE'] = i[2] + + # the c file generated will be processed too + outnode = node.change_ext('.c') + self.allnodes.append(outnode) + + task = self.create_task('glib_genmarshal', env, 2) + task.set_inputs(node) + task.set_outputs(node.change_ext('.c')) + else: + error("unknown type for marshal "+i[2]) + +def add_dbus_file(self, filename, prefix, mode): + if not hasattr(self, 'dbus_lst'): self.dbus_lst = [] + self.meths.add('process_dbus') + self.dbus_lst.append([filename, prefix, mode]) + +def process_dbus(self): + for i in getattr(self, 'dbus_lst', []): + env = self.env.copy() + node = self.path.find_source(i[0]) + + if not node: + fatal('file not found on gnome obj '+i[0]) + + env['DBT_PREFIX'] = i[1] + env['DBT_MODE'] = i[2] + + task = self.create_task('dbus_binding_tool', env, 2) + task.set_inputs(node) + task.set_outputs(node.change_ext('.h')) + +def process_enums(self): + for x in getattr(self, 'mk_enums', []): + # temporary + env = self.env.copy() + task = self.create_task('mk_enums', env) + inputs = [] + + # process the source + src_lst = self.to_list(x['source']) + if not src_lst: + Params.fatal('missing source '+str(x)) + src_lst = [self.path.find_source(k) for k in src_lst] + inputs += src_lst + env['MK_SOURCE'] = [k.abspath(env) for k in src_lst] + + # find the target + if not x['target']: + Params.fatal('missing target '+str(x)) + tgt_node = self.path.find_build(x['target'], create=1) + if tgt_node.m_name.endswith('.c'): + self.allnodes.append(tgt_node) + env['MK_TARGET'] = tgt_node.abspath(env) + + # template, if provided + if x['template']: + template_node = self.path.find_source(x['template']) + env['MK_TEMPLATE'] = '--template %s' % (template_node.abspath(env)) + inputs.append(template_node) + + # update the task instance + task.set_inputs(inputs) + task.set_outputs(tgt_node) + +def add_glib_mkenum(self, source='', template='', target=''): + "just a helper" + if not hasattr(self, 'mk_enums'): self.mk_enums = [] + self.meths.add('process_enums') + self.mk_enums.append({'source':source, 'template':template, 'target':target}) + + +Action.simple_action('mk_enums', '${GLIB_MKENUM} ${MK_TEMPLATE} ${MK_SOURCE} > ${MK_TARGET}', 'PINK', prio=30) + +Action.simple_action('sgml2man', '${SGML2MAN} -o ${TGT[0].bld_dir(env)} ${SRC} > /dev/null', color='BLUE') + +Action.simple_action('glib_genmarshal', + '${GGM} ${SRC} --prefix=${GGM_PREFIX} ${GGM_MODE} > ${TGT}', + color='BLUE') + +Action.simple_action('dbus_binding_tool', + '${DBT} --prefix=${DBT_PREFIX} --mode=${DBT_MODE} --output=${TGT} ${SRC}', + color='BLUE') + +Action.simple_action('xmlto', '${XMLTO} html -m ${SRC[1]} ${SRC[0]}') + +def detect(conf): + + conf.check_tool('checks') + + sgml2man = conf.find_program('docbook2man') + #if not sgml2man: + # fatal('The program docbook2man is mandatory!') + conf.env['SGML2MAN'] = sgml2man + + glib_genmarshal = conf.find_program('glib-genmarshal') + conf.env['GGM'] = glib_genmarshal + + dbus_binding_tool = conf.find_program('dbus-binding-tool') + conf.env['DBT'] = dbus_binding_tool + + mk_enums_tool = conf.find_program('glib-mkenums') + conf.env['GLIB_MKENUM'] = mk_enums_tool + + def getstr(varname): + return getattr(Params.g_options, varname, '') + + prefix = conf.env['PREFIX'] + datadir = getstr('datadir') + libdir = getstr('libdir') + sysconfdir = getstr('sysconfdir') + localstatedir = getstr('localstatedir') + if not datadir: datadir = os.path.join(prefix,'share') + if not libdir: libdir = os.path.join(prefix,'lib') + if not sysconfdir: + if os.path.normpath(prefix) == '/usr': + sysconfdir = '/etc' + else: + sysconfdir = os.path.join(prefix, 'etc') + if not localstatedir: + if os.path.normpath(prefix) == '/usr': + localstatedir = '/var' + else: + localstatedir = os.path.join(prefix, 'var') + + # addefine also sets the variable to the env + conf.define('GNOMELOCALEDIR', os.path.join(datadir, 'locale')) + conf.define('DATADIR', datadir) + conf.define('LIBDIR', libdir) + conf.define('SYSCONFDIR', sysconfdir) + conf.define('LOCALSTATEDIR', localstatedir) + + # TODO: maybe the following checks should be in a more generic module. + + #always defined to indicate that i18n is enabled */ + conf.define('ENABLE_NLS', 1) + + # TODO + #Define to 1 if you have the `bind_textdomain_codeset' function. + conf.define('HAVE_BIND_TEXTDOMAIN_CODESET', 1) + + # TODO + #Define to 1 if you have the `dcgettext' function. + conf.define('HAVE_DCGETTEXT', 1) + + #Define to 1 if you have the header file. + conf.check_header('dlfcn.h', 'HAVE_DLFCN_H') + + # TODO + #Define if the GNU gettext() function is already present or preinstalled. + conf.define('HAVE_GETTEXT', 1) + + #Define to 1 if you have the header file. + conf.check_header('inttypes.h', 'HAVE_INTTYPES_H') + + # TODO FIXME + #Define if your file defines LC_MESSAGES. + #conf.add_define('HAVE_LC_MESSAGES', '1') + + #Define to 1 if you have the header file. + conf.check_header('locale.h', 'HAVE_LOCALE_H') + + #Define to 1 if you have the header file. + conf.check_header('memory.h', 'HAVE_MEMORY_H') + + #Define to 1 if you have the header file. + conf.check_header('stdint.h', 'HAVE_STDINT_H') + + #Define to 1 if you have the header file. + conf.check_header('stdlib.h', 'HAVE_STDLIB_H') + + #Define to 1 if you have the header file. + conf.check_header('strings.h', 'HAVE_STRINGS_H') + + #Define to 1 if you have the header file. + conf.check_header('string.h', 'HAVE_STRING_H') + + #Define to 1 if you have the header file. + conf.check_header('sys/stat.h', 'HAVE_SYS_STAT_H') + + #Define to 1 if you have the header file. + conf.check_header('sys/types.h', 'HAVE_SYS_TYPES_H') + + #Define to 1 if you have the header file. + conf.check_header('unistd.h', 'HAVE_UNISTD_H') + +def set_options(opt): + try: + # we do not know yet + opt.add_option('--want-rpath', type='int', default=1, dest='want_rpath', help='set rpath to 1 or 0 [Default 1]') + except Exception: + pass + + for i in "execprefix datadir libdir sysconfdir localstatedir".split(): + opt.add_option('--'+i, type='string', default='', dest=i) + + +taskgen(add_marshal_file) +taskgen(process_marshal) +before('apply_core')(process_marshal) +taskgen(add_dbus_file) +taskgen(process_dbus) +before('apply_core')(process_dbus) +taskgen(process_enums) +before('apply_core')(process_enums) +taskgen(add_glib_mkenum) diff -Nru zyn-1+git.20100609/wafadmin/Tools/gob2.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/gob2.py --- zyn-1+git.20100609/wafadmin/Tools/gob2.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/gob2.py 2008-03-23 19:05:47.000000000 +0000 @@ -0,0 +1,23 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Ali Sabil, 2007 + +import Object + +Object.declare_chain( + name = 'gob2', + action = '${GOB2} -o ${TGT[0].bld_dir(env)} ${GOB2FLAGS} ${SRC}', + ext_in = '.gob', + ext_out = '.c' +) + +def detect(conf): + gob2 = conf.find_program('gob2', var='GOB2') + if not gob2: conf.fatal('could not find the gob2 compiler') + conf.env['GOB2'] = gob2 + conf.env['GOB2FLAGS'] = '' + + diff -Nru zyn-1+git.20100609/wafadmin/Tools/g++.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/g++.py --- zyn-1+git.20100609/wafadmin/Tools/g++.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/g++.py 2008-03-23 19:05:47.000000000 +0000 @@ -0,0 +1,162 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2006 (ita) +# Ralf Habacker, 2006 (rh) + +import os, optparse, sys +import Params, Configure +import ccroot, ar + +def find_cxx(conf): + v = conf.env + cc = None + if v['CXX']: cc = v['CXX'] + elif 'CXX' in os.environ: cc = os.environ['CXX'] + if not cc: cc = conf.find_program('g++', var='CXX') + if not cc: cc = conf.find_program('c++', var='CXX') + if not cc: conf.fatal('g++ was not found') + v['CXX'] = cc + +def common_flags(conf): + v = conf.env + + # CPPFLAGS CXXDEFINES _CXXINCFLAGS _CXXDEFFLAGS _LIBDIRFLAGS _LIBFLAGS + + v['CXX_SRC_F'] = '' + v['CXX_TGT_F'] = '-c -o ' + v['CPPPATH_ST'] = '-I%s' # template for adding include paths + + # linker + if not v['LINK_CXX']: v['LINK_CXX'] = v['CXX'] + v['CXXLNK_SRC_F'] = '' + v['CXXLNK_TGT_F'] = '-o ' + + v['LIB_ST'] = '-l%s' # template for adding libs + v['LIBPATH_ST'] = '-L%s' # template for adding libpaths + v['STATICLIB_ST'] = '-l%s' + v['STATICLIBPATH_ST'] = '-L%s' + v['CXXDEFINES_ST'] = '-D%s' + + v['SHLIB_MARKER'] = '-Wl,-Bdynamic' + v['STATICLIB_MARKER'] = '-Wl,-Bstatic' + + # program + v['program_PATTERN'] = '%s' + + # shared library + v['shlib_CXXFLAGS'] = ['-fPIC', '-DPIC'] + v['shlib_LINKFLAGS'] = ['-shared'] + v['shlib_PATTERN'] = 'lib%s.so' + + # static lib + v['staticlib_LINKFLAGS'] = ['-Wl,-Bstatic'] + v['staticlib_PATTERN'] = 'lib%s.a' + +def modifier_win32(conf): + v = conf.env + v['program_PATTERN'] = '%s.exe' + + v['shlib_PATTERN'] = 'lib%s.dll' + v['shlib_CXXFLAGS'] = [''] + + v['staticlib_LINKFLAGS'] = [''] + +def modifier_cygwin(conf): + v = conf.env + v['program_PATTERN'] = '%s.exe' + + v['shlib_PATTERN'] = 'lib%s.dll' + v['shlib_CXXFLAGS'] = [''] + + v['staticlib_LINKFLAGS'] = [''] + +def modifier_darwin(conf): + v = conf.env + v['shlib_CXXFLAGS'] = ['-fPIC'] + v['shlib_LINKFLAGS'] = ['-dynamiclib'] + v['shlib_PATTERN'] = 'lib%s.dylib' + + v['staticlib_LINKFLAGS'] = [''] + + v['SHLIB_MARKER'] = '' + v['STATICLIB_MARKER'] = '' + +def modifier_aix5(conf): + v = conf.env + v['program_LINKFLAGS'] = ['-Wl,-brtl'] + + v['shlib_LINKFLAGS'] = ['-shared','-Wl,-brtl,-bexpfull'] + + v['SHLIB_MARKER'] = '' + +def modifier_plugin(conf): + v = conf.env + # TODO this will disappear somehow + # plugins. We handle them exactly as shlibs + # everywhere except on osx, where we do bundles + if sys.platform == 'darwin': + v['plugin_LINKFLAGS'] = ['-bundle', '-undefined dynamic_lookup'] + v['plugin_CXXFLAGS'] = ['-fPIC'] + v['plugin_PATTERN'] = '%s.bundle' + else: + v['plugin_CXXFLAGS'] = v['shlib_CXXFLAGS'] + v['plugin_LINKFLAGS'] = v['shlib_LINKFLAGS'] + v['plugin_PATTERN'] = v['shlib_PATTERN'] + +def modifier_debug(conf): + v = conf.env + # compiler debug levels + if conf.check_flags('-O2'): + v['CXXFLAGS_OPTIMIZED'] = ['-O2'] + v['CXXFLAGS_RELEASE'] = ['-O2'] + if conf.check_flags('-g -DDEBUG'): + v['CXXFLAGS_DEBUG'] = ['-g', '-DDEBUG'] + if conf.check_flags('-g3 -O0 -DDEBUG'): + v['CXXFLAGS_ULTRADEBUG'] = ['-g3', '-O0', '-DDEBUG'] + if conf.check_flags('-Wall'): + for x in 'OPTIMIZED RELEASE DEBUG ULTRADEBUG'.split(): v.append_unique('CXXFLAGS_'+x, '-Wall') + try: + debug_level = Params.g_options.debug_level.upper() + except AttributeError: + debug_level = ccroot.DEBUG_LEVELS.CUSTOM + v.append_value('CXXFLAGS', v['CXXFLAGS_'+debug_level]) + +def detect(conf): + + find_cxx(conf) + ar.find_cpp(conf) + ar.find_ar(conf) + + conf.check_tool('cxx') + + common_flags(conf) + if sys.platform == 'win32': modifier_win32(conf) + elif sys.platform == 'cygwin': modifier_cygwin(conf) + elif sys.platform == 'darwin': modifier_darwin(conf) + elif sys.platform == 'aix5': modifier_aix5(conf) + modifier_plugin(conf) + + conf.check_tool('checks') + conf.check_features(kind='cpp') + + modifier_debug(conf) + + conf.add_os_flags('CXXFLAGS') + conf.add_os_flags('CPPFLAGS') + conf.add_os_flags('LINKFLAGS') + +def set_options(opt): + try: + opt.add_option('-d', '--debug-level', + action = 'store', + default = ccroot.DEBUG_LEVELS.RELEASE, + help = "Specify the debug level, does nothing if CXXFLAGS is set in the environment. [Allowed Values: '%s']" % "', '".join(ccroot.DEBUG_LEVELS.ALL), + choices = ccroot.DEBUG_LEVELS.ALL, + dest = 'debug_level') + except optparse.OptionConflictError: + # the gcc tool might have added that option already + pass + diff -Nru zyn-1+git.20100609/wafadmin/Tools/__init__.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/__init__.py --- zyn-1+git.20100609/wafadmin/Tools/__init__.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/__init__.py 2008-03-23 19:05:47.000000000 +0000 @@ -0,0 +1,8 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2006 (ita) + + diff -Nru zyn-1+git.20100609/wafadmin/Tools/intltool.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/intltool.py --- zyn-1+git.20100609/wafadmin/Tools/intltool.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/intltool.py 2008-03-25 21:02:39.000000000 +0000 @@ -0,0 +1,119 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2006 (ita) + +"intltool support" + +import os, re +import Object, Action, Params, Common, Scan, Utils, Runner +import cc +from Params import fatal, error + +# intltool +class intltool_in_taskgen(Object.task_gen): + def __init__(self): + Object.task_gen.__init__(self) + self.source = '' + self.inst_var = '' + self.inst_dir = '' + self.flags = '' + self.podir = 'po' + self.intlcache = '.intlcache' + self.m_tasks = [] + + def apply(self): + self.env = self.env.copy() + tree = Params.g_build + current = tree.m_curdirnode + for i in self.to_list(self.source): + node = self.path.find_source(i) + + podirnode = self.path.find_source(self.podir) + + self.env['INTLCACHE'] = os.path.join(self.path.bldpath(self.env), self.podir, self.intlcache) + self.env['INTLPODIR'] = podirnode.srcpath(self.env) + self.env['INTLFLAGS'] = self.flags + + task = self.create_task('intltool', self.env) + task.set_inputs(node) + task.set_outputs(node.change_ext('')) + + task.install = {'var': self.inst_var, 'dir': self.inst_dir, 'chmod': 0644} + +class intltool_po_taskgen(Object.task_gen): + def __init__(self, appname='set_your_app_name'): + Object.task_gen.__init__(self) + self.chmod = 0644 + self.inst_var = 'LOCALEDIR' + self.appname = appname + self.m_tasks=[] + + def apply(self): + def install_translation(task): + out = task.m_outputs[0] + filename = out.m_name + (langname, ext) = os.path.splitext(filename) + inst_file = langname + os.sep + 'LC_MESSAGES' + os.sep + self.appname + '.mo' + Common.install_as(self.inst_var, inst_file, out.abspath(self.env), chmod=self.chmod) + + linguas = self.path.find_source('LINGUAS') + if linguas: + # scan LINGUAS file for locales to process + f = open(linguas.abspath()) + re_linguas = re.compile('[-a-zA-Z_@.]+') + for line in f.readlines(): + # Make sure that we only process lines which contain locales + if re_linguas.match(line): + node = self.path.find_build(re_linguas.match(line).group() + '.po') + task = self.create_task('po', self.env) + task.set_inputs(node) + task.set_outputs(node.change_ext('.mo')) + if Params.g_install: task.install = install_translation + else: + Params.pprint('RED', "Error no LINGUAS file found in po directory") + +Action.simple_action('po', '${POCOM} -o ${TGT} ${SRC}', color='BLUE', prio=10) +Action.simple_action('intltool', + '${INTLTOOL} ${INTLFLAGS} -q -u -c ${INTLCACHE} ${INTLPODIR} ${SRC} ${TGT}', + color='BLUE', prio=200) + +def detect(conf): + + conf.check_tool('checks') + + pocom = conf.find_program('msgfmt') + #if not pocom: + # fatal('The program msgfmt (gettext) is mandatory!') + conf.env['POCOM'] = pocom + + intltool = conf.find_program('intltool-merge') + #if not intltool: + # fatal('The program intltool-merge (intltool, gettext-devel) is mandatory!') + conf.env['INTLTOOL'] = intltool + + def getstr(varname): + return getattr(Params.g_options, varname, '') + + prefix = conf.env['PREFIX'] + datadir = getstr('datadir') + if not datadir: datadir = os.path.join(prefix,'share') + + conf.define('LOCALEDIR', os.path.join(datadir, 'locale')) + conf.define('DATADIR', datadir) + + #Define to 1 if you have the header file. + conf.check_header('locale.h', 'HAVE_LOCALE_H') + +def set_options(opt): + try: + opt.add_option('--want-rpath', type='int', default=1, dest='want_rpath', help='set rpath to 1 or 0 [Default 1]') + except Exception: + pass + + for i in "datadir".split(): + opt.add_option('--'+i, type='string', default='', dest=i) + + diff -Nru zyn-1+git.20100609/wafadmin/Tools/java.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/java.py --- zyn-1+git.20100609/wafadmin/Tools/java.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/java.py 2008-03-25 21:02:39.000000000 +0000 @@ -0,0 +1,139 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2006 (ita) + +"Java support" + +import os +import Object, Action, Utils, Params + +class java_taskgen(Object.task_gen): + s_default_ext = ['.java'] + def __init__(self): + Object.task_gen.__init__(self) + + self.jarname = '' + self.jaropts = '' + self.classpath = '' + + # Jar manifest attributes + # TODO: Add manifest creation + self.jar_mf_attributes = {} + self.jar_mf_classpath = [] + + def apply(self): + nodes_lst = [] + + if not self.classpath: + if not self.env['CLASSPATH']: + self.env['CLASSPATH'] = '..' + os.pathsep + '.' + else: + self.env['CLASSPATH'] = self.classpath + + find_source_lst = self.path.find_source_lst + + # first create the nodes corresponding to the sources + for filename in self.to_list(self.source): + + node = find_source_lst(Utils.split_path(filename)) + + base, ext = os.path.splitext(filename) + #node = self.path.find_build(filename) + if not ext in self.s_default_ext: + fatal("unknown file "+filename) + + task = self.create_task('javac', self.env) + task.set_inputs(node) + task.set_outputs(node.change_ext('.class')) + + nodes_lst.append(task.m_outputs[0]) + + if self.jarname: + task = self.create_task('jar_create', self.env) + task.set_inputs(nodes_lst) + task.set_outputs(self.path.find_build_lst(Utils.split_path(self.jarname))) + + if not self.env['JAROPTS']: + if self.jaropts: + self.env['JAROPTS'] = self.jaropts + else: + self.env.append_unique('JAROPTS', '-C %s .' % self.path.bldpath(self.env)) + +Action.simple_action('javac', '${JAVAC} -classpath ${CLASSPATH} -d ${TGT[0].variant(env)} ${SRC}', color='BLUE', prio=10) +Action.simple_action('jar_create', '${JAR} cvf ${TGT} ${JAROPTS}', color='GREEN', prio=50) + +def detect(conf): + # If JAVA_PATH is set, we prepend it to the path list + java_path = os.environ['PATH'].split(os.pathsep) + + if os.environ.has_key('JAVA_HOME'): + java_path = [os.path.join(os.environ['JAVA_HOME'], 'bin')] + java_path + conf.env['JAVA_HOME'] = os.environ['JAVA_HOME'] + + conf.find_program('javac', var='JAVAC', path_list=java_path) + conf.find_program('java', var='JAVA', path_list=java_path) + conf.find_program('jar', var='JAR', path_list=java_path) + conf.env['JAVA_EXT'] = ['.java'] + + if os.environ.has_key('CLASSPATH'): + conf.env['CLASSPATH'] = os.environ['CLASSPATH'] + + conf.hook(check_java_class) + +def check_java_class(conf, classname, with_classpath=None): + """ + Check if specified java class is installed. + """ + + class_check_source = """ +public class Test { + public static void main(String[] argv) { + Class lib; + if (argv.length < 1) { + System.err.println("Missing argument"); + System.exit(77); + } + try { + lib = Class.forName(argv[0]); + } catch (ClassNotFoundException e) { + System.err.println("ClassNotFoundException"); + System.exit(1); + } + lib = null; + System.exit(0); + } +} +""" + import shutil + + javatestdir = '.waf-javatest' + + classpath = javatestdir + if conf.env['CLASSPATH']: + classpath += os.pathsep + conf.env['CLASSPATH'] + if isinstance(with_classpath, str): + classpath += os.pathsep + with_classpath + + shutil.rmtree(javatestdir, True) + os.mkdir(javatestdir) + + java_file = open(os.path.join(javatestdir, 'Test.java'), 'w') + java_file.write(class_check_source) + java_file.close() + + # Compile the source + os.popen(conf.env['JAVAC'] + ' ' + os.path.join(javatestdir, 'Test.java')) + + (jstdin, jstdout, jstderr) = os.popen3(conf.env['JAVA'] + ' -cp ' + classpath + ' Test ' + classname) + + found = not bool(jstderr.read()) + conf.check_message('Java class %s' % classname, "", found) + + shutil.rmtree(javatestdir, True) + + return found + + diff -Nru zyn-1+git.20100609/wafadmin/Tools/kde4.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/kde4.py --- zyn-1+git.20100609/wafadmin/Tools/kde4.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/kde4.py 2008-03-25 21:02:39.000000000 +0000 @@ -0,0 +1,77 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2006 (ita) + +import os, sys, re, Object, Action, Utils, Common + +class msgfmt_taskgen(Object.task_gen): + def __init__(self, appname='set_your_app_name'): + Object.task_gen.__init__(self) + self.langs = '' # for example "foo/fr foo/br" + self.chmod = 0644 + self.inst_var = 'KDE4_LOCALE_INSTALL_DIR' + self.appname = appname + + def apply(self): + + for lang in self.to_list(self.langs): + node = self.path.find_source_lst(Utils.split_path(lang+'.po')) + task = self.create_task('msgfmt', self.env) + task.set_inputs(node) + task.set_outputs(node.change_ext('.mo')) + + if not Params.g_install: continue + langname = lang.split('/') + langname = langname[-1] + inst_dir = langname+os.sep+'LC_MESSAGES' + task.install = {'var':self.inst_var,'dir':inst_dir+'/','as':self.appname+'.mo','chmod':self.chmod} + +def detect(conf): + kdeconfig = conf.find_program('kde4-config') + if not kdeconfig: + conf.fatal('we need kde4-config') + prefix = os.popen('%s --prefix' % kdeconfig).read().strip() + file = '%s/share/apps/cmake/modules/KDELibsDependencies.cmake' % prefix + try: os.stat(file) + except OSError: + file = '%s/share/apps/cmake/modules/KDELibsDependencies.cmake' % prefix + try: os.stat(file) + except: conf.fatal('could not open %s' % file) + + try: + f = open(file, 'r') + txt = f.read() + f.close() + except (OSError, IOError): + conf.fatal('could not read %s' % file) + + txt = txt.replace('\\\n', '\n') + fu = re.compile('#(.*)\n') + txt = fu.sub('', txt) + + setregexp = re.compile('([sS][eE][tT]\s*\()\s*([^\s]+)\s+\"([^"]+)\"\)') + found = setregexp.findall(txt) + + for (_, key, val) in found: + #print key, val + conf.env[key] = val + + # well well, i could just write an interpreter for cmake files + conf.env['LIB_KDECORE']='kdecore' + conf.env['LIB_KDEUI'] ='kdeui' + conf.env['LIB_KIO'] ='kio' + conf.env['LIB_KHTML'] ='khtml' + conf.env['LIB_KPARTS'] ='kparts' + + conf.env['LIBPATH_KDECORE'] = conf.env['KDE4_LIB_INSTALL_DIR'] + conf.env['CPPPATH_KDECORE'] = conf.env['KDE4_INCLUDE_INSTALL_DIR'] + conf.env.append_value('CPPPATH_KDECORE', conf.env['KDE4_INCLUDE_INSTALL_DIR']+"/KDE") + + conf.env['MSGFMT'] = conf.find_program('msgfmt') + +Action.simple_action('msgfmt', '${MSGFMT} ${SRC} -o ${TGT}', color='BLUE', prio=10) + + diff -Nru zyn-1+git.20100609/wafadmin/Tools/libtool.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/libtool.py --- zyn-1+git.20100609/wafadmin/Tools/libtool.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/libtool.py 2008-03-23 20:35:44.000000000 +0000 @@ -0,0 +1,351 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Matthias Jahn, 2008, jahn matthias ath freenet punto de +# Thomas Nagy, 2008 (ita) + +import sys, re, os, optparse + +import Action, Object, Params, Scan, Common, Utils, preproc +from Params import error, debug, fatal, warning +from ccroot import ccroot +from Object import taskgen, after, before + +REVISION="0.1.3" + +""" +if you want to use the code here, you must add the following two methods: +* apply_libtool +* apply_link_libtool + +To do so, use a code similar to the following: +obj = obj.create(...) +obj.want_libtool = 1 +obj.meths.update(['apply_libtool', 'apply_link_libtool']) +""" + +# fake libtool files +fakelibtool_vardeps = ['CXX', 'PREFIX'] +def fakelibtool_build(task): + # Writes a .la file, used by libtool + env = task.env() + dest = open(task.m_outputs[0].abspath(env), 'w') + sname = task.m_inputs[0].m_name + fu = dest.write + fu("# Generated by ltmain.sh - GNU libtool 1.5.18 - (pwn3d by BKsys II code name WAF)\n") + if env['vnum']: + nums = env['vnum'].split('.') + libname = task.m_inputs[0].m_name + name3 = libname+'.'+env['vnum'] + name2 = libname+'.'+nums[0] + name1 = libname + fu("dlname='%s'\n" % name2) + strn = " ".join([name3, name2, name1]) + fu("library_names='%s'\n" % (strn) ) + else: + fu("dlname='%s'\n" % sname) + fu("library_names='%s %s %s'\n" % (sname, sname, sname) ) + fu("old_library=''\n") + vars = ' '.join(env['libtoolvars']+env['LINKFLAGS']) + fu("dependency_libs='%s'\n" % vars) + fu("current=0\n") + fu("age=0\nrevision=0\ninstalled=yes\nshouldnotlink=no\n") + fu("dlopen=''\ndlpreopen=''\n") + fu("libdir='%s/lib'\n" % env['PREFIX']) + dest.close() + return 0 + +def read_la_file(path): + sp = re.compile(r'^([^=]+)=\'(.*)\'$') + dc={} + file = open(path, "r") + for line in file.readlines(): + try: + #print sp.split(line.strip()) + _, left, right, _ = sp.split(line.strip()) + dc[left]=right + except ValueError: + pass + file.close() + return dc + +def apply_link_libtool(self): + if not getattr(self, 'want_libtool', 0): return + + if self.m_type != 'program': + linktask = self.link_task + latask = self.create_task('fakelibtool', self.env) + latask.set_inputs(linktask.m_outputs) + latask.set_outputs(linktask.m_outputs[0].change_ext('.la')) + self.m_latask = latask + + if not (Params.g_commands['install'] or Params.g_commands['uninstall']): return + self.install_results(dest_var, dest_subdir, self.m_latask) + +def apply_libtool(self): + if getattr(self, 'want_libtool', 0) <= 0: return + + self.env['vnum']=self.vnum + + paths=[] + libs=[] + libtool_files=[] + libtool_vars=[] + + for l in self.env['LINKFLAGS']: + if l[:2]=='-L': + paths.append(l[2:]) + elif l[:2]=='-l': + libs.append(l[2:]) + + for l in libs: + for p in paths: + dict = read_la_file(p+'/lib'+l+'.la') + linkflags2 = dict.get('dependency_libs', '') + for v in linkflags2.split(): + if v.endswith('.la'): + libtool_files.append(v) + libtool_vars.append(v) + continue + self.env.append_unique('LINKFLAGS', v) + break + + self.env['libtoolvars']=libtool_vars + + while libtool_files: + file = libtool_files.pop() + dict = read_la_file(file) + for v in dict['dependency_libs'].split(): + if v[-3:] == '.la': + libtool_files.append(v) + continue + self.env.append_unique('LINKFLAGS', v) + +Action.Action('fakelibtool', vars=fakelibtool_vardeps, func=fakelibtool_build, color='BLUE', prio=200) + +class libtool_la_file: + def __init__ (self, la_filename): + self.__la_filename = la_filename + #remove path and .la suffix + self.linkname = str(os.path.split(la_filename)[-1])[:-3] + if self.linkname.startswith("lib"): + self.linkname = self.linkname[3:] + # The name that we can dlopen(3). + self.dlname = None + # Names of this library + self.library_names = None + # The name of the static archive. + self.old_library = None + # Libraries that this one depends upon. + self.dependency_libs = None + # Version information for libIlmImf. + self.current = None + self.age = None + self.revision = None + # Is this an already installed library? + self.installed = None + # Should we warn about portability when linking against -modules? + self.shouldnotlink = None + # Files to dlopen/dlpreopen + self.dlopen = None + self.dlpreopen = None + # Directory that this library needs to be installed in: + self.libdir = '/usr/lib' + if not self.__parse(): + raise "file %s not found!!" %(la_filename) + + def __parse(self): + "Retrieve the variables from a file" + if not os.path.isfile(self.__la_filename): return 0 + la_file=open(self.__la_filename, 'r') + for line in la_file: + ln = line.strip() + if not ln: continue + if ln[0]=='#': continue + (key, value) = str(ln).split('=', 1) + key = key.strip() + value = value.strip() + if value == "no": value = False + elif value == "yes": value = True + else: + try: value = int(value) + except ValueError: value = value.strip("'") + setattr(self, key, value) + la_file.close() + return 1 + + def get_libs(self): + """return linkflags for this lib""" + libs = [] + if self.dependency_libs: + libs = str(self.dependency_libs).strip().split() + if libs == None: + libs = [] + # add la lib and libdir + libs.insert(0, "-l%s" % self.linkname.strip()) + libs.insert(0, "-L%s" % self.libdir.strip()) + return libs + + def __str__(self): + return '''\ +dlname = "%(dlname)s" +library_names = "%(library_names)s" +old_library = "%(old_library)s" +dependency_libs = "%(dependency_libs)s" +version = %(current)s.%(age)s.%(revision)s +installed = "%(installed)s" +shouldnotlink = "%(shouldnotlink)s" +dlopen = "%(dlopen)s" +dlpreopen = "%(dlpreopen)s" +libdir = "%(libdir)s"''' % self.__dict__ + +class libtool_config: + def __init__ (self, la_filename): + self.__libtool_la_file = libtool_la_file(la_filename) + tmp = self.__libtool_la_file + self.__version = [int(tmp.current), int(tmp.age), int(tmp.revision)] + self.__sub_la_files = [] + self.__sub_la_files.append(la_filename) + self.__libs = None + + def __cmp__(self, other): + """make it compareable with X.Y.Z versions (Y and Z are optional)""" + if not other: + return 1 + othervers = [int(s) for s in str(other).split(".")] + selfvers = self.__version + + if selfvers > othervers: + return 1 + if selfvers < othervers: + return -1 + return 0 + + def __str__(self): + return "\n".join([ + str(self.__libtool_la_file), + ' '.join(self.__libtool_la_file.get_libs()), + '* New getlibs:', + ' '.join(self.get_libs()) + ]) + + def __get_la_libs(self, la_filename): + return libtool_la_file(la_filename).get_libs() + + def get_libs(self): + """return the complete uniqe linkflags that do not + contain .la files anymore""" + libs_list = list(self.__libtool_la_file.get_libs()) + libs_map = {} + while len(libs_list) > 0: + entry = libs_list.pop(0) + if entry: + if str(entry).endswith(".la"): + ## prevents duplicate .la checks + if entry not in self.__sub_la_files: + self.__sub_la_files.append(entry) + libs_list.extend(self.__get_la_libs(entry)) + else: + libs_map[entry]=1 + self.__libs = libs_map.keys() + return self.__libs + + def get_libs_only_L(self): + if not self.__libs: self.get_libs() + libs = self.__libs + libs = filter(lambda s: str(s).startswith('-L'), libs) + return libs + + def get_libs_only_l(self): + if not self.__libs: self.get_libs() + libs = self.__libs + libs = filter(lambda s: str(s).startswith('-l'), libs) + return libs + + def get_libs_only_other(self): + if not self.__libs: self.get_libs() + libs = self.__libs + libs = filter(lambda s: not (str(s).startswith('-L') or str(s).startswith('-l')), libs) + return libs + +def useCmdLine(): + """parse cmdline args and control build""" + usage = '''Usage: %prog [options] PathToFile.la +example: %prog --atleast-version=2.0.0 /usr/lib/libIlmImf.la +nor: %prog --libs /usr/lib/libamarok.la''' + parser = optparse.OptionParser(usage) + a = parser.add_option + a("--version", dest = "versionNumber", + action = "store_true", default = False, + help = "output version of libtool-config" + ) + a("--debug", dest = "debug", + action = "store_true", default = False, + help = "enable debug" + ) + a("--libs", dest = "libs", + action = "store_true", default = False, + help = "output all linker flags" + ) + a("--libs-only-l", dest = "libs_only_l", + action = "store_true", default = False, + help = "output -l flags" + ) + a("--libs-only-L", dest = "libs_only_L", + action = "store_true", default = False, + help = "output -L flags" + ) + a("--libs-only-other", dest = "libs_only_other", + action = "store_true", default = False, + help = "output other libs (e.g. -pthread)" + ) + a("--atleast-version", dest = "atleast_version", + default=None, + help = "return 0 if the module is at least version ATLEAST_VERSION" + ) + a("--exact-version", dest = "exact_version", + default=None, + help = "return 0 if the module is exactly version EXACT_VERSION" + ) + a("--max-version", dest = "max_version", + default=None, + help = "return 0 if the module is at no newer than version MAX_VERSION" + ) + + (options, args) = parser.parse_args() + if len(args) != 1 and not options.versionNumber: + parser.error("incorrect number of arguments") + if options.versionNumber: + print "libtool-config version %s" % REVISION + return 0 + ltf = libtool_config(args[0]) + if options.debug: + print(ltf) + if options.atleast_version: + if ltf >= options.atleast_version: return 0 + sys.exit(1) + if options.exact_version: + if ltf == options.exact_version: return 0 + sys.exit(1) + if options.max_version: + if ltf <= options.max_version: return 0 + sys.exit(1) + + def p(x): + print " ".join(x) + if options.libs: p(ltf.get_libs()) + elif options.libs_only_l: p(ltf.get_libs_only_l()) + elif options.libs_only_L: p(ltf.get_libs_only_L()) + elif options.libs_only_other: p(ltf.get_libs_only_other()) + return 0 + +if __name__ == '__main__': + useCmdLine() + + +taskgen(apply_link_libtool) +after('apply_link')(apply_link_libtool) +taskgen(apply_libtool) +before('apply_core')(apply_libtool) diff -Nru zyn-1+git.20100609/wafadmin/Tools/lua.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/lua.py --- zyn-1+git.20100609/wafadmin/Tools/lua.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/lua.py 2008-03-25 21:02:39.000000000 +0000 @@ -0,0 +1,31 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Sebastian Schlingmann, 2008 +# Thomas Nagy, 2008 (ita) + +import Object + +Object.declare_chain( + name = 'luac', + action = '${LUAC} -s -o ${TGT} ${SRC}', + ext_in = '.lua', + ext_out = '.luac', + reentrant = 0, + install = 'LUADIR', # env variable +) + +class lua_taskgen(Object.task_gen): + def __init__(self): + Object.task_gen.__init__(self) + self.chmod = 0755 + self.inst_var = '' + self.inst_dir = '' + +def detect(conf): + luac = conf.find_program('luac', var='LUAC') + if not luac: conf.fatal('cannot find the compiler "luac"') + + diff -Nru zyn-1+git.20100609/wafadmin/Tools/misc.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/misc.py --- zyn-1+git.20100609/wafadmin/Tools/misc.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/misc.py 2008-03-25 21:02:39.000000000 +0000 @@ -0,0 +1,430 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2006 (ita) + +""" +Custom objects: + - execute a function everytime + - copy a file somewhere else +""" + +import shutil, re, os, types + +import Object, Action, Node, Params, Task, Common +import pproc as subprocess +from Params import fatal, debug + +def copy_func(tsk): + "Make a file copy. This might be used to make other kinds of file processing (even calling a compiler is possible)" + env = tsk.env() + infile = tsk.m_inputs[0].abspath(env) + outfile = tsk.m_outputs[0].abspath(env) + try: + shutil.copy2(infile, outfile) + except OSError, IOError: + return 1 + else: + if tsk.chmod: os.chmod(outfile, tsk.chmod) + return 0 + +def action_process_file_func(tsk): + "Ask the function attached to the task to process it" + if not tsk.fun: fatal('task must have a function attached to it for copy_func to work!') + return tsk.fun(tsk) + +class cmd_taskgen(Object.task_gen): + "This object will call a command everytime" + def __init__(self, type='none'): + Object.task_gen.__init__(self) + self.m_type = type + self.prio = 1 + self.fun = None + self.inst_var = '' + self.inst_dir = '' + + def apply(self): + # create a task + if not self.fun: fatal('cmdobj needs a function!') + tsk = Task.TaskCmd(self.fun, self.env) + tsk.prio = self.prio + self.m_tasks.append(tsk) + tsk.install = {'var': self.inst_var, 'dir': self.inst_dir} + +class copy_taskgen(Object.task_gen): + "By default, make a file copy, if fun is provided, fun will make the copy (or call a compiler, etc)" + def __init__(self, type='none'): + Object.task_gen.__init__(self) + + self.source = '' + self.target = '' + self.chmod = '' + self.fun = copy_func + + self.env = Params.g_build.env().copy() + + def apply(self): + + lst = self.to_list(self.source) + + for filename in lst: + node = self.path.find_source(filename) + if not node: fatal('cannot find input file %s for processing' % filename) + + target = self.target + if not target or len(lst)>1: target = node.m_name + + # TODO the file path may be incorrect + newnode = self.path.find_build(target) + + tsk = self.create_task('copy', self.env, 10) + tsk.set_inputs(node) + tsk.set_outputs(newnode) + tsk.m_env = self.env + tsk.fun = self.fun + tsk.chmod = self.chmod + + if not tsk.env(): + tsk.debug() + fatal('task witout an environment') + +def subst_func(tsk): + "Substitutes variables in a .in file" + + m4_re = re.compile('@(\w+)@', re.M) + + env = tsk.env() + infile = tsk.m_inputs[0].abspath(env) + outfile = tsk.m_outputs[0].abspath(env) + + file = open(infile, 'r') + code = file.read() + file.close() + + s = m4_re.sub(r'%(\1)s', code) + + dict = tsk.dict + if not dict: + names = m4_re.findall(code) + for i in names: + if env[i] and type(env[i]) is types.ListType : + dict[i] = " ".join(env[i]) + else: dict[i] = env[i] + + file = open(outfile, 'w') + file.write(s % dict) + file.close() + + return 0 + +class subst_taskgen(Object.task_gen): + def __init__(self, type='none'): + Object.task_gen.__init__(self) + self.fun = subst_func + self.dict = {} + self.prio = 8 + + self.inst_var = '' + self.inst_dir = '' + + def apply(self): + + lst = self.to_list(self.source) + + for filename in lst: + node = self.path.find_source(filename) + if not node: fatal('cannot find input file %s for processing' % filename) + + newnode = node.change_ext('') + + if self.dict and not self.env['DICT_HASH']: + self.env = self.env.copy() + self.env['DICT_HASH'] = hash(str(self.dict)) # <- pretty sure it wont work (ita) + + tsk = self.create_task('copy', self.env, self.prio) + tsk.set_inputs(node) + tsk.set_outputs(newnode) + tsk.m_env = self.env + tsk.fun = self.fun + tsk.dict = self.dict + tsk.dep_vars = ['DICT_HASH'] + tsk.install = {'var': self.inst_var, 'dir': self.inst_dir} + + if not tsk.env(): + tsk.debug() + fatal('task witout an environment') + +class CommandOutputTask(Task.Task): + + def __init__(self, env, priority, command, command_node, command_args, stdin, stdout, cwd): + Task.Task.__init__(self, 'command-output', env, prio=priority, normal=1) + assert isinstance(command, (str, Node.Node)) + self.command = command + self.command_args = command_args + self.stdin = stdin + self.stdout = stdout + self.cwd = cwd + + if command_node is not None: self.dep_nodes = [command_node] + self.dep_vars = [] # additional environment variables to look + +class CommandOutput(Object.task_gen): + + CMD_ARGV_INPUT, CMD_ARGV_OUTPUT, CMD_ARGV_INPUT_DIR, CMD_ARGV_OUTPUT_DIR = range(4) + + def __init__(self, env=None): + Object.task_gen.__init__(self) + self.env = env + if not self.env: + self.env = Params.g_build.env().copy() + + self.stdin = None + self.stdout = None + + # the command to execute + self.command = None + + # whether it is an external command; otherwise it is assumed + # to be an executable binary or script that lives in the + # source or build tree. + self.command_is_external = False + + # extra parameters (argv) to pass to the command (excluding + # the command itself) + self.argv = [] + + # task priority + self.prio = 100 + + # dependencies to other objects -> this is probably not what you want (ita) + # values must be 'task_gen' instances (not names!) + self.dependencies = [] + + # dependencies on env variable contents + self.dep_vars = [] + + # input files that are implicit, i.e. they are not + # stdin, nor are they mentioned explicitly in argv + self.hidden_inputs = [] + + # output files that are implicit, i.e. they are not + # stdout, nor are they mentioned explicitly in argv + self.hidden_outputs = [] + + # change the subprocess to this cwd (must use obj.input_dir() or output_dir() here) + self.cwd = None + + def _command_output_func(task): + assert len(task.m_inputs) > 0 + + def input_path(node, template): + if task.cwd is None: + return template % node.bldpath(task.env()) + else: + return template % node.abspath() + def output_path(node, template): + fun = node.abspath + if task.cwd is None: fun = node.bldpath + return template % fun(task.env()) + + if isinstance(task.command, Node.Node): + argv = [input_path(task.command, '%s')] + else: + argv = [task.command] + + for arg in task.command_args: + if isinstance(arg, str): + argv.append(arg) + else: + role, node, template = arg + if role in (CommandOutput.CMD_ARGV_INPUT, CommandOutput.CMD_ARGV_INPUT_DIR): + argv.append(input_path(node, template)) + elif role in (CommandOutput.CMD_ARGV_OUTPUT, CommandOutput.CMD_ARGV_OUTPUT_DIR): + argv.append(output_path(node, template)) + else: + raise AssertionError + + if task.stdin: + stdin = file(input_path(task.stdin, '%s')) + else: + stdin = None + + if task.stdout: + stdout = file(output_path(task.stdout, '%s'), "w") + else: + stdout = None + + if task.cwd is None: + cwd = ('None (actually %r)' % os.getcwd()) + else: + cwd = repr(task.cwd) + Params.debug("command-output: cwd=%s, stdin=%r, stdout=%r, argv=%r" % + (cwd, stdin, stdout, argv)) + command = subprocess.Popen(argv, stdin=stdin, stdout=stdout, cwd=task.cwd) + return command.wait() + + _command_output_func = staticmethod(_command_output_func) + + def apply(self): + if self.command is None: + Params.fatal("command-output missing command") + if self.command_is_external: + cmd = self.command + cmd_node = None + else: + cmd_node = self.path.find_build(self.command, create=True) + assert cmd_node is not None, ('''Could not find command '%s' in source tree. +Hint: if this is an external command, +use command_is_external=True''') % (self.command,) + cmd = cmd_node + + if self.cwd is None: + cwd = None + else: + role, file_name, template = self.cwd + if role == CommandOutput.CMD_ARGV_INPUT_DIR: + if isinstance(file_name, Node.Node): + input_node = file_name + else: + input_node = self.path.find_dir(file_name) + if input_node is None: + Params.fatal("File %s not found" % (file_name,)) + cwd = input_node.abspath() + elif role == CommandOutput.CMD_ARGV_OUTPUT_DIR: + if isinstance(file_name, Node.Node): + output_node = file_name + else: + output_node = self.path.find_dir(file_name) + if output_node is None: + Params.fatal("File %s not found" % (file_name,)) + cwd = output_node.abspath(self.env) + else: + raise AssertionError + + args = [] + inputs = [] + outputs = [] + + for arg in self.argv: + if isinstance(arg, str): + args.append(arg) + else: + role, file_name, template = arg + if role == CommandOutput.CMD_ARGV_INPUT: + if isinstance(file_name, Node.Node): + input_node = file_name + else: + input_node = self.path.find_build(file_name, create=True) + if input_node is None: + Params.fatal("File %s not found" % (file_name,)) + inputs.append(input_node) + args.append((role, input_node, template)) + elif role == CommandOutput.CMD_ARGV_OUTPUT: + if isinstance(file_name, Node.Node): + output_node = file_name + else: + output_node = self.path.find_build(file_name, create=True) + if output_node is None: + Params.fatal("File %s not found" % (file_name,)) + outputs.append(output_node) + args.append((role, output_node, template)) + elif role == CommandOutput.CMD_ARGV_INPUT_DIR: + if isinstance(file_name, Node.Node): + input_node = file_name + else: + input_node = self.path.find_dir(file_name) + if input_node is None: + Params.fatal("File %s not found" % (file_name,)) + args.append((role, input_node, template)) + elif role == CommandOutput.CMD_ARGV_OUTPUT_DIR: + if isinstance(file_name, Node.Node): + output_node = file_name + else: + output_node = self.path.find_dir(file_name) + if output_node is None: + Params.fatal("File %s not found" % (file_name,)) + args.append((role, output_node, template)) + else: + raise AssertionError + + if self.stdout is None: + stdout = None + else: + stdout = self.path.find_build(self.stdout, create=True) + if stdout is None: + Params.fatal("File %s not found" % (self.stdout,)) + outputs.append(stdout) + + if self.stdin is None: + stdin = None + else: + stdin = self.path.find_build(self.stdin, create=True) + if stdin is None: + Params.fatal("File %s not found" % (self.stdin,)) + inputs.append(stdin) + + for hidden_input in self.to_list(self.hidden_inputs): + node = self.path.find_build(hidden_input, create=True) + if node is None: + Params.fatal("File %s not found in dir %s" % (hidden_input, self.path)) + inputs.append(node) + + for hidden_output in self.to_list(self.hidden_outputs): + node = self.path.find_build(hidden_output, create=True) + if node is None: + Params.fatal("File %s not found in dir %s" % (hidden_output, self.path)) + outputs.append(node) + + if not inputs: + Params.fatal("command-output objects must have at least one input file") + if not outputs: + Params.fatal("command-output objects must have at least one output file") + + task = CommandOutputTask(self.env, self.prio, + cmd, cmd_node, args, + stdin, stdout, cwd) + self.m_tasks.append(task) + + task.set_inputs(inputs) + task.set_outputs(outputs) + task.dep_vars = self.to_list(self.dep_vars) + + + for dep in self.dependencies: + assert dep is not self + if not dep.m_posted: + dep.post() + for dep_task in dep.m_tasks: + task.set_run_after(dep_task) + + def input_file(self, file_name, template='%s'): + """Returns an object to be used as argv element that instructs + the task to use a file from the input vector at the given + position as argv element.""" + return (CommandOutput.CMD_ARGV_INPUT, file_name, template) + + def output_file(self, file_name, template='%s'): + """Returns an object to be used as argv element that instructs + the task to use a file from the output vector at the given + position as argv element.""" + return (CommandOutput.CMD_ARGV_OUTPUT, file_name, template) + + def input_dir(self, file_name, template='%s'): + """Returns an object to be used as argv element that instructs + the task to use a directory path from the input vector at the given + position as argv element.""" + return (CommandOutput.CMD_ARGV_INPUT_DIR, file_name, template) + + def output_dir(self, file_name, template='%s'): + """Returns an object to be used as argv element that instructs + the task to use a directory path from the output vector at the given + position as argv element.""" + return (CommandOutput.CMD_ARGV_OUTPUT_DIR, file_name, template) + +Action.Action('copy', vars=[], func=action_process_file_func) +Action.Action('command-output', func=CommandOutput._command_output_func, color='BLUE') +Object.task_gen.classes['command-output'] = CommandOutput + + diff -Nru zyn-1+git.20100609/wafadmin/Tools/msvc.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/msvc.py --- zyn-1+git.20100609/wafadmin/Tools/msvc.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/msvc.py 2008-03-23 20:35:44.000000000 +0000 @@ -0,0 +1,435 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Carlos Rafael Giani, 2006 (dv) +# Tamas Pal, 2007 (folti) +# Visual C support - beta, needs more testing + +import os, sys, re, string, optparse +import Utils, Action, Params, Object, Runner, Configure +from Params import debug, error, fatal, warning +from Utils import quote_whitespace +from Object import taskgen, after, before, feature + +import ccroot +from libtool import read_la_file +from os.path import exists + +def msvc_linker(task): + """Special linker for MSVC with support for embedding manifests into DLL's + and executables compiled by Visual Studio 2005 or probably later. Without + the manifest file, the binaries are unusable. + See: http://msdn2.microsoft.com/en-us/library/ms235542(VS.80).aspx + Problems with this tool: it is always called whether MSVC creates manifests or not.""" + e = task.env() + linker = e['LINK'] + srcf = e['LINK_SRC_F'] + trgtf = e['LINK_TGT_F'] + linkflags = e.get_flat('LINKFLAGS') + libdirs = e.get_flat('_LIBDIRFLAGS') + libs = e.get_flat('_LIBFLAGS') + + subsystem='' + if task.m_subsystem: + subsystem='/subsystem:%s' % task.m_subsystem + outfile=task.m_outputs[0].bldpath(e) + manifest=outfile+'.manifest' + # pdb file containing the debug symbols (if compiled with /Zi or /ZI and linked with /debug + pdbnode=task.m_outputs[0].change_ext('.pdb') + pdbfile=pdbnode.bldpath(e) + + objs=" ".join(['"%s"' % a.abspath(e) for a in task.m_inputs]) + + cmd="%s %s %s%s %s%s %s %s %s" % (linker,subsystem,srcf,objs,trgtf,outfile, linkflags, libdirs,libs) + ret=Runner.exec_command(cmd) + if ret: return ret + + # check for the pdb file. if exists, add to the list of outputs + if os.path.exists(pdbfile): + task.m_outputs.append(pdbnode) + + if os.path.exists(manifest): + debug('manifesttool', 'msvc') + mtool = e['MT'] + if not mtool: + return 0 + mode='' + # embedding mode. Different for EXE's and DLL's. + # see: http://msdn2.microsoft.com/en-us/library/ms235591(VS.80).aspx + if task.m_type == 'program': + mode='1' + elif task.m_type == 'shlib': + mode='2' + + debug('embedding manifest','msvcobj') + flags = e['MTFLAGS'] + if flags: + flags=string.join(flags,' ') + else: + flags='' + + cmd='%s %s -manifest "%s" -outputresource:"%s";#%s' % (mtool, flags, + manifest, outfile, mode) + ret=Runner.exec_command(cmd) + return ret + +# importlibs provided by MSVC/Platform SDK. Do NOT search them.... +g_msvc_systemlibs = """ +aclui activeds ad1 adptif adsiid advapi32 asycfilt authz bhsupp bits bufferoverflowu cabinet +cap certadm certidl ciuuid clusapi comctl32 comdlg32 comsupp comsuppd comsuppw comsuppwd comsvcs +credui crypt32 cryptnet cryptui d3d8thk daouuid dbgeng dbghelp dciman32 ddao35 ddao35d +ddao35u ddao35ud delayimp dhcpcsvc dhcpsapi dlcapi dnsapi dsprop dsuiext dtchelp +faultrep fcachdll fci fdi framedyd framedyn gdi32 gdiplus glauxglu32 gpedit gpmuuid +gtrts32w gtrtst32hlink htmlhelp httpapi icm32 icmui imagehlp imm32 iphlpapi iprop +kernel32 ksguid ksproxy ksuser libcmt libcmtd libcpmt libcpmtd loadperf lz32 mapi +mapi32 mgmtapi minidump mmc mobsync mpr mprapi mqoa mqrt msacm32 mscms mscoree +msdasc msimg32 msrating mstask msvcmrt msvcurt msvcurtd mswsock msxml2 mtx mtxdm +netapi32 nmapinmsupp npptools ntdsapi ntdsbcli ntmsapi ntquery odbc32 odbcbcp +odbccp32 oldnames ole32 oleacc oleaut32 oledb oledlgolepro32 opends60 opengl32 +osptk parser pdh penter pgobootrun pgort powrprof psapi ptrustm ptrustmd ptrustu +ptrustud qosname rasapi32 rasdlg rassapi resutils riched20 rpcndr rpcns4 rpcrt4 rtm +rtutils runtmchk scarddlg scrnsave scrnsavw secur32 sensapi setupapi sfc shell32 +shfolder shlwapi sisbkup snmpapi sporder srclient sti strsafe svcguid tapi32 thunk32 +traffic unicows url urlmon user32 userenv usp10 uuid uxtheme vcomp vcompd vdmdbg +version vfw32 wbemuuid webpost wiaguid wininet winmm winscard winspool winstrm +wintrust wldap32 wmiutils wow32 ws2_32 wsnmp32 wsock32 wst wtsapi32 xaswitch xolehlp +""".split() + + +def find_lt_names_msvc(self, libname, is_static=False): + """ + Win32/MSVC specific code to glean out information from libtool la files. + this function is not attached to the task_gen class + """ + lt_names=[ + 'lib%s.la' % libname, + '%s.la' % libname, + ] + + for path in self.libpaths: + for la in lt_names: + laf=os.path.join(path,la) + dll=None + if exists(laf): + ltdict=read_la_file(laf) + lt_libdir=None + if ltdict.has_key('libdir') and ltdict['libdir'] != '': + lt_libdir=ltdict['libdir'] + if not is_static and ltdict.has_key('library_names') and ltdict['library_names'] != '': + dllnames=ltdict['library_names'].split() + dll=dllnames[0].lower() + dll=re.sub('\.dll$', '', dll) + return (lt_libdir, dll, False) + elif ltdict.has_key('old_library') and ltdict['old_library'] != '': + olib=ltdict['old_library'] + if exists(os.path.join(path,olib)): + return (path, olib, True) + elif lt_libdir != '' and exists(os.path.join(lt_libdir,olib)): + return (lt_libdir, olib, True) + else: + return (None, olib, True) + else: + fatal('invalid libtool object file: %s' % laf) + return (None, None, None) + +def libname_msvc(self, libname, is_static=False): + lib=libname.lower() + lib=re.sub('\.lib$','',lib) + + if lib in g_msvc_systemlibs: + return lib+'.lib' + + lib=re.sub('^lib','',lib) + + if lib == 'm': + return None + + (lt_path, lt_libname, lt_static) = find_lt_names_msvc(self, lib, is_static) + + if lt_path != None and lt_libname != None: + if lt_static == True: + # file existance check has been made by find_lt_names + return os.path.join(lt_path,lt_libname) + + if lt_path != None: + _libpaths=[lt_path] + self.libpaths + else: + _libpaths=self.libpaths + + static_libs=[ + '%ss.lib' % lib, + 'lib%ss.lib' % lib, + '%s.lib' %lib, + 'lib%s.lib' % lib, + ] + + dynamic_libs=[ + 'lib%s.dll.lib' % lib, + 'lib%s.dll.a' % lib, + '%s.dll.lib' % lib, + '%s.dll.a' % lib, + 'lib%s_d.lib' % lib, + '%s_d.lib' % lib, + '%s.lib' %lib, + ] + + libnames=static_libs + if not is_static: + libnames=dynamic_libs + static_libs + + for path in _libpaths: + for libn in libnames: + if os.path.exists(os.path.join(path,libn)): + debug('lib found: %s' % os.path.join(path,libn), 'msvc') + return libn + + return None + +def apply_msvc_obj_vars(self): + debug('apply_msvc_obj_vars called for msvcobj', 'msvc') + env = self.env + app = env.append_unique + + cpppath_st = env['CPPPATH_ST'] + lib_st = env['LIB_ST'] + staticlib_st = env['STATICLIB_ST'] + libpath_st = env['LIBPATH_ST'] + staticlibpath_st = env['STATICLIBPATH_ST'] + + self.addflags('CPPFLAGS', self.cppflags) + + for i in env['RPATH']: app('LINKFLAGS', i) + for i in env['LIBPATH']: + app('LINKFLAGS', libpath_st % i) + if not self.libpaths.count(i): + self.libpaths.append(i) + for i in env['LIBPATH']: + app('LINKFLAGS', staticlibpath_st % i) + if not self.libpaths.count(i): + self.libpaths.append(i) + + # i doubt that anyone will make a fully static binary anyway + if not env['FULLSTATIC']: + if env['STATICLIB'] or env['LIB']: + app('LINKFLAGS', env['SHLIB_MARKER']) + + if env['STATICLIB']: + app('LINKFLAGS', env['STATICLIB_MARKER']) + for i in env['STATICLIB']: + debug('libname: %s' % i,'msvc') + libname = libname_msvc(self, i, True) + debug('libnamefixed: %s' % libname,'msvc') + if libname != None: + app('LINKFLAGS', libname) + + if self.env['LIB']: + for i in env['LIB']: + debug('libname: %s' % i,'msvc') + libname = libname_msvc(self, i) + debug('libnamefixed: %s' % libname,'msvc') + if libname != None: + app('LINKFLAGS', libname) + +def apply_link_msvc(self): + # if we are only building .o files, tell which ones we built + # FIXME remove the "type" thing + # FIXME simplify this piece of code (about the same is in ccroot.py) + if self.m_type == 'objects': + self.out_nodes = [] + app = self.out_nodes.append + for t in self.compiled_tasks: app(t.m_outputs[0]) + return + + if self.m_type=='staticlib': + linktask = self.create_task('msvc_ar_link_static', self.env) + else: + linktask = self.create_task('msvc_%s_link' % self.m_type_initials, self.env) + outputs = [t.m_outputs[0] for t in self.compiled_tasks] + linktask.set_inputs(outputs) + linktask.set_outputs(self.path.find_build(get_target_name(self))) + + link_task.m_type = self.m_type + link_task.m_subsystem = getattr(self, 'subsystem', '') + self.link_task = linktask + +def init_msvc(self): + "all methods (msvc and non-msvc) are to be executed, but we remove the ones we do not want" + if self.env['MSVC']: + self.meths.remove('apply_link') + else: + for x in ['apply_link_msvc', 'apply_msvc_obj_vars'] + self.meths.remove(x) + self.libpaths = getattr(self, 'libpaths', '') + +static_link_str = '${STLIBLINK} ${LINK_SRC_F}${SRC} ${LINK_TGT_F}${TGT}' +Action.simple_action('msvc_ar_link_static', static_link_str, color='YELLOW', prio=101) +Action.Action('msvc_cc_link', vars=['LINK', 'LINK_SRC_F', 'LINK_TGT_F', 'LINKFLAGS', '_LIBDIRFLAGS', '_LIBFLAGS', 'MT', 'MTFLAGS'] , color='YELLOW', func=msvc_linker, prio=101) +Action.Action('msvc_cpp_link', vars=['LINK', 'LINK_SRC_F', 'LINK_TGT_F', 'LINKFLAGS', '_LIBDIRFLAGS', '_LIBFLAGS', 'MT', 'MTFLAGS'] , color='YELLOW', func=msvc_linker, prio=101) + +rc_str='${RC} ${RCFLAGS} /fo ${TGT} ${SRC}' +Action.simple_action('rc', rc_str, color='GREEN', prio=50) + +import winres + +def detect(conf): + # due to path format limitations, limit operation only to native Win32. Yeah it sucks. + if sys.platform != 'win32': + conf.fatal('MSVC module only works under native Win32 Python! cygwin is not supported yet') + + comp = conf.find_program('CL', var='CXX') + if not comp: conf.fatal('CL was not found (compiler)') + + link = conf.find_program('LINK') + if not link: conf.fatal('LINK was not found (linker)') + + stliblink = conf.find_program('LIB') + if not stliblink: return + + manifesttool = conf.find_program('MT') + + v = conf.env + + # c/c++ compiler - check for whitespace, and if so, add quotes + v['CC'] = quote_whitespace(comp) + v['CXX'] = v['CC'] + v['MSVC'] = 1 + + v['CPPFLAGS'] = ['/W3', '/nologo', '/EHsc', '/errorReport:prompt'] + v['CCDEFINES'] = ['WIN32'] # command-line defines + v['CXXDEFINES'] = ['WIN32'] # command-line defines + + v['_CCINCFLAGS'] = [] + v['_CCDEFFLAGS'] = [] + v['_CXXINCFLAGS'] = [] + v['_CXXDEFFLAGS'] = [] + + v['CC_SRC_F'] = '' + v['CC_TGT_F'] = '/c /Fo' + v['CXX_SRC_F'] = '' + v['CXX_TGT_F'] = '/c /Fo' + + v['CPPPATH_ST'] = '/I%s' # template for adding include paths + + # Subsystem specific flags + v['CPPFLAGS_CONSOLE'] = ['/SUBSYSTEM:CONSOLE'] + v['CPPFLAGS_NATIVE'] = ['/SUBSYSTEM:NATIVE'] + v['CPPFLAGS_POSIX'] = ['/SUBSYSTEM:POSIX'] + v['CPPFLAGS_WINDOWS'] = ['/SUBSYSTEM:WINDOWS'] + v['CPPFLAGS_WINDOWSCE'] = ['/SUBSYSTEM:WINDOWSCE'] + + # CRT specific flags + v['CPPFLAGS_CRT_MULTITHREADED'] = ['/MT'] + v['CPPFLAGS_CRT_MULTITHREADED_DLL'] = ['/MD'] + v['CPPDEFINES_CRT_MULTITHREADED'] = ['_MT'] + v['CPPDEFINES_CRT_MULTITHREADED_DLL'] = ['_MT', '_DLL'] + + v['CPPFLAGS_CRT_MULTITHREADED_DBG'] = ['/MTd'] + v['CPPFLAGS_CRT_MULTITHREADED_DLL_DBG'] = ['/MDd'] + v['CPPDEFINES_CRT_MULTITHREADED_DBG'] = ['_DEBUG', '_MT'] + v['CPPDEFINES_CRT_MULTITHREADED_DLL_DBG'] = ['_DEBUG', '_MT', '_DLL'] + + # compiler debug levels + v['CCFLAGS'] = ['/TC'] + v['CCFLAGS_OPTIMIZED'] = ['/O2', '/DNDEBUG'] + v['CCFLAGS_RELEASE'] = ['/O2', '/DNDEBUG'] + v['CCFLAGS_DEBUG'] = ['/Od', '/RTC1', '/D_DEBUG', '/ZI'] + v['CCFLAGS_ULTRADEBUG'] = ['/Od', '/RTC1', '/D_DEBUG', '/ZI'] + + v['CXXFLAGS'] = ['/TP'] + v['CXXFLAGS_OPTIMIZED'] = ['/O2', '/DNDEBUG'] + v['CXXFLAGS_RELEASE'] = ['/O2', '/DNDEBUG'] + v['CXXFLAGS_DEBUG'] = ['/Od', '/RTC1', '/D_DEBUG', '/ZI'] + v['CXXFLAGS_ULTRADEBUG'] = ['/Od', '/RTC1', '/D_DEBUG', '/ZI'] + + # linker + v['STLIBLINK'] = '\"%s\"' % stliblink + v['LINK'] = '\"%s\"' % link + v['LIB'] = [] + + v['LINK_TGT_F'] = '/OUT:' + v['LINK_SRC_F'] = ' ' + + v['LIB_ST'] = '%s.lib' # template for adding libs + v['LIBPATH_ST'] = '/LIBPATH:%s' # template for adding libpaths + v['STATICLIB_ST'] = '%s.lib' + v['STATICLIBPATH_ST'] = '/LIBPATH:%s' + v['CCDEFINES_ST'] = '/D%s' + v['CXXDEFINES_ST'] = '/D%s' + v['_LIBDIRFLAGS'] = '' + v['_LIBFLAGS'] = '' + + v['SHLIB_MARKER'] = '' + v['STATICLIB_MARKER'] = '' + + conf.check_tool('winres') + + if not conf.env['WINRC']: + warning('Resource compiler not found. Compiling resource file is disabled','msvc') + + # manifest tool. Not required for VS 2003 and below. Must have for VS 2005 and later + if manifesttool: + v['MT'] = quote_whitespace (manifesttool) + v['MTFLAGS']=['/NOLOGO'] + + v['LINKFLAGS'] = ['/NOLOGO', '/MACHINE:X86', '/ERRORREPORT:PROMPT'] + + try: + debug_level = Params.g_options.debug_level.upper() + except AttributeError: + debug_level = ccroot.DEBUG_LEVELS.CUSTOM + v['CCFLAGS'] += v['CCFLAGS_'+debug_level] + v['CXXFLAGS'] += v['CXXFLAGS_'+debug_level] + v['LINKFLAGS'] += v['LINKFLAGS_'+debug_level] + + conf.add_os_flags('CFLAGS', 'CCFLAGS') + conf.add_os_flags('CPPFLAGS') + conf.add_os_flags('CXXFLAGS') + conf.add_os_flags('LINKFLAGS') + + # shared library + v['shlib_CCFLAGS'] = [''] + v['shlib_CXXFLAGS'] = [''] + v['shlib_LINKFLAGS']= ['/DLL'] + v['shlib_PATTERN'] = '%s.dll' + + # plugins. We handle them exactly as shlibs + # everywhere except on osx, where we do bundles + v['plugin_CCFLAGS'] = v['shlib_CCFLAGS'] + v['plugin_LINKFLAGS'] = v['shlib_LINKFLAGS'] + v['plugin_PATTERN'] = v['shlib_PATTERN'] + + # static library + v['staticlib_LINKFLAGS'] = [''] + v['staticlib_PATTERN'] = '%s.lib' + + v['program_PATTERN'] = '%s.exe' + +def set_options(opt): + try: + opt.add_option('-d', '--debug-level', + action = 'store', + default = ccroot.DEBUG_LEVELS.DEBUG, + help = "Specify the debug level, does nothing if CFLAGS is set in the environment. [Allowed Values: '%s']" % "', '".join(ccroot.DEBUG_LEVELS.ALL), + choices = ccroot.DEBUG_LEVELS.ALL, + dest = 'debug_level') + except optparse.OptionConflictError: + pass # maybe already defined by another C-compiler + + +taskgen(apply_msvc_obj_vars) +feature('cc')(apply_msvc_obj_vars) +feature('cxx')(apply_msvc_obj_vars) +after('apply_obj_vars_cc')(apply_msvc_obj_vars) +after('apply_obj_vars_cxx')(apply_msvc_obj_vars) +taskgen(apply_link_msvc) +feature('cc')(apply_link_msvc) +feature('cxx')(apply_link_msvc) +after('apply_core')(apply_link_msvc) +before('apply_obj_vars_cc')(apply_link_msvc) +before('apply_obj_vars_cxx')(apply_link_msvc) +taskgen(init_msvc) +feature('cc')(init_msvc) +feature('cxx')(init_msvc) +before('apply_core')(init_msvc) diff -Nru zyn-1+git.20100609/wafadmin/Tools/nasm.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/nasm.py --- zyn-1+git.20100609/wafadmin/Tools/nasm.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/nasm.py 2008-03-23 20:35:44.000000000 +0000 @@ -0,0 +1,53 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2008 + +""" +Nasm processing +""" + +import os +import Action, Object +from Object import taskgen, before, extension + +nasm_str = '${NASM} ${NASM_FLAGS} ${NASM_INCLUDES} ${SRC} -o ${TGT}' + +EXT_NASM = ['.s'] + +def apply_nasm_vars(self): + + # flags + if hasattr(self, 'nasm_flags'): + for flag in self.to_list(self.nasm_flags): + self.env.append_value('NASM_FLAGS', flag) + + # includes - well, if we suppose it works with c processing + if hasattr(self, 'includes'): + for inc in self.to_list(self.includes): + self.env.append_value('NASM_INCLUDES', '-I %s' % inc.srcpath(self.env)) + +def nasm_file(self, node): + o_node = node.change_ext('.o') + + task = self.create_task('nasm') + task.set_inputs(node) + task.set_outputs(o_node) + + self.compiled_tasks.append(task) + + self.meths.add('apply_nasm_vars') + +# create our action here +Action.simple_action('nasm', nasm_str, color='BLUE', prio=40) + +def detect(conf): + nasm = conf.find_program('nasm', var='NASM') + if not nasm: conf.fatal("could not find nasm, install it or set PATH env var.") + + +taskgen(apply_nasm_vars) +before('apply_link')(apply_nasm_vars) +extension(EXT_NASM)(nasm_file) diff -Nru zyn-1+git.20100609/wafadmin/Tools/ocaml.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/ocaml.py --- zyn-1+git.20100609/wafadmin/Tools/ocaml.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/ocaml.py 2008-03-25 21:02:39.000000000 +0000 @@ -0,0 +1,398 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2006 (ita) + +"ocaml support" + +import os, re +import Params, Action, Object, Scan, Utils, Task +from Params import error, fatal +from Object import taskgen, feature, before, after, extension + +EXT_MLL = ['.mll'] +EXT_MLY = ['.mly'] +EXT_MLI = ['.mli'] +EXT_MLC = ['.c'] +EXT_ML = ['.ml'] + +open_re = re.compile('open ([a-zA-Z]+);;', re.M) + +def filter_comments(filename): + f = open(filename, 'r') + txt = f.read() + f.close() + buf = [] + + i = 0 + max = len(txt) + while i < max: + c = txt[i] + # skip a string + if c == '"': + i += 1 + c = '' + while i < max: + p = c + c = txt[i] + i += 1 + if i == max: return buf + if c == '"': + cnt = 0 + while i < cnt and i < max: + #print "cntcnt = ", str(cnt), self.txt[self.i-2-cnt] + if txt[i-2-cnt] == '\\': cnt+=1 + else: break + #print "cnt is ", str(cnt) + if (cnt%2)==0: break + # skip a char - unfortunately caml is a bit special t' + elif c == "'": + i += 1 + if i == max: return buf + c = txt[i] + if c == '\\': + i += 1 + if i == max: return buf + c = txt[i] + if c == 'x': + i += 2 # skip two chars + i += 1 + if i == max: return buf + c = txt[i] + #if c != '\'': print "uh-oh, invalid character" + + # skip a comment + elif c == '(': + if i == max: break + c = txt[i+1] + # eat (* *) comments + if c == '*': + i += 1 + nesting = 1 + prev = 0 + while i < max: + c = txt[i] + if c == '*': + prev = 1 + elif c == ')' and prev: + if prev: + nesting -= 1 + if nesting == 0: break + elif c == '(': + prev = 0 + if i == max: return buf + i += 1 + c = txt[i] + if c == '*': nesting += 1 + else: + prev = 0 + i += 1 + # a valid char, add it to the buffer + else: + buf.append(c) + i += 1 + return buf + +class ocaml_link(Task.Task): + """link tasks in ocaml are special, the command line calculation must be postponed + until having the dependencies on the compilation tasks, this means that we must + produce the .ml files (lex, ..) to decide the order on which to link the files""" + def __init__(self, action_name, env, normal=1): + Task.Task.__init__(self, action_name, env, normal) + def may_start(self): + if not getattr(self, 'order', ''): + + # now reorder the m_inputs given the task dependencies + if getattr(self, 'bytecode', 0): alltasks = self.obj.bytecode_tasks + else: alltasks = self.obj.native_tasks + + # this part is difficult, we do not have a total order on the tasks + # if the dependencies are wrong, this may not stop + seen = [] + pendant = []+alltasks + while pendant: + task = pendant.pop(0) + if task in seen: continue + for x in task.get_run_after(): + if not x in seen: + pendant.append(task) + break + else: + seen.append(task) + self.m_inputs = [x.m_outputs[0] for x in seen] + self.order=1 + return Task.Task.may_start(self) + +class ocaml_scanner(Scan.scanner): + def __init__(self): + Scan.scanner.__init__(self) + def may_start(self, task): + if getattr(task, 'flag_deps', ''): return 1 + + # the evil part is that we can only compute the dependencies after the + # source files can be read (this means actually producing the source files) + if getattr(task, 'bytecode', ''): alltasks = task.obj.bytecode_tasks + else: alltasks = task.obj.native_tasks + + task.signature() # ensure that files are scanned - unfortunately + tree = Params.g_build + env = task.env() + for node in task.m_inputs: + lst = tree.m_depends_on[node.variant(env)][node] + for depnode in lst: + for t in alltasks: + if t == task: continue + if depnode in t.m_inputs: + task.set_run_after(t) + task.obj.flag_deps = 'ok' + + # TODO necessary to get the signature right - for now + delattr(task, 'sign_all') + task.signature() + + return 1 + + def scan(self, task, node): + #print "scan is called" + code = "".join(filter_comments(node.abspath(task.env()))) + + global open_re + names=[] + import_iterator = open_re.finditer(code) + if import_iterator: + for import_match in import_iterator: + names.append(import_match.group(1)) + found_lst = [] + raw_lst = [] + for name in names: + nd = None + for x in task.incpaths: + nd = x.find_source(name.lower()+'.ml') + if nd: + found_lst.append(nd) + break + else: + raw_lst.append(name) + + return (found_lst, raw_lst) + +g_caml_scanner = ocaml_scanner() + +def get_target_name(self, bytecode): + if bytecode: + if self.islibrary: + return self.target+'.cma' + else: + return self.target+'.run' + else: + if self.m_type == 'c_object': return self.target+'.o' + + if self.islibrary: + return self.target+'.cmxa' + else: + return self.target + +native_lst=['native', 'all', 'c_object'] +bytecode_lst=['bytecode', 'all'] +class ocaml_taskgen(Object.task_gen): + s_default_ext = ['.mli', '.mll', '.mly', '.ml'] + def __init__(self, type='all', library=0): + Object.task_gen.__init__(self) + + self.m_type = type + self.m_source = '' + self.m_target = '' + self.islibrary = library + self._incpaths_lst = [] + self._bld_incpaths_lst = [] + self._mlltasks = [] + self._mlytasks = [] + + self.mlitasks = [] + self.native_tasks = [] + self.bytecode_tasks = [] + self.linktasks = [] + + self.bytecode_env = None + self.native_env = None + + + self.compiled_tasks = [] + self.includes = '' + self.uselib = '' + + self.out_nodes = [] + + self.are_deps_set = 0 + + if not self.env: self.env = Params.g_build.env() + + if not type in ['bytecode','native','all','c_object']: + print 'type for camlobj is undefined '+type + type='all' + + if type in native_lst: + self.native_env = self.env.copy() + self.native_env['OCAMLCOMP'] = self.native_env['OCAMLOPT'] + self.native_env['OCALINK'] = self.native_env['OCAMLOPT'] + if type in bytecode_lst: + self.bytecode_env = self.env.copy() + self.bytecode_env['OCAMLCOMP'] = self.bytecode_env['OCAMLC'] + self.bytecode_env['OCALINK'] = self.bytecode_env['OCAMLC'] + + if self.islibrary: + self.bytecode_env['OCALINKFLAGS'] = '-a' + self.native_env['OCALINKFLAGS'] = '-a' + + if self.m_type == 'c_object': + self.native_env['OCALINK'] = self.native_env['OCALINK']+' -output-obj' + + self.features.append('ocaml') + +Object.add_feature('ocaml', ['apply_core']) + +def apply_incpaths_ml(self): + inc_lst = self.includes.split() + lst = self._incpaths_lst + tree = Params.g_build + for dir in inc_lst: + node = self.path.find_source(dir) + if not node: + error("node not found dammit") + continue + Params.g_build.rescan(node) + if not node in lst: lst.append( node ) + self._bld_incpaths_lst.append(node) + # now the nodes are added to self._incpaths_lst + +def apply_vars_ml(self): + for i in self._incpaths_lst: + if self.bytecode_env: + self.bytecode_env.append_value('OCAMLPATH', '-I %s' % i.srcpath(self.env)) + self.bytecode_env.append_value('OCAMLPATH', '-I %s' % i.bldpath(self.env)) + + if self.native_env: + self.native_env.append_value('OCAMLPATH', '-I %s' % i.bldpath(self.env)) + self.native_env.append_value('OCAMLPATH', '-I %s' % i.srcpath(self.env)) + + varnames = ['INCLUDES', 'OCAMLFLAGS', 'OCALINKFLAGS', 'OCALINKFLAGS_OPT'] + for name in self.uselib.split(): + for vname in varnames: + cnt = self.env[vname+'_'+name] + if cnt: + if self.bytecode_env: self.bytecode_env.append_value(vname, cnt) + if self.native_env: self.native_env.append_value(vname, cnt) + +def apply_link_ml(self): + + if self.bytecode_env: + linktask = ocaml_link('ocalink', self.bytecode_env) + linktask.bytecode = 1 + linktask.set_outputs(self.path.find_build(get_target_name(self, bytecode=1))) + linktask.obj = self + self.linktasks.append(linktask) + if self.native_env: + linktask = ocaml_link('ocalinkopt', self.native_env) + linktask.set_outputs(self.path.find_build(get_target_name(self, bytecode=0))) + linktask.obj = self + self.linktasks.append(linktask) + + self.out_nodes += linktask.m_outputs + + # we produce a .o file to be used by gcc + if self.m_type == 'c_object': self.compiled_tasks.append(linktask) + +def mll_hook(self, node): + mll_task = self.create_task('ocamllex', self.native_env) + mll_task.set_inputs(node) + mll_task.set_outputs(node.change_ext('.ml')) + self.mlltasks.append(mll_task) + + self.allnodes.append(mll_task.m_outputs[0]) + +def mly_hook(self, node): + mly_task = self.create_task('ocamlyacc', self.native_env) + mly_task.set_inputs(node) + mly_task.set_outputs([node.change_ext('.ml'), node.change_ext('.mli')]) + self._mlytasks.append(mly_task) + self.allnodes.append(mly_task.m_outputs[0]) + + task = self.create_task('ocamlcmi', self.native_env) + task.set_inputs(mly_task.m_outputs[1]) + task.set_outputs(mly_task.m_outputs[1].change_ext('.cmi')) + +def mli_hook(self, node): + task = self.create_task('ocamlcmi', self.native_env) + task.set_inputs(node) + task.set_outputs(node.change_ext('.cmi')) + self.mlitasks.append(task) + +def mlc_hook(self, node): + task = self.create_task('ocamlcc', self.native_env) + task.set_inputs(node) + task.set_outputs(node.change_ext('.o')) + + self.out_nodes += task.m_outputs + +def ml_hook(self, node): + if self.native_env: + task = self.create_task('ocaml', self.native_env) + task.set_inputs(node) + task.set_outputs(node.change_ext('.cmx')) + task.m_scanner = g_caml_scanner + task.obj = self + task.incpaths = self._bld_incpaths_lst + self.native_tasks.append(task) + if self.bytecode_env: + task = self.create_task('ocaml', self.bytecode_env) + task.set_inputs(node) + task.m_scanner = g_caml_scanner + task.obj = self + task.bytecode = 1 + task.incpaths = self._bld_incpaths_lst + task.set_outputs(node.change_ext('.cmo')) + self.bytecode_tasks.append(task) + +Action.simple_action('ocaml', '${OCAMLCOMP} ${OCAMLPATH} ${OCAMLFLAGS} ${INCLUDES} -c -o ${TGT} ${SRC}', color='GREEN', prio=60) +Action.simple_action('ocalink', '${OCALINK} -o ${TGT} ${INCLUDES} ${OCALINKFLAGS} ${SRC}', color='YELLOW', prio=99) +Action.simple_action('ocalinkopt', '${OCALINK} -o ${TGT} ${INCLUDES} ${OCALINKFLAGS_OPT} ${SRC}', color='YELLOW', prio=99) +Action.simple_action('ocamlcmi', '${OCAMLC} ${OCAMLPATH} ${INCLUDES} -o ${TGT} -c ${SRC}', color='BLUE', prio=40) +Action.simple_action('ocamlcc', 'cd ${TGT[0].bld_dir(env)} && ${OCAMLOPT} ${OCAMLFLAGS} ${OCAMLPATH} ${INCLUDES} -c ${SRC[0].abspath(env)}', color='GREEN', prio=60) +Action.simple_action('ocamllex', '${OCAMLLEX} ${SRC} -o ${TGT}', color='BLUE', prio=20) +Action.simple_action('ocamlyacc', '${OCAMLYACC} -b ${TGT[0].bldbase(env)} ${SRC}', color='BLUE', prio=20) + +def detect(conf): + opt = conf.find_program('ocamlopt', var='OCAMLOPT') + occ = conf.find_program('ocamlc', var='OCAMLC') + if (not opt) or (not occ): + fatal('The objective caml compiler was not found:\ninstall it or make it available in your PATH') + + conf.env['OCAMLC'] = occ + conf.env['OCAMLOPT'] = opt + conf.env['OCAMLLEX'] = conf.find_program('ocamllex', var='OCAMLLEX') + conf.env['OCAMLYACC'] = conf.find_program('ocamlyacc', var='OCAMLYACC') + conf.env['OCAMLFLAGS'] = '' + conf.env['OCALINK'] = '' + conf.env['OCAMLLIB'] = os.popen(conf.env['OCAMLC']+' -where').read().strip()+os.sep + conf.env['LIBPATH_OCAML'] = os.popen(conf.env['OCAMLC']+' -where').read().strip()+os.sep + conf.env['CPPPATH_OCAML'] = os.popen(conf.env['OCAMLC']+' -where').read().strip()+os.sep + conf.env['LIB_OCAML'] = 'camlrun' + conf.env['OCALINKFLAGS'] = '' + + +taskgen(apply_incpaths_ml) +feature('ocaml')(apply_incpaths_ml) +before('apply_vars_ml')(apply_incpaths_ml) +taskgen(apply_vars_ml) +feature('ocaml')(apply_vars_ml) +before('apply_core')(apply_vars_ml) +taskgen(apply_link_ml) +feature('ocaml')(apply_link_ml) +after('apply_core')(apply_link_ml) +extension(EXT_MLL)(mll_hook) +extension(EXT_MLY)(mly_hook) +extension(EXT_MLI)(mli_hook) +extension(EXT_MLC)(mlc_hook) +extension(EXT_ML)(ml_hook) diff -Nru zyn-1+git.20100609/wafadmin/Tools/osx.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/osx.py --- zyn-1+git.20100609/wafadmin/Tools/osx.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/osx.py 2008-03-23 19:05:47.000000000 +0000 @@ -0,0 +1,95 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 + +"""MacOSX related tools + +To compile an executable into a Mac application bundle, set its 'mac_app' attribute +to a True value: + +obj.mac_app = True +""" + +import os, shutil +import Object, Action +from Object import taskgen, feature, after, before +from Params import error, debug, fatal, warning + +def create_task_macapp(self): + if self.m_type == 'program' and self.link_task: + apptask = self.create_task('macapp', self.env) + apptask.set_inputs(self.link_task.m_outputs) + apptask.set_outputs(self.link_task.m_outputs[0].change_ext('.app')) + self.m_apptask = apptask + +def apply_link_osx(self): + """Use env['MACAPP'] to force *all* executables to be transformed into Mac applications + or use obj.mac_app = True to build specific targets as Mac apps""" + if self.env['MACAPP'] or getattr(self, 'mac_app', False): + self.create_task_macapp() + +app_dirs = ['Contents', os.path.join('Contents','MacOS'), os.path.join('Contents','Resources')] + +app_info = ''' + + + + + CFBundlePackageType + APPL + CFBundleGetInfoString + Created by Waf + CFBundleSignature + ???? + NOTE + THIS IS A GENERATED FILE, DO NOT MODIFY + CFBundleExecutable + %s + + +''' + +def app_build(task): + global app_dirs + env = task.env() + + i = 0 + for p in task.m_outputs: + srcfile = p.srcpath(env) + + debug("creating directories") + try: + os.mkdir(srcfile) + [os.makedirs(os.path.join(srcfile, d)) for d in app_dirs] + except (OSError, IOError): + pass + + # copy the program to the contents dir + srcprg = task.m_inputs[i].srcpath(env) + dst = os.path.join(srcfile, 'Contents', 'MacOS') + debug("copy %s to %s" % (srcprg, dst)) + shutil.copy(srcprg, dst) + + # create info.plist + debug("generate Info.plist") + # TODO: Support custom info.plist contents. + + f = file(os.path.join(srcfile, "Contents", "Info.plist"), "w") + f.write(app_info % os.path.basename(srcprg)) + f.close() + + i += 1 + + return 0 + +x = Action.Action('macapp', vars=[], func=app_build) +x.prio = 300 + + +taskgen(create_task_macapp) +taskgen(apply_link_osx) +after('apply_link')(apply_link_osx) +feature('cc')(apply_link_osx) +feature('cxx')(apply_link_osx) diff -Nru zyn-1+git.20100609/wafadmin/Tools/perl.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/perl.py --- zyn-1+git.20100609/wafadmin/Tools/perl.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/perl.py 2008-03-23 20:35:44.000000000 +0000 @@ -0,0 +1,118 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# andersg at 0x63.nu 2007 + +import os +import pproc as subprocess +import Action, Object, Node, Params +from Object import extension + +xsubpp_str = '${PERL} ${XSUBPP} -noprototypes -typemap ${EXTUTILS_TYPEMAP} ${SRC} > ${TGT}' +EXT_XS = ['.xs'] + +def xsubpp_file(self, node): + gentask = self.create_task('xsubpp') + gentask.set_inputs(node) + gentask.set_outputs(node.change_ext('.c')) + + cctask = self.create_task('cc') + cctask.set_inputs(gentask.m_outputs) + cctask.set_outputs(node.change_ext('.o')) + +Action.simple_action('xsubpp', xsubpp_str, color='BLUE', prio=10) + +def check_perl_version(conf, minver=None): + """ + Checks if perl is installed. + + If installed the variable PERL will be set in environment. + + Perl binary can be overridden by --with-perl-binary config variable + + """ + res = True + + if not getattr(Params.g_options, 'perlbinary', None): + perl = conf.find_program("perl", var="PERL") + if not perl: + return False + else: + perl = Params.g_options.perlbinary + conf.env['PERL'] = perl + + version = os.popen(perl + " -e'printf \"%vd\", $^V'").read() + if not version: + res = False + version = "Unknown" + elif not minver is None: + ver = tuple(map(int, version.split("."))) + if ver < minver: + res = False + + if minver is None: + cver = "" + else: + cver = ".".join(map(str,minver)) + conf.check_message("perl", cver, res, version) + return res + +def check_perl_module(conf, module): + """ + Check if specified perlmodule is installed. + + Minimum version can be specified by specifying it after modulename + like this: + + conf.check_perl_module("Some::Module 2.92") + """ + cmd = [conf.env['PERL'], '-e', 'use %s' % module] + # TODO are you certain ? + r = subprocess.call(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) == 0 + conf.check_message("perl module %s" % module, "", r) + return r + +def check_perl_ext_devel(conf): + """ + Check for configuration needed to build perl extensions. + + Sets different xxx_PERLEXT variables in the environment. + + Also sets the ARCHDIR_PERL variable useful as installation path, + which can be overridden by --with-perl-archdir option. + """ + if not conf.env['PERL']: + return False + + perl = conf.env['PERL'] + + conf.env["LINKFLAGS_PERLEXT"] = os.popen(perl + " -MConfig -e'print $Config{lddlflags}'").read() + conf.env["CPPPATH_PERLEXT"] = os.popen(perl + " -MConfig -e'print \"$Config{archlib}/CORE\"'").read() + conf.env["CCFLAGS_PERLEXT"] = os.popen(perl + " -MConfig -e'print \"$Config{ccflags} $Config{cccdlflags}\"'").read() + + conf.env["XSUBPP"] = os.popen(perl + " -MConfig -e'print \"$Config{privlib}/ExtUtils/xsubpp$Config{exe_ext}\"'").read() + conf.env["EXTUTILS_TYPEMAP"] = os.popen(perl + " -MConfig -e'print \"$Config{privlib}/ExtUtils/typemap\"'").read() + + if not getattr(Params.g_options, 'perlarchdir', None): + conf.env["ARCHDIR_PERL"] = os.popen(perl + " -MConfig -e'print $Config{sitearch}'").read() + else: + conf.env["ARCHDIR_PERL"] = getattr(Params.g_options, 'perlarchdir') + + conf.env["perlext_PATTERN"] = '%s.' + os.popen(perl + " -MConfig -e'print $Config{dlext}'").read() + conf.env["perlext_USELIB"] = "PERL PERLEXT" + + return True + +def detect(conf): + conf.hook(check_perl_version) + conf.hook(check_perl_ext_devel) + conf.hook(check_perl_module) + +def set_options(opt): + opt.add_option("--with-perl-binary", type="string", dest="perlbinary", help = 'Specify alternate perl binary', default=None) + opt.add_option("--with-perl-archdir", type="string", dest="perlarchdir", help = 'Specify directory where to install arch specific files', default=None) + + +extension(EXT_XS)(xsubpp_file) diff -Nru zyn-1+git.20100609/wafadmin/Tools/preproc.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/preproc.py --- zyn-1+git.20100609/wafadmin/Tools/preproc.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/preproc.py 2008-03-23 19:05:47.000000000 +0000 @@ -0,0 +1,723 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2006-2008 (ita) + +#C/C++ preprocessor for finding dependencies +#TODO: more varargs, pragma once + +import re, sys, os, string, types +if __name__ == '__main__': + sys.path = ['.', '..'] + sys.path +import Params +from Params import debug, error, warning +import traceback + +class PreprocError(Exception): + pass + +g_findall = 1 +'search harder for project includes' + +use_trigraphs = 0 +'apply the trigraph rules first' + +strict_quotes = 0 +"Keep <> for system includes (do not search for those includes)" + +g_optrans = { +'not':'!', +'and':'&&', +'bitand':'&', +'and_eq':'&=', +'or':'||', +'bitor':'|', +'or_eq':'|=', +'xor':'^', +'xor_eq':'^=', +'compl':'~', +} +"these ops are for c++, to reset, set an empty dict" + +# ignore #warning and #error +re_lines = re.compile(\ + '^[ \t]*(#|%:)[ \t]*(ifdef|ifndef|if|else|elif|endif|include|import|define|undef|pragma)[ \t]*(.*)\r*$', + re.IGNORECASE | re.MULTILINE) +re_mac = re.compile("^[a-zA-Z_]\w*") +re_fun = re.compile('^[a-zA-Z_][a-zA-Z0-9_]*[(]') +re_pragma_once = re.compile('^\s*once\s*', re.IGNORECASE) +re_nl = re.compile('\\\\\r*\n', re.MULTILINE) +re_cpp = re.compile(\ + r"""(/\*[^*]*\*+([^/*][^*]*\*+)*/)|//[^\n]*|("(\\.|[^"\\])*"|'(\\.|[^'\\])*'|.[^/"'\\]*)""", + re.MULTILINE) +trig_def = [('??'+a, b) for a, b in zip("=-/!'()<>", r'#~\|^[]{}')] +chr_esc = {'0':0, 'a':7, 'b':8, 't':9, 'n':10, 'f':11, 'v':12, 'r':13, '\\':92, "'":39} + +NUM = 'i' +OP = 'O' +IDENT = 'T' +STR = 's' +CHAR = 'c' + +tok_types = [NUM, STR, IDENT, OP] +exp_types = [ + r"""0[xX](?P[a-fA-F0-9]+)(?P[uUlL]*)|L*?'(?P(\\.|[^\\'])+)'|(?P\d+)[Ee](?P[+-]*?\d+)(?P[fFlL]*)|(?P\d*\.\d+)([Ee](?P[+-]*?\d+))?(?P[fFlL]*)|(?P\d+\.\d*)([Ee](?P[+-]*?\d+))?(?P[fFlL]*)|(?P0*)(?P\d+)(?P[uUlL]*)""", + r'L?"([^"\\]|\\.)*"', + r'[a-zA-Z_]\w*', + r'%:%:|<<=|>>=|\.\.\.|<<|<%|<:|<=|>>|>=|\+\+|\+=|--|->|-=|\*=|/=|%:|%=|%>|==|&&|&=|\|\||\|=|\^=|:>|!=|##|[\(\)\{\}\[\]<>\?\|\^\*\+&=:!#;,%/\-\?\~\.]', +] +re_clexer = re.compile('|'.join(["(?P<%s>%s)" % (name, part) for name, part in zip(tok_types, exp_types)]), re.M) + +accepted = 'a' +ignored = 'i' +undefined = 'u' +skipped = 's' + +def repl(m): + s = m.group(1) + if s is not None: return ' ' + s = m.group(3) + if s is None: return '' + return s + +def filter_comments(filename): + # return a list of tuples : keyword, line + f = open(filename, "r") + code = f.read() + f.close() + if use_trigraphs: + for (a, b) in trig_def: code = code.split(a).join(b) + code = re_nl.sub('', code) + code = re_cpp.sub(repl, code) + return [(m.group(2), m.group(3)) for m in re.finditer(re_lines, code)] + +prec = {} +# op -> number, needed for such expressions: #if 1 && 2 != 0 +ops = ['* / %', '+ -', '<< >>', '< <= >= >', '== !=', '& | ^', '&& ||', ','] +for x in range(len(ops)): + syms = ops[x] + for u in syms.split(): + prec[u] = x + +def reduce_nums(val_1, val_2, val_op): + #print val_1, val_2, val_op + # pass two values, return a value + + # now perform the operation, make certain a and b are numeric + try: a = 0 + val_1 + except TypeError: a = int(val_1) + try: b = 0 + val_2 + except TypeError: b = int(val_2) + + d = val_op + if d == '%': c = a%b + elif d=='+': c = a+b + elif d=='-': c = a-b + elif d=='*': c = a*b + elif d=='/': c = a/b + elif d=='^': c = a^b + elif d=='|': c = a|b + elif d=='||': c = int(a or b) + elif d=='&': c = a&b + elif d=='&&': c = int(a and b) + elif d=='==': c = int(a == b) + elif d=='!=': c = int(a != b) + elif d=='<=': c = int(a <= b) + elif d=='<': c = int(a < b) + elif d=='>': c = int(a > b) + elif d=='>=': c = int(a >= b) + elif d=='^': c = int(a^b) + elif d=='<<': c = a<>': c = a>>b + else: c = 0 + return c + +def get_expr(lst, defs, ban): + + if not lst: return ([], [], []) + + (p, v) = lst[0] + if p == NUM: + return (p, v, lst[1:]) + + elif p == STR: + try: + (p2, v2) = lst[1] + if p2 == STR: return (p, v+v2, lst[2:]) + except IndexError: pass + + return (p, v, lst[1:]) + + elif p == OP: + if v in ['+', '-', '!', '~', '#']: + (p2, v2, lst2) = get_expr(lst[1:], defs, ban) + + if v == '#': + if p2 != IDENT: raise PreprocError, "ident expected %s" % str(lst) + return get_expr([(STR, v2)]+lst2, defs, ban) + + if p2 != NUM: raise PreprocError, "num expected %s" % str(lst) + + if v == '+': return (p2, v2, lst2) + elif v == '-': return (p2, - int(v2), lst2) + elif v == '!': return (p2, int(not int(v2)), lst2) + elif v == '~': return (p2, ~ int(v2), lst2) + + return (p2, v2, lst2) + + elif v == '(': + count_par = 0 + i = 0 + for _, v in lst: + if v == ')': + count_par -= 1 + if count_par == 0: break + elif v == '(': count_par += 1 + i += 1 + else: + raise PreprocError, "rparen expected %s" % str(lst) + + ret = process_tokens(lst[1:i], defs, ban) + if len(ret) == 1: + (p, v) = ret[0] + return (p, v, lst[i+1:]) + else: + #return (None, lst1, lst[i+1:]) + raise PreprocError, "cannot reduce %s" % str(lst) + + elif p == IDENT: + if len(lst)>1: + (p2, v2) = lst[1] + if v2 == "##": + # token pasting, reevaluate the identifier obtained + (p3, v3) = lst[2] + if p3 != IDENT and p3 != NUM and p3 != OP: + raise PreprocError, "%s: ident expected after '##'" % str(lst) + return get_expr([(p, v+v3)]+lst[3:], defs, ban) + + if v.lower() == 'defined': + (p2, v2) = lst[1] + off = 2 + if v2 == '(': + (p3, v3) = lst[2] + if p3 != IDENT: raise PreprocError, 'expected an identifier after a "defined("' + (p2, v2) = lst[3] + if v2 != ')': raise PreprocError, 'expected a ")" after a "defined(x"' + off = 4 + elif p2 != IDENT: + raise PreprocError, 'expected a "(" or an identifier after a defined' + + x = 0 + if v2 in defs: x = 1 + #return get_expr([(NUM, x)] + lst[off:], defs, ban) + return (NUM, x, lst[off:]) + + elif not v in defs or v in ban: + if "waf_include" in ban: return (p, v, lst[1:]) + else: return (NUM, 0, lst[1:]) + + # tokenize on demand + if type(defs[v]) is types.StringType: + v, k = extract_macro(defs[v]) + defs[v] = k + macro_def = defs[v] + + if not macro_def[0]: + # simple macro, substitute, and reevaluate + lst = macro_def[1] + lst[1:] + return get_expr(lst, defs, ban) + else: + # collect the arguments for the funcall + params = [] + i = 1 + p2, v2 = lst[i] + if p2 != OP or v2 != '(': raise PreprocError, "invalid function call '%s'" % v + + one_param = [] + count_paren = 0 + try: + while 1: + i += 1 + p2, v2 = lst[i] + + if p2 == OP and count_paren == 0: + if v2 == '(': + one_param.append((p2, v2)) + count_paren += 1 + elif v2 == ')': + if one_param: params.append(one_param) + lst = lst[i+1:] + break + elif v2 == ',': + if not one_param: raise PreprocError, "empty param in funcall %s" % p + params.append(one_param) + one_param = [] + else: + one_param.append((p2, v2)) + else: + one_param.append((p2, v2)) + if v2 == '(': count_paren += 1 + elif v2 == ')': count_paren -= 1 + + except IndexError, e: + #raise PreprocError, 'invalid function call %s: missing ")"' % p + raise + + # substitute the arguments within the define expression + accu = [] + table = macro_def[0] + for p2, v2 in macro_def[1]: + if p2 == IDENT and v2 in table: accu += params[table[v2]] + else: + if v2 == '__VA_ARGS__': + # first collect the tokens + va_toks = [] + st = len(macro_def[0]) + pt = len(params) + for x in params[pt-st+1:]: + va_toks.extend(x) + va_toks.append((OP, ',')) + if va_toks: va_toks.pop() # extra comma + if len(accu)>1: + (p3, v3) = accu[-1] + (p4, v4) = accu[-2] + if v3 == '##': + # remove the token paste + accu.pop() + if v4 == ',' and pt < st: + # remove the comma + accu.pop() + accu += va_toks + else: + accu.append((p2, v2)) + + return get_expr(accu + lst, defs, ban+[v]) + +def process_tokens(lst, defs, ban): + accu = [] + while lst: + p, v, nlst = get_expr(lst, defs, ban) + if p == NUM: + if not nlst: return [(p, v)] # finished + + op1, ov1 = nlst[0] + if op1 != OP: + raise PreprocError, "op expected %s" % str(lst) + + if ov1 == '?': + i = 0 + count_par = 0 + for _, k in nlst: + if k == ')': count_par -= 1 + elif k == '(': count_par += 1 + elif k == ':' and count_par == 0: break + i += 1 + else: raise PreprocError, "ending ':' expected %s" % str(lst) + + if reduce_nums(v, 0, '+'): lst = nlst[1:i] + else: lst = nlst[i+1:] + continue + + elif ov1 == ',': + lst = nlst[1:] + continue + + p2, v2, nlst = get_expr(nlst[1:], defs, ban) + if p2 != NUM: raise PreprocError, "num expected after op %s" % str(lst) + if nlst: + # op precedence + op3, ov3 = nlst[0] + if prec[ov3] < prec[ov1]: + #print "ov3", ov3, ov1 + # as needed + p4, v4, nlst2 = get_expr(nlst[1:], defs, ban) + v5 = reduce_nums(v2, v4, ov3) + lst = [(p, v), (op1, ov1), (NUM, v5)] + nlst2 + continue + + # no op precedence or empty list, reduce the first tokens + lst = [(NUM, reduce_nums(v, v2, ov1))] + nlst + continue + + elif p == STR: + if nlst: raise PreprocError, "sequence must terminate with a string %s" % str(nlst) + return [(p, v)] + + return (None, None, []) + +def eval_macro(lst, adefs): + # look at the result, and try to return a 0/1 result + ret = process_tokens(lst, adefs, []) + if not ret: raise PreprocError, "missing tokens to evaluate %s" % str(lst) + p, v = ret[0] + return int(v) != 0 + +def try_exists(node, list): + lst = []+list + while lst: + name = lst.pop(0) + # it is not a build node, else we would already got it + path = os.path.join(node.abspath(), name) + try: os.stat(path) + except OSError: + #traceback.print_exc() + return None + node = node.find_dir_lst([name]) + return node + +class c_parser(object): + def __init__(self, nodepaths=None, strpaths=None, defines=None): + #self.lines = txt.split('\n') + self.lines = [] + + if defines is None: + self.defs = {} + else: + self.defs = dict(defines) # make a copy + self.state = [] + + self.env = None # needed for the variant when searching for files + + # include paths + if strpaths is None: + self.strpaths = [] + else: + self.strpaths = strpaths + self.pathcontents = {} + + self.deps = [] + self.deps_paths = [] + + if nodepaths is None: + self.m_nodepaths = [] + else: + self.m_nodepaths = nodepaths + self.m_nodes = [] + self.m_names = [] + + # file added + self.curfile = '' + self.ban_includes = [] + + # dynamic cache + try: + self.parse_cache = Params.g_build.parse_cache + except AttributeError: + Params.g_build.parse_cache = {} + self.parse_cache = Params.g_build.parse_cache + + def tryfind(self, filename): + self.curfile = filename + global g_findall + if self.m_nodepaths: + found = 0 + for n in self.m_nodepaths: + found = n.find_source(filename, create=0) + if found: + break + # second pass for unreachable folders + if not found and g_findall: + lst = filename.split('/') + if len(lst)>1: + lst=lst[:-1] # take the folders only + try: cache = Params.g_build.preproc_cache + except AttributeError: Params.g_build.preproc_cache = cache = {} + key = hash( (str(self.m_nodepaths), str(lst)) ) + if not cache.get(key, None): + cache[key] = 1 + for n in self.m_nodepaths: + node = try_exists(n, lst) + if node: + found = n.find_source(filename, create=0) + if found: break + if found: + self.m_nodes.append(found) + # Qt + if filename[-4:] != '.moc': self.addlines(found.abspath(self.env)) + if not found: + if not filename in self.m_names: + self.m_names.append(filename) + else: + found = 0 + for p in self.strpaths: + if not p in self.pathcontents.keys(): + self.pathcontents[p] = os.listdir(p) + if filename in self.pathcontents[p]: + #print "file %s found in path %s" % (filename, p) + np = os.path.join(p, filename) + # screw Qt two times + if filename[-4:] != '.moc': self.addlines(np) + self.deps_paths.append(np) + found = 1 + if not found: + pass + #error("could not find %s " % filename) + + def addlines(self, filepath): + pc = self.parse_cache + debug("reading file %r" % filepath, 'preproc') + if filepath in pc.keys(): + self.lines = pc[filepath] + self.lines + return + + try: + lines = filter_comments(filepath) + pc[filepath] = lines # memorize the lines filtered + self.lines = lines + self.lines + except IOError: + raise PreprocError, "could not read the file %s" % filepath + except Exception: + if Params.g_verbose > 0: + warning("parsing %s failed" % filepath) + traceback.print_exc() + + def start(self, node, env): + debug("scanning %s (in %s)" % (node.m_name, node.m_parent.m_name), 'preproc') + + self.env = env + variant = node.variant(env) + + self.addlines(node.abspath(env)) + if env['DEFLINES']: + self.lines = [('define', x) for x in env['DEFLINES']] + self.lines + + while self.lines: + (type, line) = self.lines.pop(0) + try: + self.process_line(type, line) + except Exception, ex: + if Params.g_verbose: + warning("line parsing failed (%s): %s" % (str(ex), line)) + traceback.print_exc() + + # debug only + def start_local(self, filename): + self.addlines(filename) + #print self.lines + while self.lines: + (type, line) = self.lines.pop(0) + try: + self.process_line(type, line) + except Exception, ex: + if Params.g_verbose: + warning("line parsing failed (%s): %s" % (str(ex), line)) + traceback.print_exc() + raise + + def process_line(self, token, line): + ve = Params.g_verbose + if ve: debug("line is %s - %s state is %s" % (token, line, self.state), 'preproc') + state = self.state + + # make certain we define the state if we are about to enter in an if block + if token in ['ifdef', 'ifndef', 'if']: + state.append(undefined) + elif token == 'endif': + state.pop() + + # skip lines when in a dead 'if' branch, wait for the endif + if not token in ['else', 'elif', 'endif']: + if skipped in self.state or ignored in self.state: + return + + if token == 'if': + ret = eval_macro(tokenize(line), self.defs) + if ret: state[-1] = accepted + else: state[-1] = ignored + elif token == 'ifdef': + m = re_mac.search(line) + if m and m.group(0) in self.defs: state[-1] = accepted + else: state[-1] = ignored + elif token == 'ifndef': + m = re_mac.search(line) + if m and m.group(0) in self.defs: state[-1] = ignored + else: state[-1] = accepted + elif token == 'include' or token == 'import': + (type, inc) = extract_include(line, self.defs) + if inc in self.ban_includes: return + if token == 'import': self.ban_includes.append(inc) + if ve: debug("include found %s (%s) " % (inc, type), 'preproc') + if type == '"' or not strict_quotes: + if not inc in self.deps: + self.deps.append(inc) + self.tryfind(inc) + elif token == 'elif': + if state[-1] == accepted: + state[-1] = skipped + elif state[-1] == ignored: + if eval_macro(tokenize(line), self.defs): + state[-1] = accepted + elif token == 'else': + if state[-1] == accepted: state[-1] = skipped + elif state[-1] == ignored: state[-1] = accepted + elif token == 'define': + m = re_mac.search(line) + if m: + name = m.group(0) + if ve: debug("define %s %s" % (name, line), 'preproc') + self.defs[name] = line + else: + raise PreprocError, "invalid define line %s" % line + elif token == 'undef': + m = re_mac.search(line) + if m and m.group(0) in self.defs: + self.defs.__delitem__(m.group(0)) + #print "undef %s" % name + elif token == 'pragma': + if re_pragma_once.search(line.lower()): + self.ban_includes.append(self.curfile) + +def extract_macro(txt): + t = tokenize(txt) + if re_fun.search(txt): + p, name = t[0] + + p, v = t[1] + if p != OP: raise PreprocError, "expected open parenthesis" + + i = 1 + pindex = 0 + params = {} + wantident = 1 + + while 1: + i += 1 + p, v = t[i] + + if wantident: + if p == IDENT: + params[v] = pindex + pindex += 1 + elif v == '...': + pass + else: + raise PreprocError, "expected ident" + else: + if v == ',': + pass + elif v == ')': + break + elif v == '...': + raise PreprocError, "not implemented" + wantident = not wantident + + return (name, [params, t[i+1:]]) + else: + (p, v) = t[0] + return (v, [[], t[1:]]) + +re_include = re.compile('^\s*(<(?P.*)>|"(?P.*)")') +def extract_include(txt, defs): + m = re_include.search(txt) + if m: + if m.group('a'): return '<', m.group('a') + if m.group('b'): return '"', m.group('b') + + # perform preprocessing and look at the result, it must match an include + tokens = process_tokens(tokens, defs, ['waf_include']) + p, v = tokens[0] + if p != STR: raise PreprocError, "could not parse include %s" % txt + return ('"', v) + +def parse_char(txt): + if not txt: raise PreprocError, "attempted to parse a null char" + if txt[0] != '\\': + return ord(txt) + c = txt[1] + if c == 'x': + if len(txt) == 4 and txt[3] in string.hexdigits: return int(txt[2:], 16) + return int(txt[2:], 16) + elif c.isdigit(): + if c == '0' and len(txt)==2: return 0 + for i in 3, 2, 1: + if len(txt) > i and txt[1:1+i].isdigit(): + return (1+i, int(txt[1:1+i], 8)) + else: + try: return chr_esc[c] + except KeyError: raise PreprocError, "could not parse char literal '%s'" % txt + +def tokenize(s): + ret = [] + for match in re_clexer.finditer(s): + m = match.group + for name in tok_types: + v = m(name) + if v: + if name == IDENT: + try: v = g_optrans[v]; name = OP + except KeyError: + # c++ specific + if v.lower() == "true": + v = 1 + name = NUM + elif v.lower() == "false": + v = 0 + name = NUM + elif name == NUM: + if m('oct'): v = int(v, 8) + elif m('hex'): v = int(m('hex'), 16) + elif m('n0'): v = m('n0') + else: + v = m('char') + if v: v = parse_char(v) + else: v = m('n2') or m('n4') + elif name == OP: + if v == '%:': v='#' + elif v == '%:%:': v='##' + + ret.append((name, v)) + break + return ret + +# quick test # +if __name__ == "__main__": + Params.g_verbose = 2 + Params.g_zones = ['preproc'] + class dum: + def __init__(self): + self.parse_cache = {} + Params.g_build = dum() + + try: arg = sys.argv[1] + except IndexError: arg = "file.c" + + paths = ['.'] + f = open(arg, "r"); txt = f.read(); f.close() + + m1 = [[], [(NUM, 1), (OP, '+'), (NUM, 2)]] + fun1 = [[(IDENT, 'x'), (IDENT, 'y')], [(IDENT, 'x'), (OP, '##'), (IDENT, 'y')]] + fun2 = [[(IDENT, 'x'), (IDENT, 'y')], [(IDENT, 'x'), (OP, '*'), (IDENT, 'y')]] + + def test(x): + y = process_tokens(tokenize(x), {'m1':m1, 'fun1':fun1, 'fun2':fun2}, []) + #print x, y + + test("0&&2<3") + test("(5>1)*6") + test("1+2+((3+4)+5)+6==(6*7)/2==1*-1*-1") + test("1,2,3*9,9") + test("1?77:88") + test("0?77:88") + test("1?1,(0?5:9):3,4") + test("defined inex") + test("defined(inex)") + test("m1*3") + test("7*m1*3") + test("fun1(m,1)") + test("fun2(2, fun1(m, 1))") + #test("foo##.##h") + + gruik = c_parser(strpaths = paths) + gruik.start_local(arg) + print "we have found the following dependencies" + print gruik.deps + print gruik.deps_paths + + #f = open(arg, "r") + #txt = f.read() + #f.close() + #print tokenize(txt) + + diff -Nru zyn-1+git.20100609/wafadmin/Tools/python.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/python.py --- zyn-1+git.20100609/wafadmin/Tools/python.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/python.py 2008-03-25 21:02:39.000000000 +0000 @@ -0,0 +1,312 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2007 (ita) +# Gustavo Carneiro (gjc), 2007 + +"Python support" + +import os, sys +import Object, Action, Utils, Params, Common, Utils +from Object import extension +import pproc as subprocess + +EXT_PY = ['.py'] + +def process_py(self, node): + + if self.env['PYC']: + t1 = self.create_task('pyc', self.env) + t1.set_inputs(node) + t1.set_outputs(node.change_ext('.pyc')) + + if self.env['PYO']: + t2 = self.create_task('pyo', self.env) + t2.set_inputs(node) + t2.set_outputs(node.change_ext('.pyo')) + + if Params.g_install: + inst_src = not self.env['NOPY'] + install = {'var': self.inst_var, 'dir': self.inst_dir, 'chmod': self.chmod, 'src': inst_src} + + try: t2.install = install + except: pass + try: t1.install = install + except: pass + +class py_taskgen(Object.task_gen): + def __init__(self, env=None): + Object.task_gen.__init__(self) + + self.inst_var = 'PYTHONDIR' + self.inst_dir = '' + self.chmod = 0644 + +Action.simple_action('pyc', '${PYTHON} ${PYFLAGS} -c ${PYCMD} ${SRC} ${TGT}', color='BLUE', prio=50) +Action.simple_action('pyo', '${PYTHON} ${PYFLAGS_OPT} -c ${PYCMD} ${SRC} ${TGT}', color='BLUE', prio=50) + +def _get_python_variables(python_exe, variables, imports=['import sys']): + """Run a python interpreter and print some variables""" + program = list(imports) + program.append('') + for v in variables: + program.append("print repr(%s)" % v) + proc = subprocess.Popen([python_exe, "-c", '\n'.join(program)], + stdout=subprocess.PIPE) + output = proc.communicate()[0].split("\n") + if proc.returncode: + if Params.g_verbose: + Params.warning("Python program to extract python configuration variables failed:\n%s" + % '\n'.join(["line %03i: %s" % (lineno+1, line) for lineno, line in enumerate(program)])) + raise ValueError + return_values = [] + for s in output: + s = s.strip() + if not s: + continue + if s == 'None': + return_values.append(None) + elif s[0] == "'" and s[-1] == "'": + return_values.append(s[1:-1]) + elif s[0].isdigit(): + return_values.append(int(s)) + else: break + return return_values + +def check_python_headers(conf): + """Check for headers and libraries necessary to extend or embed python. + + If successful, xxx_PYEXT and xxx_PYEMBED variables are defined in the + enviroment (for uselib). PYEXT should be used for compiling + python extensions, while PYEMBED should be used by programs that + need to embed a python interpreter. + + Note: this test requires that check_python_version was previously + executed and successful.""" + + try: import distutils + except ImportError: return 0 + + env = conf.env + python = env['PYTHON'] + assert python, ("python is %r !" % (python,)) + + try: + # Get some python configuration variables using distutils + v = 'prefix SO SYSLIBS SHLIBS LIBDIR LIBPL INCLUDEPY Py_ENABLE_SHARED'.split() + (python_prefix, python_SO, python_SYSLIBS, python_SHLIBS, + python_LIBDIR, python_LIBPL, INCLUDEPY, Py_ENABLE_SHARED) = \ + _get_python_variables(python, ["get_config_var('%s')" % x for x in v], + ['from distutils.sysconfig import get_config_var']) + except ValueError: + conf.fatal("Python development headers not found (-v for details).") + + env['pyext_PATTERN'] = '%s'+python_SO + + # Check for python libraries for embedding + if python_SYSLIBS is not None: + for lib in python_SYSLIBS.split(): + if lib.startswith('-l'): + lib = lib[2:] # strip '-l' + env.append_value('LIB_PYEMBED', lib) + if python_SHLIBS is not None: + for lib in python_SHLIBS.split(): + if lib.startswith('-l'): + lib = lib[2:] # strip '-l' + env.append_value('LIB_PYEMBED', lib) + lib = conf.create_library_configurator() + lib.name = 'python' + env['PYTHON_VERSION'] + lib.uselib = 'PYTHON' + lib.code = ''' +#ifdef __cplusplus +extern "C" { +#endif + void Py_Initialize(void); + void Py_Finalize(void); +#ifdef __cplusplus +} +#endif +int main(int argc, char *argv[]) { Py_Initialize(); Py_Finalize(); return 0; } +''' + if python_LIBDIR is not None: + lib.path = [python_LIBDIR] + result = lib.run() + else: + result = 0 + + ## try again with -L$python_LIBPL (some systems don't install the python library in $prefix/lib) + if not result: + if python_LIBPL is not None: + lib.path = [python_LIBPL] + result = lib.run() + else: + result = 0 + + ## try again with -L$prefix/libs, and pythonXY name rather than pythonX.Y (win32) + if not result: + lib.path = [os.path.join(python_prefix, "libs")] + lib.name = 'python' + env['PYTHON_VERSION'].replace('.', '') + result = lib.run() + + if result: + env['LIBPATH_PYEMBED'] = lib.path + env.append_value('LIB_PYEMBED', lib.name) + + + # according to + # distutils.command.build_ext.build_ext.get_libraries.__doc__ + # this might want to be OS/2 aswell. + if sys.platform == 'win32' or (Py_ENABLE_SHARED is not None + and sys.platform != 'darwin'): + env['LIBPATH_PYEXT'] = env['LIBPATH_PYEMBED'] + env['LIB_PYEXT'] = env['LIB_PYEMBED'] + + # We check that pythonX.Y-config exists, and if it exists we + # use it to get only the includes, else fall back to distutils. + python_config = conf.find_program( + 'python%s-config' % ('.'.join(env['PYTHON_VERSION'].split('.')[:2])), + var='PYTHON_CONFIG') + if python_config: + includes = [] + for incstr in os.popen("%s %s --includes" % (python, python_config)).readline().strip().split(): + # strip the -I or /I + if (incstr.startswith('-I') + or incstr.startswith('/I')): + incstr = incstr[2:] + # append include path, unless already given + if incstr not in includes: + includes.append(incstr) + env['CPPPATH_PYEXT'] = list(includes) + env['CPPPATH_PYEMBED'] = list(includes) + else: + env['CPPPATH_PYEXT'] = [INCLUDEPY] + env['CPPPATH_PYEMBED'] = [INCLUDEPY] + + # Code using the Python API needs to be compiled with -fno-strict-aliasing + if env['CC']: + version = os.popen("%s --version" % env['CC']).readline() + if '(GCC)' in version: + env.append_value('CCFLAGS_PYEMBED', '-fno-strict-aliasing') + env.append_value('CCFLAGS_PYEXT', '-fno-strict-aliasing') + if env['CXX']: + version = os.popen("%s --version" % env['CXX']).readline() + if '(GCC)' in version: + env.append_value('CXXFLAGS_PYEMBED', '-fno-strict-aliasing') + env.append_value('CXXFLAGS_PYEXT', '-fno-strict-aliasing') + + # Test to see if it compiles + header = conf.create_header_configurator() + header.name = 'Python.h' + header.define = 'HAVE_PYTHON_H' + header.uselib = 'PYEXT' + header.code = "#include \nint main(int argc, char *argv[]) { Py_Initialize(); Py_Finalize(); return 0; }" + result = header.run() + if not result: + conf.fatal("Python development headers not found.") + +def check_python_version(conf, minver=None): + """ + Check if the python interpreter is found matching a given minimum version. + minver should be a tuple, eg. to check for python >= 2.4.2 pass (2,4,2) as minver. + + If successful, PYTHON_VERSION is defined as 'MAJOR.MINOR' + (eg. '2.4') of the actual python version found, and PYTHONDIR is + defined, pointing to the site-packages directory appropriate for + this python version, where modules/packages/extensions should be + installed. + """ + assert minver is None or isinstance(minver, tuple) + python = conf.env['PYTHON'] + assert python, ("python is %r !" % (python,)) + + # Get python version string + cmd = [python, "-c", "import sys\nfor x in sys.version_info: print str(x)"] + Params.debug("Running python command %r" % cmd, 'python') + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE) + lines = proc.communicate()[0].split() + assert len(lines) == 5, "found %i lines, expected 5: %r" % (len(lines), lines) + pyver_tuple = (int(lines[0]), int(lines[1]), int(lines[2]), lines[3], int(lines[4])) + + # compare python version with the minimum required + result = (minver is None) or (pyver_tuple >= minver) + + if result: + # define useful environment variables + pyver = '.'.join([str(x) for x in pyver_tuple[:2]]) + conf.env['PYTHON_VERSION'] = pyver + + if 'PYTHONDIR' in os.environ: + pydir = os.environ['PYTHONDIR'] + else: + if sys.platform == 'win32': + (python_LIBDEST,) = \ + _get_python_variables(python, ["get_config_var('LIBDEST')"], + ['from distutils.sysconfig import get_config_var']) + else: + python_LIBDEST = None + if python_LIBDEST is None: + if conf.env['LIBDIR']: + python_LIBDEST = os.path.join(conf.env['LIBDIR'], "python" + pyver) + else: + python_LIBDEST = os.path.join(conf.env['PREFIX'], "lib", "python" + pyver) + pydir = os.path.join(python_LIBDEST, "site-packages") + + conf.define('PYTHONDIR', pydir) + conf.env['PYTHONDIR'] = pydir + + # Feedback + pyver_full = '.'.join(map(str, pyver_tuple[:3])) + if minver is None: + conf.check_message_custom('Python version', '', pyver_full) + else: + minver_str = '.'.join(map(str, minver)) + conf.check_message('Python version', ">= %s" % (minver_str,), result, option=pyver_full) + + if not result: + conf.fatal("Python too old.") + +def check_python_module(conf, module_name): + """ + Check if the selected python interpreter can import the given python module. + """ + result = not subprocess.Popen([conf.env['PYTHON'], "-c", "import %s" % module_name], + stderr=subprocess.PIPE, stdout=subprocess.PIPE).wait() + conf.check_message('Python module', module_name, result) + if not result: + conf.fatal("Python module not found.") + +def detect(conf): + python = conf.find_program('python', var='PYTHON') + if not python: return + + v = conf.env + + v['PYCMD'] = '"import sys, py_compile;py_compile.compile(sys.argv[1], sys.argv[2])"' + v['PYFLAGS'] = '' + v['PYFLAGS_OPT'] = '-O' + + v['PYC'] = getattr(Params.g_options, 'pyc', 1) + v['PYO'] = getattr(Params.g_options, 'pyo', 1) + + # FIXME - this thing must be updated + #v['pyext_INST_VAR'] = 'PYTHONDIR' + #v['pyext_INST_DIR'] = '' + + #v['pyembed_INST_DIR'] = v['program_INST_DIR'] + + # now a small difference + v['pyext_USELIB'] = 'PYEXT' + v['pyembed_USELIB'] = 'PYEMBED' + + conf.hook(check_python_version) + conf.hook(check_python_headers) + conf.hook(check_python_module) + +def set_options(opt): + opt.add_option('--nopyc', action = 'store_false', default = 1, help = 'no pyc files (configuration)', dest = 'pyc') + opt.add_option('--nopyo', action = 'store_false', default = 1, help = 'no pyo files (configuration)', dest = 'pyo') + + +extension(EXT_PY)(process_py) diff -Nru zyn-1+git.20100609/wafadmin/Tools/qt4.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/qt4.py --- zyn-1+git.20100609/wafadmin/Tools/qt4.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/qt4.py 2008-03-25 21:02:39.000000000 +0000 @@ -0,0 +1,472 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2006 (ita) + +""" +Qt4 support + +If QT4_ROOT is given (absolute path), the configuration will look in it first + +This module also demonstrates how to add tasks dynamically (when the build has started) +""" + +import os, sys +import ccroot, cxx +import Action, Params, Object, Task, Utils, Runner +from Object import taskgen, feature, after, extension +from Params import error, fatal + +MOC_H = ['.h', '.hpp', '.hxx', '.hh'] +EXT_RCC = ['.qrc'] +EXT_UI = ['.ui'] +EXT_QT4 = ['.cpp', '.cc', '.cxx', '.C', '.c'] + +class MTask(Task.Task): + "A cpp task that may create a moc task dynamically" + def __init__(self, action_name, env, parent, priority=10): + Task.Task.__init__(self, action_name, env, priority) + self.moc_done = 0 + self.parent = parent + + def may_start(self): + + if self.moc_done: + # if there is a moc task, delay the computation of the file signature + for t in self.get_run_after(): + if not t.m_hasrun: + return 0 + # we need to recompute the signature as the moc task has finally run + # unfortunately, the moc file enters in the dependency calculation TODO + delattr(self, 'sign_all') + self.signature() + return Task.Task.may_start(self) + + tree = Params.g_build + parn = self.parent + node = self.m_inputs[0] + + # to know if there is a moc file to create + self.signature() + + moctasks=[] + mocfiles=[] + variant = node.variant(parn.env) + try: + tmp_lst = tree.m_raw_deps[variant][node] + tree.m_raw_deps[variant][node] = [] + except KeyError: + tmp_lst = [] + for d in tmp_lst: + if not d.endswith('.moc'): continue + # paranoid check + if d in mocfiles: + error("paranoia owns") + continue + # process that base.moc only once + mocfiles.append(d) + + # find the extension - this search is done only once + ext = '' + try: ext = Params.g_options.qt_header_ext + except AttributeError: pass + + if not ext: + base2 = d[:-4] + path = node.m_parent.srcpath(parn.env) + for i in MOC_H: + try: + # TODO we could use find_source + os.stat(os.path.join(path, base2+i)) + except OSError: + pass + else: + ext = i + break + if not ext: fatal("no header found for %s which is a moc file" % str(d)) + + # next time we will not search for the extension (look at the 'for' loop below) + h_node = node.m_parent.find_source(base2+i) + m_node = h_node.change_ext('.moc') + tree.m_depends_on[variant][m_node] = h_node + + # create the task + task = Task.Task('moc', parn.env, normal=0) + task.set_inputs(h_node) + task.set_outputs(m_node) + + generator = Params.g_build.generator + generator.outstanding.insert(0, task) + generator.total += 1 + + moctasks.append(task) + + # remove raw deps except the moc files to save space (optimization) + tmp_lst = tree.m_raw_deps[variant][node] = mocfiles + + # look at the file inputs, it is set right above + try: lst = tree.m_depends_on[variant][node] + except KeyError: lst=[] + for d in lst: + name = d.m_name + if name.endswith('.moc'): + task = Task.Task('moc', parn.env, normal=0) + task.set_inputs(tree.m_depends_on[variant][d]) + task.set_outputs(d) + + generator = Params.g_build.generator + generator.outstanding.insert(0, task) + generator.total += 1 + + moctasks.append(task) + break + # simple scheduler dependency: run the moc task before others + self.m_run_after = moctasks + self.moc_done = 1 + return 0 + +def translation_update(task): + outs=[a.abspath(task.env) for a in task.m_outputs] + outs=" ".join(outs) + lupdate = task.env['QT_LUPDATE'] + + for x in task.m_inputs: + file = x.abspath(task.env) + cmd = "%s %s -ts %s" % (lupdate, file, outs) + Params.pprint('BLUE', cmd) + Runner.exec_command(cmd) + +def create_rcc_task(self, node): + "hook for rcc files" + # run rcctask with one of the highest priority + # TODO add the dependency on the files listed in .qrc + rcnode = node.change_ext('_rc.cpp') + + rcctask = self.create_task('rcc', self.env) + rcctask.m_inputs = [node] + rcctask.m_outputs = [rcnode] + + cpptask = self.create_task('cpp', self.env) + cpptask.m_inputs = [rcnode] + cpptask.m_outputs = [rcnode.change_ext('.o')] + + self.compiled_tasks.append(cpptask) + + return cpptask + +def create_uic_task(self, node): + "hook for uic tasks" + uictask = self.create_task('ui4', self.env) + uictask.m_inputs = [node] + uictask.m_outputs = [node.change_ext('.h')] + +class qt4obj(cxx.cpp_taskgen): + def __init__(self, type='program', subtype=None): + cxx.cpp_taskgen.__init__(self, type, subtype) + self.link_task = None + self.lang = '' + self.langname = '' + self.update = 0 + self.features.append('qt4') + +def apply_qt4(self): + if self.lang: + lst=[] + trans=[] + for l in self.to_list(self.lang): + t = Task.Task('ts2qm', self.env, 4) + t.set_inputs(self.path.find_build(l+'.ts')) + t.set_outputs(t.m_inputs[0].change_ext('.qm')) + lst.append(t.m_outputs[0]) + + if self.update: + trans.append(t.m_inputs[0]) + + if self.update and Params.g_options.trans_qt4: + # we need the cpp files given, except the rcc task we create after + u = Task.TaskCmd(translation_update, self.env, 2) + u.m_inputs = [a.m_inputs[0] for a in self.compiled_tasks] + u.m_outputs = trans + + if self.langname: + t = Task.Task('qm2rcc', self.env, 40) + t.set_inputs(lst) + t.set_outputs(self.path.find_build(self.langname+'.qrc')) + t.path = self.path + k = create_rcc_task(self, t.m_outputs[0]) + self.link_task.m_inputs.append(k.m_outputs[0]) + + lst = [] + for flag in self.to_list(self.env['CXXFLAGS']): + if len(flag) < 2: continue + if flag[0:2] == '-D' or flag[0:2] == '-I': + lst.append(flag) + self.env['MOC_FLAGS'] = lst + +def find_sources_in_dirs(self, dirnames, excludes=[], exts=[]): + "the .ts files are added to self.lang" + lst=[] + excludes = self.to_list(excludes) + #make sure dirnames is a list helps with dirnames with spaces + dirnames = self.to_list(dirnames) + + ext_lst = exts or self.mappings.keys() + Object.task_gen.mappings.keys() + + for name in dirnames: + #print "name is ", name + anode = self.path.ensure_node_from_lst(Utils.split_path(name)) + #print "anode ", anode.m_name, " ", anode.files() + Params.g_build.rescan(anode) + #print "anode ", anode.m_name, " ", anode.files() + + for file in anode.files(): + #print "file found ->", file + (base, ext) = os.path.splitext(file.m_name) + if ext in ext_lst: + s = file.relpath(self.path) + if not s in lst: + if s in excludes: continue + lst.append(s) + elif ext == '.ts': + self.lang += ' '+base + + lst.sort() + self.source = self.source+' '+(" ".join(lst)) +setattr(qt4obj, 'find_sources_in_dirs', find_sources_in_dirs) + +def cxx_hook(self, node): + # create the compilation task: cpp or cc + task = MTask('cpp', self.env, self) + self.m_tasks.append(task) + try: obj_ext = self.obj_ext + except AttributeError: obj_ext = '_%s.o' % self.m_type[:2] + + task.m_scanner = ccroot.g_c_scanner + task.path_lst = self.inc_paths + task.defines = self.scanner_defines + + task.m_inputs = [node] + task.m_outputs = [node.change_ext(obj_ext)] + self.compiled_tasks.append(task) + +def process_qm2rcc(task): + outfile = task.m_outputs[0].abspath(task.env()) + f = open(outfile, 'w') + f.write('\n\n') + for k in task.m_inputs: + f.write(' ') + #f.write(k.m_name) + f.write(k.relpath(task.path)) + f.write('\n') + f.write('\n') + f.close() + +Action.simple_action('moc', '${QT_MOC} ${MOC_FLAGS} ${SRC} ${MOC_ST} ${TGT}', color='BLUE', vars=['QT_MOC', 'MOC_FLAGS'], prio=100) +Action.simple_action('rcc', '${QT_RCC} -name ${SRC[0].m_name} ${SRC} ${RCC_ST} -o ${TGT}', color='BLUE', prio=60) +Action.simple_action('ui4', '${QT_UIC} ${SRC} -o ${TGT}', color='BLUE', prio=60) +Action.simple_action('ts2qm', '${QT_LRELEASE} ${SRC} -qm ${TGT}', color='BLUE', prio=40) + +Action.Action('qm2rcc', vars=[], func=process_qm2rcc, color='BLUE', prio=60) + +def detect_qt4(conf): + env = conf.env + opt = Params.g_options + + qtlibs = getattr(opt, 'qtlibs', '') + qtincludes = getattr(opt, 'qtincludes', '') + qtbin = getattr(opt, 'qtbin', '') + useframework = getattr(opt, 'use_qt4_osxframework', True) + qtdir = getattr(opt, 'qtdir', '') + + if not qtdir: qtdir = os.environ.get('QT4_ROOT', '') + + if not qtdir: + try: + lst = os.listdir('/usr/local/Trolltech/') + lst.sort() + lst.reverse() + qtdir = '/usr/local/Trolltech/%s/' % lst[0] + + except OSError: + pass + + if not qtdir: + try: + path = os.environ['PATH'].split(':') + for qmk in ['qmake-qt4', 'qmake4', 'qmake']: + qmake = conf.find_program(qmk, path) + if qmake: + version = os.popen(qmake+" -query QT_VERSION").read().strip().split('.') + if version[0] == "4": + qtincludes = os.popen(qmake+" -query QT_INSTALL_HEADERS").read().strip() + qtdir = os.popen(qmake + " -query QT_INSTALL_PREFIX").read().strip()+"/" + qtbin = os.popen(qmake + " -query QT_INSTALL_BINS").read().strip()+"/" + break + except OSError: + pass + + # check for the qt includes first + if not qtincludes: qtincludes = qtdir + 'include/' + env['QTINCLUDEPATH']=qtincludes + + lst = [qtincludes, '/usr/share/qt4/include/', '/opt/qt4/include'] + test = conf.create_header_enumerator() + test.name = 'QtGui/QFont' + test.path = lst + test.mandatory = 1 + ret = test.run() + + + # check for the qtbinaries + if not qtbin: qtbin = qtdir + 'bin/' + + binpath = [qtbin, '/usr/share/qt4/bin/'] + os.environ['PATH'].split(':') + def find_bin(lst, var): + for f in lst: + ret = conf.find_program(f, path_list=binpath) + if ret: + env[var]=ret + break + + find_bin(['uic-qt3', 'uic3'], 'QT_UIC3') + + find_bin(['uic-qt4', 'uic'], 'QT_UIC') + version = os.popen(env['QT_UIC'] + " -version 2>&1").read().strip() + version = version.replace('Qt User Interface Compiler ','') + version = version.replace('User Interface Compiler for Qt', '') + if version.find(" 3.") != -1: + conf.check_message('uic version', '(too old)', 0, option='(%s)'%version) + sys.exit(1) + conf.check_message('uic version', '', 1, option='(%s)'%version) + + find_bin(['moc-qt4', 'moc'], 'QT_MOC') + find_bin(['rcc'], 'QT_RCC') + find_bin(['lrelease-qt4', 'lrelease'], 'QT_LRELEASE') + find_bin(['lupdate-qt4', 'lupdate'], 'QT_LUPDATE') + + env['UIC3_ST']= '%s -o %s' + env['UIC_ST'] = '%s -o %s' + env['MOC_ST'] = '-o' + + + # check for the qt libraries + if not qtlibs: qtlibs = qtdir + 'lib' + + vars = "Qt3Support QtCore QtGui QtNetwork QtOpenGL QtSql QtSvg QtTest QtXml QtWebKit".split() + + framework_ok = False + if sys.platform == "darwin" and useframework: + for i in vars: + e = conf.create_framework_configurator() + e.path = [qtlibs] + e.name = i + e.remove_dot_h = 1 + e.run() + + if not i == 'QtCore': + # strip -F flag so it don't get reduant + for r in env['CCFLAGS_' + i.upper()]: + if r.startswith('-F'): + env['CCFLAGS_' + i.upper()].remove(r) + break + + incflag = '-I%s' % os.path.join(qtincludes, i) + if not incflag in env["CCFLAGS_" + i.upper ()]: + env['CCFLAGS_' + i.upper ()] += [incflag] + if not incflag in env["CXXFLAGS_" + i.upper ()]: + env['CXXFLAGS_' + i.upper ()] += [incflag] + + # now we add some static depends. + if conf.is_defined("HAVE_QTOPENGL"): + if not '-framework OpenGL' in env["LINKFLAGS_QTOPENGL"]: + env["LINKFLAGS_QTOPENGL"] += ['-framework OpenGL'] + + if conf.is_defined("HAVE_QTGUI"): + if not '-framework AppKit' in env["LINKFLAGS_QTGUI"]: + env["LINKFLAGS_QTGUI"] += ['-framework AppKit'] + if not '-framework ApplicationServices' in env["LINKFLAGS_QTGUI"]: + env["LINKFLAGS_QTGUI"] += ['-framework ApplicationServices'] + + framework_ok = True + + if not framework_ok: # framework_ok is false either when the platform isn't OSX, Qt4 shall not be used as framework, or Qt4 could not be found as framework + vars_debug = [a+'_debug' for a in vars] + + for i in vars_debug+vars: + #conf.check_pkg(i, pkgpath=qtlibs) + pkgconf = conf.create_pkgconfig_configurator() + pkgconf.name = i + pkgconf.pkgpath = '%s:%s/pkgconfig:/usr/lib/qt4/lib/pkgconfig:/opt/qt4/lib/pkgconfig:/usr/lib/qt4/lib:/opt/qt4/lib' % (qtlibs, qtlibs) + pkgconf.run() + + + # the libpaths are set nicely, unfortunately they make really long command-lines + # remove the qtcore ones from qtgui, etc + def process_lib(vars_, coreval): + for d in vars_: + var = d.upper() + if var == 'QTCORE': continue + + value = env['LIBPATH_'+var] + if value: + core = env[coreval] + accu = [] + for lib in value: + if lib in core: continue + accu.append(lib) + env['LIBPATH_'+var] = accu + + process_lib(vars, 'LIBPATH_QTCORE') + process_lib(vars_debug, 'LIBPATH_QTCORE_DEBUG') + + # rpath if wanted + if Params.g_options.want_rpath: + def process_rpath(vars_, coreval): + for d in vars_: + var = d.upper() + value = env['LIBPATH_'+var] + if value: + core = env[coreval] + accu = [] + for lib in value: + if var != 'QTCORE': + if lib in core: + continue + accu.append('-Wl,--rpath='+lib) + env['RPATH_'+var] = accu + process_rpath(vars, 'LIBPATH_QTCORE') + process_rpath(vars_debug, 'LIBPATH_QTCORE_DEBUG') + + env['QTLOCALE'] = str(env['PREFIX'])+'/share/locale' + +def detect(conf): + if sys.platform=='win32': fatal('Qt4.py will not work on win32 for now - ask the author') + detect_qt4(conf) + +def set_options(opt): + try: opt.add_option('--want-rpath', type='int', default=1, dest='want_rpath', help='set rpath to 1 or 0 [Default 1]') + except Exception: pass + + opt.add_option('--header-ext', + type='string', + default='', + help='header extension for moc files', + dest='qt_header_ext') + + for i in "qtdir qtincludes qtlibs qtbin".split(): + opt.add_option('--'+i, type='string', default='', dest=i) + + if sys.platform == "darwin": + opt.add_option('--no-qt4-framework', action="store_false", help='do not use the framework version of Qt4 in OS X', dest='use_qt4_osxframework',default=True) + + opt.add_option('--translate', action="store_true", help="collect translation strings", dest="trans_qt4", default=False) + + +extension(EXT_RCC)(create_rcc_task) +extension(EXT_UI)(create_uic_task) +taskgen(apply_qt4) +feature('qt4')(apply_qt4) +after('apply_link')(apply_qt4) +extension(EXT_QT4)(cxx_hook) diff -Nru zyn-1+git.20100609/wafadmin/Tools/sconpat.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/sconpat.py --- zyn-1+git.20100609/wafadmin/Tools/sconpat.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/sconpat.py 2008-03-23 19:05:47.000000000 +0000 @@ -0,0 +1,70 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2006-2008 (ita) + +try: from hashlib import md5 +except ImportError: from md5 import md5 +import Utils, Configure, Action, Task, Params +from Params import error, fatal + +class sconpat_error(Exception): + pass + +class Builder_class(object): + def __init__(self): + self.action = None + self.generator = None + def init(self, **kw): + if kw.has_key('generator') and kw.has_key('action'): + raise sconpat_error, 'do not mix action and generator in a builder' + + if kw.has_key('action'): + + a = kw['action'].replace('$SOURCES', '${SRC}') + a = a.replace('$TARGETS', '${TGT}') + a = a.replace('$TARGET', '${TGT[0].abspath(env)}') + a = a.replace('$SOURCE', '${SRC[0].abspath(env)}') + + m = md5() + m.update(a) + key = m.hexdigest() + + Action.simple_action(key, a, kw.get('color', 'GREEN')) + self.action=key + def apply(self, target, source, **kw): + #print "Builder_class apply called" + #print kw['env'] + #print target + #print source + + curdir = Params.g_build.m_curdirnode + + t = Task.Task(self.action, kw['env'], 10) + t.set_inputs(curdir.find_source(source, create=1)) + t.set_outputs(curdir.find_build(target, create=1)) + +def Builder(**kw): + ret = Builder_class() + ret.init(**kw) + return ret + +def Environment(**kw): + import Environment + ret = Environment.Environment() + if kw.has_key('BUILDERS'): + bd = kw['BUILDERS'] + for k in bd: + # store the builder name on the builder + bd[k].name = k + + def miapply(self, *lst, **kw): + if not 'env' in kw: kw['env']=ret + bd[k].apply(*lst, **kw) + + ret.__class__.__dict__[k]=miapply + return ret + + diff -Nru zyn-1+git.20100609/wafadmin/Tools/suncc.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/suncc.py --- zyn-1+git.20100609/wafadmin/Tools/suncc.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/suncc.py 2008-03-23 19:05:47.000000000 +0000 @@ -0,0 +1,125 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2006 (ita) +# Ralf Habacker, 2006 (rh) + +import os, optparse +import Utils, Action, Params, Configure +import ccroot, ar + +def find_cc(conf): + v = conf.env + cc = None + if v['CC']: cc = v['CC'] + elif 'CC' in os.environ: cc = os.environ['CC'] + #if not cc: cc = conf.find_program('gcc', var='CC') + if not cc: cc = conf.find_program('cc', var='CC') + if not cc: conf.fatal('suncc was not found') + v['CC'] = cc + + #TODO: Has anyone a better idea to check if this is a sun cc? + ret = os.popen("%s -flags" % cc).close() + if ret: + conf.check_message('suncc', '', not ret) + return + +def common_flags(conf): + v = conf.env + + # CPPFLAGS CCDEFINES _CCINCFLAGS _CCDEFFLAGS _LIBDIRFLAGS _LIBFLAGS + + v['CC_SRC_F'] = '' + v['CC_TGT_F'] = '-c -o ' + v['CPPPATH_ST'] = '-I%s' # template for adding include paths + + # linker + if not v['LINK_CC']: v['LINK_CC'] = v['CC'] + v['CCLNK_SRC_F'] = '' + v['CCLNK_TGT_F'] = '-o ' + + v['LIB_ST'] = '-l%s' # template for adding libs + v['LIBPATH_ST'] = '-L%s' # template for adding libpaths + v['STATICLIB_ST'] = '-l%s' + v['STATICLIBPATH_ST'] = '-L%s' + v['CCDEFINES_ST'] = '-D%s' + + + v['SHLIB_MARKER'] = '-Bdynamic' + v['STATICLIB_MARKER'] = '-Bstatic' + + # program + v['program_PATTERN'] = '%s' + + # shared library + v['shlib_CCFLAGS'] = ['-Kpic', '-DPIC'] + v['shlib_LINKFLAGS'] = ['-G'] + v['shlib_PATTERN'] = 'lib%s.so' + + # static lib + v['staticlib_LINKFLAGS'] = ['-Bstatic'] + v['staticlib_PATTERN'] = 'lib%s.a' + + v['plugin_CCFLAGS'] = v['shlib_CCFLAGS'] + v['plugin_LINKFLAGS'] = v['shlib_LINKFLAGS'] + v['plugin_PATTERN'] = v['shlib_PATTERN'] + +def modifier_debug(conf): + v = conf.env + + # compiler debug levels + v['CCFLAGS'] = ['-O'] + if conf.check_flags('-O2'): + v['CCFLAGS_OPTIMIZED'] = ['-O2'] + v['CCFLAGS_RELEASE'] = ['-O2'] + if conf.check_flags('-g -DDEBUG'): + v['CCFLAGS_DEBUG'] = ['-g', '-DDEBUG'] + if conf.check_flags('-g3 -O0 -DDEBUG'): + v['CCFLAGS_ULTRADEBUG'] = ['-g3', '-O0', '-DDEBUG'] + + # see the option below + try: + debug_level = Params.g_options.debug_level.upper() + except AttributeError: + debug_level = ccroot.DEBUG_LEVELS.CUSTOM + v.append_value('CCFLAGS', v['CCFLAGS_'+debug_level]) + +def detect(conf): + + # TODO FIXME later it will start from eval_rules + # funcs = [find_cc, find_cpp, find_ar, common_flags, modifier_win32] + #eval_rules(conf, funcs, on_error) + + find_cc(conf) + ar.find_cpp(conf) + ar.find_ar(conf) + + conf.check_tool('cc') + + common_flags(conf) + #modifier_plugin(conf) + + conf.check_tool('checks') + conf.check_features() + + modifier_debug(conf) + + conf.add_os_flags('CFLAGS', 'CCFLAGS') + conf.add_os_flags('CPPFLAGS') + conf.add_os_flags('LINKFLAGS') + +def set_options(opt): + try: + opt.add_option('-d', '--debug-level', + action = 'store', + default = ccroot.DEBUG_LEVELS.RELEASE, + help = "Specify the debug level, does nothing if CFLAGS is set in the environment. [Allowed Values: '%s']" % "', '".join(ccroot.DEBUG_LEVELS.ALL), + choices = ccroot.DEBUG_LEVELS.ALL, + dest = 'debug_level') + except optparse.OptionConflictError: + # the sunc++ tool might have added that option already + pass + + diff -Nru zyn-1+git.20100609/wafadmin/Tools/sunc++.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/sunc++.py --- zyn-1+git.20100609/wafadmin/Tools/sunc++.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/sunc++.py 2008-03-23 19:05:47.000000000 +0000 @@ -0,0 +1,107 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2006 (ita) +# Ralf Habacker, 2006 (rh) + +import os, optparse +import Utils, Action, Params, Configure +import ccroot, ar + +def find_cxx(conf): + v = conf.env + cc = None + if v['CXX']: cc = v['CXX'] + elif 'CXX' in os.environ: cc = os.environ['CXX'] + #if not cc: cc = conf.find_program('g++', var='CXX') + if not cc: cc = conf.find_program('c++', var='CXX') + if not cc: conf.fatal('sunc++ was not found') + v['CXX'] = cc + +def common_flags(conf): + v = conf.env + + # CPPFLAGS CXXDEFINES _CXXINCFLAGS _CXXDEFFLAGS _LIBDIRFLAGS _LIBFLAGS + + v['CXX_SRC_F'] = '' + v['CXX_TGT_F'] = '-c -o ' + v['CPPPATH_ST'] = '-I%s' # template for adding include paths + + # linker + if not v['LINK_CXX']: v['LINK_CXX'] = v['CXX'] + v['CXXLNK_SRC_F'] = '' + v['CXXLNK_TGT_F'] = '-o ' + + v['LIB_ST'] = '-l%s' # template for adding libs + v['LIBPATH_ST'] = '-L%s' # template for adding libpaths + v['STATICLIB_ST'] = '-l%s' + v['STATICLIBPATH_ST'] = '-L%s' + v['CXXDEFINES_ST'] = '-D%s' + + v['SHLIB_MARKER'] = '-Bdynamic' + v['STATICLIB_MARKER'] = '-Bstatic' + + # program + v['program_PATTERN'] = '%s' + + # shared library + v['shlib_CXXFLAGS'] = ['-Kpic', '-DPIC'] + v['shlib_LINKFLAGS'] = ['-G'] + v['shlib_PATTERN'] = 'lib%s.so' + + # static lib + v['staticlib_LINKFLAGS'] = ['-Bstatic'] + v['staticlib_PATTERN'] = 'lib%s.a' + +def modifier_debug(conf): + v = conf.env + v['CXXFLAGS'] = [''] + if conf.check_flags('-O2'): + v['CXXFLAGS_OPTIMIZED'] = ['-O2'] + v['CXXFLAGS_RELEASE'] = ['-O2'] + if conf.check_flags('-g -DDEBUG'): + v['CXXFLAGS_DEBUG'] = ['-g', '-DDEBUG'] + if conf.check_flags('-g3 -O0 -DDEBUG'): + v['CXXFLAGS_ULTRADEBUG'] = ['-g3', '-O0', '-DDEBUG'] + + try: + debug_level = Params.g_options.debug_level.upper() + except AttributeError: + debug_level = ccroot.DEBUG_LEVELS.CUSTOM + v.append_value('CXXFLAGS', v['CXXFLAGS_'+debug_level]) + +def detect(conf): + + find_cxx(conf) + ar.find_cpp(conf) + ar.find_ar(conf) + + conf.check_tool('cxx') + + common_flags(conf) + + conf.check_tool('checks') + conf.check_features(kind='cpp') + + modifier_debug(conf) + + conf.add_os_flags('CXXFLAGS') + conf.add_os_flags('CPPFLAGS') + conf.add_os_flags('LINKFLAGS') + +def set_options(opt): + try: + opt.add_option('-d', '--debug-level', + action = 'store', + default = ccroot.DEBUG_LEVELS.RELEASE, + help = "Specify the debug level, does nothing if CFLAGS is set in the environment. [Allowed Values: '%s']" % "', '".join(ccroot.DEBUG_LEVELS.ALL), + choices = ccroot.DEBUG_LEVELS.ALL, + dest = 'debug_level') + + except optparse.OptionConflictError: + # the suncc tool might have added that option already + pass + + diff -Nru zyn-1+git.20100609/wafadmin/Tools/swig.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/swig.py --- zyn-1+git.20100609/wafadmin/Tools/swig.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/swig.py 2008-03-25 21:02:39.000000000 +0000 @@ -0,0 +1,139 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: UTF-8 +# Petar Forai +# Thomas Nagy + +print """ +WARNING: You are using the swig tool! + This tool is marked as beeing deprecated! use with caution! + it is not maintained actively +""" + +import re +import Action, Scan, Params, Object +from Params import fatal + +swig_str = '${SWIG} ${SWIGFLAGS} -o ${TGT[0].bldpath(env)} ${SRC}' + +re_1 = re.compile(r'^%module.*?\s+([\w]+)\s*?$', re.M) +re_2 = re.compile('%include "(.*)"', re.M) +re_3 = re.compile('#include "(.*)"', re.M) + +class swig_class_scanner(Scan.scanner): + def __init__(self): + Scan.scanner.__init__(self) + def scan(self, task, node): + env = task.m_env + variant = node.variant(env) + tree = Params.g_build + + lst_names = [] + lst_src = [] + + # read the file + fi = open(node.abspath(env), 'r') + content = fi.read() + fi.close() + + # module name, only for the .swig file + names = re_1.findall(content) + if names: lst_names.append(names[0]) + + # find .i files (and perhaps .h files) + names = re_2.findall(content) + for n in names: + u = node.m_parent.find_source(n) + if u: lst_src.append(u) + + # find project headers + names = re_3.findall(content) + for n in names: + u = node.m_parent.find_source(n) + if u: lst_src.append(u) + + # list of nodes this one depends on, and module name if present + #print "result of ", node, lst_src, lst_names + return (lst_src, lst_names) + +swig_scanner = swig_class_scanner() + +def i_file(self, node): + ext = '.swigwrap.c' + if self.__class__.__name__ == 'cpp_taskgen': + ext = '.swigwrap.cc' + + variant = node.variant(self.env) + + ltask = self.create_task('swig') + ltask.set_inputs(node) + + tree = Params.g_build + def check_rec(task, node_): + for j in tree.m_depends_on[0][node_]: + if j.m_name.endswith('.i'): + check_rec(task, j) + check_rec(ltask, node) + + # get the name of the swig module to process + try: modname = Params.g_build.m_raw_deps[0][node][0] + except KeyError: return + + # set the output files + outs = [node.change_ext(ext)] + # swig generates a python file in python mode TODO: other modes ? + if '-python' in self.env['SWIGFLAGS']: + outs.append(node.m_parent.find_build(modname+'.py')) + elif '-ocaml' in self.env['SWIGFLAGS']: + outs.append(node.m_parent.find_build(modname+'.ml')) + outs.append(node.m_parent.find_build(modname+'.mli')) + + ltask.set_outputs(outs) + + # create the build task (c or cpp) + task = self.create_task(self.m_type_initials) + task.set_inputs(ltask.m_outputs[0]) + task.set_outputs(node.change_ext('.swigwrap.os')) + +Action.simple_action('swig', swig_str, color='BLUE', prio=40) + +# register the hook for use with cpp and cc task generators +try: Object.hook('cpp', 'SWIG_EXT', i_file) +except KeyError: pass +try: Object.hook('cc', 'SWIG_EXT', i_file) +except KeyError: pass + +def check_swig_version(conf, minver=None): + """Check for a minimum swig version like conf.check_swig_version("1.3.28") + or conf.check_swig_version((1,3,28)) """ + import pproc as subprocess + reg_swig = re.compile(r'SWIG Version\s(.*)', re.M) + proc = subprocess.Popen([conf.env['SWIG'], "-version"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + swig_out = proc.communicate()[0] + swigver = [int(s) for s in reg_swig.findall(swig_out)[0].split(".")] + if isinstance(minver, basestring): + minver = [int(s) for s in minver.split(".")] + if isinstance(minver, tuple): + minver = [int(s) for s in minver] + result = (minver is None) or (minver[:3] <= swigver[:3]) + swigver_full = '.'.join(map(str, swigver)) + if result: + conf.env['SWIG_VERSION'] = swigver_full + minver_str = '.'.join(map(str, minver)) + if minver is None: + conf.check_message_custom('swig version', '', swigver_full) + else: + conf.check_message('swig version', ">= %s" % (minver_str,), result, option=swigver_full) + return result + +def detect(conf): + swig = conf.find_program('swig', var='SWIG') + env = conf.env + env['SWIG'] = swig + env['SWIGFLAGS'] = '' + env['SWIG_EXT'] = ['.swig'] + conf.hook(check_swig_version) + + diff -Nru zyn-1+git.20100609/wafadmin/Tools/tex.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/tex.py --- zyn-1+git.20100609/wafadmin/Tools/tex.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/tex.py 2008-03-25 21:02:39.000000000 +0000 @@ -0,0 +1,252 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2006 (ita) + +"TeX/LaTeX/PDFLaTeX support" + +import os, re +import Utils, Params, Action, Object, Runner, Scan +from Params import error, warning, debug, fatal + +re_tex = re.compile(r'\\(?Pinclude|import|bringin){(?P[^{}]*)}', re.M) +class tex_scanner(Scan.scanner): + def __init__(self): + Scan.scanner.__init__(self) + + def scan(self, task, node): + env = task.env() + + nodes = [] + names = [] + if not node: return (nodes, names) + + fi = open(node.abspath(env), 'r') + code = fi.read() + fi.close() + + curdirnode = task.curdirnode + abs = curdirnode.abspath() + for match in re_tex.finditer(code): + path = match.group('file') + if path: + for k in ['', '.tex', '.ltx']: + # add another loop for the tex include paths? + debug("trying %s%s" % (path, k), 'tex') + try: + os.stat(abs+os.sep+path+k) + except OSError: + continue + found = path+k + node = curdirnode.find_source(found) + if node: + nodes.append(node) + else: + debug('could not find %s' % path, 'tex') + names.append(path) + + debug("found the following : %s and names %s" % (nodes, names), 'tex') + return (nodes, names) + +g_tex_scanner = tex_scanner() + +g_bibtex_re = re.compile('bibdata', re.M) +def tex_build(task, command='LATEX'): + env = task.env() + + if env['PROMPT_LATEX']: + exec_cmd = Runner.exec_command_interact + com = '%s %s' % (env[command], env.get_flat(command+'FLAGS')) + else: + exec_cmd = Runner.exec_command + com = '%s %s %s' % (env[command], env.get_flat(command+'FLAGS'), '-interaction=batchmode') + + node = task.m_inputs[0] + reldir = node.bld_dir(env) + srcfile = node.srcpath(env) + + lst = [] + for c in Utils.split_path(reldir): + if c: lst.append('..') + sr = os.path.join(*(lst + [srcfile])) + sr2 = os.path.join(*(lst + [node.m_parent.srcpath(env)])) + + aux_node = node.change_ext('.aux') + idx_node = node.change_ext('.idx') + + hash = '' + old_hash = '' + + nm = aux_node.m_name + docuname = nm[ : len(nm) - 4 ] # 4 is the size of ".aux" + + latex_compile_cmd = 'cd %s && TEXINPUTS=%s:$TEXINPUTS %s %s' % (reldir, sr2, com, sr) + warning('first pass on %s' % command) + ret = exec_cmd(latex_compile_cmd) + if ret: return ret + + # look in the .aux file if there is a bibfile to process + try: + file = open(aux_node.abspath(env), 'r') + ct = file.read() + file.close() + except (OSError, IOError): + error('erreur bibtex scan') + else: + fo = g_bibtex_re.findall(ct) + + # yes, there is a .aux file to process + if fo: + bibtex_compile_cmd = 'cd %s && BIBINPUTS=%s:$BIBINPUTS %s %s' % (reldir, sr2, env['BIBTEX'], docuname) + + warning('calling bibtex') + ret = exec_cmd(bibtex_compile_cmd) + if ret: + error('error when calling bibtex %s' % bibtex_compile_cmd) + return ret + + # look on the filesystem if there is a .idx file to process + try: + idx_path = idx_node.abspath(env) + os.stat(idx_path) + except OSError: + error('erreur file.idx scan') + else: + makeindex_compile_cmd = 'cd %s && %s %s' % (reldir, env['MAKEINDEX'], idx_path) + warning('calling makeindex') + ret = exec_cmd(makeindex_compile_cmd) + if ret: + error('error when calling makeindex %s' % makeindex_compile_cmd) + return ret + + i = 0 + while i < 10: + # prevent against infinite loops - one never knows + i += 1 + + # watch the contents of file.aux + old_hash = hash + try: + hash = Params.h_file(aux_node.abspath(env)) + except KeyError: + error('could not read aux.h -> %s' % aux_node.abspath(env)) + pass + + # debug + #print "hash is, ", hash, " ", old_hash + + # stop if file.aux does not change anymore + if hash and hash == old_hash: break + + # run the command + warning('calling %s' % command) + ret = exec_cmd(latex_compile_cmd) + if ret: + error('error when calling %s %s' % (command, latex_compile_cmd)) + return ret + + # 0 means no error + return 0 + +latex_vardeps = ['LATEX', 'LATEXFLAGS'] +def latex_build(task): + return tex_build(task, 'LATEX') + +pdflatex_vardeps = ['PDFLATEX', 'PDFLATEXFLAGS'] +def pdflatex_build(task): + return tex_build(task, 'PDFLATEX') + +g_texobjs = ['latex','pdflatex'] +class tex_taskgen(Object.task_gen): + s_default_ext = ['.tex', '.ltx'] + def __init__(self, type='latex'): + Object.task_gen.__init__(self) + + global g_texobjs + if not type in g_texobjs: + fatal('type %s not supported for texobj' % type) + self.m_type = type + self.outs = '' # example: "ps pdf" + self.prompt = 1 # prompt for incomplete files (else the batchmode is used) + self.deps = '' + def apply(self): + + tree = Params.g_build + outs = self.outs.split() + self.env['PROMPT_LATEX'] = self.prompt + + deps_lst = [] + + if self.deps: + deps = self.to_list(self.deps) + for filename in deps: + n = self.path.find_source(filename) + if not n in deps_lst: deps_lst.append(n) + + for filename in self.source.split(): + base, ext = os.path.splitext(filename) + if not ext in self.s_default_ext: continue + + node = self.path.find_source(filename) + if not node: fatal('cannot find %s' % filename) + + if self.m_type == 'latex': + task = self.create_task('latex', self.env) + task.set_inputs(node) + task.set_outputs(node.change_ext('.dvi')) + elif self.m_type == 'pdflatex': + task = self.create_task('pdflatex', self.env) + task.set_inputs(node) + task.set_outputs(node.change_ext('.pdf')) + else: + fatal('no type or invalid type given in tex object (should be latex or pdflatex)') + + task.m_scanner = g_tex_scanner + task.m_env = self.env + task.curdirnode = self.path + + # add the manual dependencies + if deps_lst: + variant = node.variant(self.env) + try: + lst = tree.m_depends_on[variant][node] + for n in deps_lst: + if not n in lst: + lst.append(n) + except KeyError: + tree.m_depends_on[variant][node] = deps_lst + + if self.m_type == 'latex': + if 'ps' in outs: + pstask = self.create_task('dvips', self.env) + pstask.set_inputs(task.m_outputs) + pstask.set_outputs(node.change_ext('.ps')) + if 'pdf' in outs: + pdftask = self.create_task('dvipdf', self.env) + pdftask.set_inputs(task.m_outputs) + pdftask.set_outputs(node.change_ext('.pdf')) + elif self.m_type == 'pdflatex': + if 'ps' in outs: + pstask = self.create_task('pdf2ps', self.env) + pstask.set_inputs(task.m_outputs) + pstask.set_outputs(node.change_ext('.ps')) + +def detect(conf): + v = conf.env + for p in 'tex latex pdflatex bibtex dvips dvipdf ps2pdf makeindex'.split(): + conf.find_program(p, var=p.upper()) + v[p.upper()+'FLAGS'] = '' + v['DVIPSFLAGS'] = '-Ppdf' + +Action.simple_action('tex', '${TEX} ${TEXFLAGS} ${SRC}', color='BLUE', prio=60) +Action.simple_action('bibtex', '${BIBTEX} ${BIBTEXFLAGS} ${SRC}', color='BLUE', prio=60) +Action.simple_action('dvips', '${DVIPS} ${DVIPSFLAGS} ${SRC} -o ${TGT}', color='BLUE', prio=60) +Action.simple_action('dvipdf', '${DVIPDF} ${DVIPDFFLAGS} ${SRC} ${TGT}', color='BLUE', prio=60) +Action.simple_action('pdf2ps', '${PDF2PS} ${PDF2PSFLAGS} ${SRC} ${TGT}', color='BLUE', prio=60) + +Action.Action('latex', vars=latex_vardeps, func=latex_build, prio=40) +Action.Action('pdflatex', vars=pdflatex_vardeps, func=pdflatex_build, prio=40) + + diff -Nru zyn-1+git.20100609/wafadmin/Tools/vala.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/vala.py --- zyn-1+git.20100609/wafadmin/Tools/vala.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/vala.py 2008-03-23 20:35:44.000000000 +0000 @@ -0,0 +1,126 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Ali Sabil, 2007 + +import os.path, shutil +import Action, Object, Runner, Utils, Params, Node +from Object import extension + +EXT_VALA = ['.vala'] + +class ValacAction(Action.Action): + def __init__(self): + Action.Action.__init__(self, 'valac', color='GREEN') + + def get_str(self, task): + "string to display to the user" + env = task.env() + src_str = " ".join([a.m_name for a in task.m_inputs]) + return "* %s : %s" % (self.m_name, src_str) + + def run(self, task): + env = task.env() + inputs = [a.srcpath(env) for a in task.m_inputs] + valac = env['VALAC'] + vala_flags = env.get_flat('VALAFLAGS') + top_src = Params.g_build.m_srcnode.abspath() + top_bld = Params.g_build.m_srcnode.abspath(env) + + cmd = [valac, '-C', vala_flags] + + if task.threading: + cmd.append('--thread') + + if task.output_type in ('shlib', 'staticlib', 'plugin'): + cmd.append('--library ' + task.target) + cmd.append('--basedir ' + top_src) + cmd.append('-d ' + top_bld) + #cmd.append('-d %s' % Params.g_build.m_srcnode.abspath(bld.env())) + #cmd.append('-d %s' % Params.g_build.m_bldnode.bldpath(env)) + else: + output_dir = task.m_outputs[0].bld_dir(env) + cmd.append('-d %s' % output_dir) + + for vapi_dir in task.vapi_dirs: + cmd.append('--vapidir=%s' % vapi_dir) + + for package in task.packages: + cmd.append('--pkg %s' % package) + + cmd.append(" ".join(inputs)) + result = Runner.exec_command(" ".join(cmd)) + + if task.output_type in ('shlib', 'staticlib', 'plugin'): + # generate the .deps file + if task.packages: + filename = os.path.join(task.m_outputs[0].bld_dir(env), "%s.deps" % task.target) + deps = open(filename, 'w') + for package in task.packages: + deps.write(package + '\n') + deps.close() + + # handle vala 0.1.6 who doesn't honor --directory for the generated .vapi + # waf is always run from the build directory + try: + src_vapi = os.path.join(top_bld, "..", "%s.vapi" % task.target) + dst_vapi = task.m_outputs[0].bld_dir(env) + shutil.move(src_vapi, dst_vapi) + except IOError: + pass + return result + +def vala_file(self, node): + valatask = self.create_task('valac') + valatask.output_type = self.m_type + valatask.packages = [] + valatask.vapi_dirs = [] + valatask.target = self.target + valatask.threading = False + + if hasattr(self, 'packages'): + valatask.packages = Utils.to_list(self.packages) + + if hasattr(self, 'vapi_dirs'): + vapi_dirs = Utils.to_list(self.vapi_dirs) + for vapi_dir in vapi_dirs: + valatask.vapi_dirs.append(self.path.find_dir(vapi_dir).abspath()) + valatask.vapi_dirs.append(self.path.find_dir(vapi_dir).abspath(self.env)) + + if hasattr(self, 'threading'): + valatask.threading = self.threading + + input_nodes = [] + for source in self.to_list(self.source): + if source.endswith(".vala"): + input_nodes.append(self.path.find_source(source)) + valatask.set_inputs(input_nodes) + + output_nodes = [] + for node in input_nodes: + output_nodes.append(node.change_ext('.c')) + output_nodes.append(node.change_ext('.h')) + + if self.m_type != 'program': + output_nodes.append(self.path.find_build('%s.vapi' % self.target)) + if valatask.packages: + output_nodes.append(self.path.find_build('%s.deps' % self.target)) + valatask.set_outputs(output_nodes) + + for node in valatask.m_outputs: + if node.m_name.endswith('.c'): + self.allnodes.append(node) + +# create our action here +ValacAction() + +def detect(conf): + valac = conf.find_program('valac', var='VALAC') + if not valac: conf.fatal('Could not find the valac compiler anywhere') + conf.env['VALAC'] = valac + conf.env['VALAFLAGS'] = '' + + +extension(EXT_VALA)(vala_file) diff -Nru zyn-1+git.20100609/wafadmin/Tools/winres.py zyn-1+git.20100609+dfsg0/wafadmin/Tools/winres.py --- zyn-1+git.20100609/wafadmin/Tools/winres.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Tools/winres.py 2008-03-25 21:02:39.000000000 +0000 @@ -0,0 +1,61 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Brant Young, 2007 + +"This hook is called when the class cpp/cc task generator encounters a '.rc' file: X{.rc -> [.res|.rc.o]}" + +import os, sys +import Action, Object +from Utils import quote_whitespace +from Object import extension + +EXT_WINRC = ['.rc'] + +winrc_str = '${WINRC} ${_CPPDEFFLAGS} ${_CXXDEFFLAGS} ${_CCDEFFLAGS} ${WINRCFLAGS} ${_CPPINCFLAGS} ${_CXXINCFLAGS} ${_CCINCFLAGS} ${WINRC_TGT_F}${TGT} ${WINRC_SRC_F}${SRC}' + +def rc_file(self, node): + obj_ext = '.rc.o' + if self.env['WINRC_TGT_F'] == '/fo ': obj_ext = '.res' + + rctask = self.create_task('winrc') + rctask.set_inputs(node) + rctask.set_outputs(node.change_ext(obj_ext)) + + # make linker can find compiled resource files + self.compiled_tasks.append(rctask) + +# create our action, for use with rc file +Action.simple_action('winrc', winrc_str, color='BLUE', prio=40) + +def detect(conf): + v = conf.env + + cc = os.path.basename(''.join(v['CC']).lower()) + cxx = os.path.basename(''.join(v['CXX']).lower()) + + # TODO ugly + if cc.find('gcc')>-1 or cc.find('cc')>-1 or cxx.find('g++')>-1 or cxx.find('c++')>-1: + # find windres while use gcc toolchain + winrc = conf.find_program('windres', var='WINRC') + v['WINRC_TGT_F'] = '-o ' + v['WINRC_SRC_F'] = '-i ' + elif cc.find('cl.exe')>-1 or cxx.find('cl.exe')>-1 : + # find rc.exe while use msvc + winrc = conf.find_program('RC', var='WINRC') + v['WINRC_TGT_F'] = '/fo ' + v['WINRC_SRC_F'] = ' ' + else: + return 0 + + if not winrc: + conf.fatal('winrc was not found!!') + else: + v['WINRC'] = quote_whitespace(winrc) + + v['WINRCFLAGS'] = '' + + +extension(EXT_WINRC)(rc_file) diff -Nru zyn-1+git.20100609/wafadmin/UnitTest.py zyn-1+git.20100609+dfsg0/wafadmin/UnitTest.py --- zyn-1+git.20100609/wafadmin/UnitTest.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/UnitTest.py 2008-03-23 19:05:48.000000000 +0000 @@ -0,0 +1,181 @@ +#! /usr/bin/env python +# encoding: utf-8 + +#! /usr/bin/env python +# encoding: utf-8 +# Carlos Rafael Giani, 2006 + +""" +Unit tests run in the shutdown() method, and for c/c++ programs + +One should NOT have to give parameters to programs to execute + +In the shutdown method, add the following code: + + >>> def shutdown(): + ... ut = UnitTest.unit_test() + ... ut.run() + ... ut.print_results() + + +Each object to use as a unit test must be a program and must have X{obj.unit_test=1} +""" +import os, sys +import Params, Object, Utils +import pproc as subprocess + +class unit_test(object): + "Unit test representation" + def __init__(self): + self.returncode_ok = 0 # Unit test returncode considered OK. All returncodes differing from this one + # will cause the unit test to be marked as "FAILED". + + # The following variables are filled with data by run(). + + # print_results() uses these for printing the unit test summary, + # but if there is need for direct access to the results, + # they can be retrieved here, after calling run(). + + self.num_tests_ok = 0 # Number of successful unit tests + self.num_tests_failed = 0 # Number of failed unit tests + self.num_tests_err = 0 # Tests that have not even run + self.total_num_tests = 0 # Total amount of unit tests + self.max_label_length = 0 # Maximum label length (pretty-print the output) + + self.unit_tests = {} # Unit test dictionary. Key: the label (unit test filename relative + # to the build dir), value: unit test filename with absolute path + self.unit_test_results = {} # Dictionary containing the unit test results. + # Key: the label, value: result (true = success false = failure) + self.unit_test_erroneous = {} # Dictionary indicating erroneous unit tests. + # Key: the label, value: true = unit test has an error false = unit test is ok + self.change_to_testfile_dir = False #True if the test file needs to be executed from the same dir + self.want_to_see_test_output = False #True to see the stdout from the testfile (for example check suites) + self.want_to_see_test_error = False #True to see the stderr from the testfile (for example check suites) + self.run_if_waf_does = 'check' #build was the old default + + def run(self): + "Run the unit tests and gather results (note: no output here)" + + self.num_tests_ok = 0 + self.num_tests_failed = 0 + self.num_tests_err = 0 + self.total_num_tests = 0 + self.max_label_length = 0 + + self.unit_tests = {} + self.unit_test_results = {} + self.unit_test_erroneous = {} + + # If waf is not building, don't run anything + if not Params.g_commands[self.run_if_waf_does]: return + + # Gather unit tests to call + for obj in Object.g_allobjs: + if not hasattr(obj,'unit_test'): continue + unit_test = getattr(obj,'unit_test') + if not unit_test: continue + try: + if obj.m_type == 'program': + filename = obj.link_task.m_outputs[0].abspath(obj.env) + label = obj.link_task.m_outputs[0].bldpath(obj.env) + self.max_label_length = max(self.max_label_length, len(label)) + self.unit_tests[label] = filename + except KeyError: + pass + self.total_num_tests = len(self.unit_tests) + # Now run the unit tests + col1=Params.g_colors['GREEN'] + col2=Params.g_colors['NORMAL'] + Params.pprint('GREEN', 'Running the unit tests') + count = 0 + result = 1 + + curdir = os.getcwd() # store the current dir (only if self.change_to_testfile_dir) + for label, filename in self.unit_tests.iteritems(): + count += 1 + line = Utils.progress_line(count, self.total_num_tests, col1, col2) + if Params.g_options.progress_bar and line: + sys.stdout.write(line) + sys.stdout.flush() + try: + if self.change_to_testfile_dir: + os.chdir(os.path.dirname(filename)) + + kwargs = dict() + if not self.want_to_see_test_output: + kwargs['stdout'] = subprocess.PIPE # PIPE for ignoring output + if not self.want_to_see_test_error: + kwargs['stderr'] = subprocess.PIPE # PIPE for ignoring output + pp = subprocess.Popen(filename, **kwargs) + pp.wait() + + if self.change_to_testfile_dir: + os.chdir(curdir) + + result = int(pp.returncode == self.returncode_ok) + + if result: + self.num_tests_ok += 1 + else: + self.num_tests_failed += 1 + + self.unit_test_results[label] = result + self.unit_test_erroneous[label] = 0 + except OSError: + self.unit_test_erroneous[label] = 1 + self.num_tests_err += 1 + except KeyboardInterrupt: + if Params.g_options.progress_bar: sys.stdout.write(Params.g_cursor_off) + if Params.g_options.progress_bar: sys.stdout.write(Params.g_cursor_off) + + def print_results(self): + "Pretty-prints a summary of all unit tests, along with some statistics" + + # If waf is not building, don't output anything + if not Params.g_commands[self.run_if_waf_does]: return + + p = Params.pprint + # Early quit if no tests were performed + if self.total_num_tests == 0: + p('YELLOW', 'No unit tests present') + return + p('GREEN', 'Running unit tests') + print + + for label, filename in self.unit_tests.iteritems(): + err = 0 + result = 0 + + try: err = self.unit_test_erroneous[label] + except KeyError: pass + + try: result = self.unit_test_results[label] + except KeyError: pass + + n = self.max_label_length - len(label) + if err: n += 4 + elif result: n += 7 + else: n += 3 + + line = '%s %s' % (label, '.' * n) + + print line, + if err: p('RED', 'ERROR') + elif result: p('GREEN', 'OK') + else: p('YELLOW', 'FAILED') + + percentage_ok = float(self.num_tests_ok) / float(self.total_num_tests) * 100.0 + percentage_failed = float(self.num_tests_failed) / float(self.total_num_tests) * 100.0 + percentage_erroneous = float(self.num_tests_err) / float(self.total_num_tests) * 100.0 + + print ''' +Successful tests: %i (%.1f%%) +Failed tests: %i (%.1f%%) +Erroneous tests: %i (%.1f%%) + +Total number of tests: %i +''' % (self.num_tests_ok, percentage_ok, self.num_tests_failed, percentage_failed, + self.num_tests_err, percentage_erroneous, self.total_num_tests) + p('GREEN', 'Unit tests finished') + + diff -Nru zyn-1+git.20100609/wafadmin/Utils.py zyn-1+git.20100609+dfsg0/wafadmin/Utils.py --- zyn-1+git.20100609/wafadmin/Utils.py 1970-01-01 00:00:00.000000000 +0000 +++ zyn-1+git.20100609+dfsg0/wafadmin/Utils.py 2008-03-25 19:28:28.000000000 +0000 @@ -0,0 +1,210 @@ +#! /usr/bin/env python +# encoding: utf-8 +import sys +if sys.hexversion < 0x020400f0: from sets import Set as set +#! /usr/bin/env python +# encoding: utf-8 +# Thomas Nagy, 2005 (ita) + +"Utility functions" + +import os, sys, imp, types, string, time +import Params +from Constants import * + +g_trace = 0 +g_debug = 0 +g_error = 0 + +g_ind_idx = 0 +g_ind = ['\\', '|', '/', '-'] +"the rotation thing" + +def test_full(): + try: + f=open('.waf-full','w') + f.write('test') + f.close() + os.unlink('.waf-full') + except IOError, e: + import errno + if e.errno == errno.ENOSPC: + Params.fatal('filesystem full', e.errno) + else: + Params.fatal(str(e), e.errno) + +# TODO DEPRECATED: to be removed in waf 1.4 +def waf_version(mini = "0.0.1", maxi = "100.0.0"): + "throws an exception if the waf version is wrong" + min_lst = map(int, mini.split('.')) + max_lst = map(int, maxi.split('.')) + waf_lst = map(int, Params.g_version.split('.')) + + mm = min(len(min_lst), len(waf_lst)) + for (a, b) in zip(min_lst[:mm], waf_lst[:mm]): + if a < b: + break + if a > b: + Params.fatal("waf version should be at least %s (%s found)" % (mini, Params.g_version)) + + mm = min(len(max_lst), len(waf_lst)) + for (a, b) in zip(max_lst[:mm], waf_lst[:mm]): + if a > b: + break + if a < b: + Params.fatal("waf version should be at most %s (%s found)" % (maxi, Params.g_version)) + +def reset(): + import Params, Object, Environment + Params.g_build = None + Object.g_allobjs = [] + Environment.g_cache_max = {} + #Object.task_gen.mappings = {} + #Object.task_gen.mapped = {} + +def to_list(sth): + if type(sth) is types.ListType: + return sth + else: + return sth.split() + +def options(**kwargs): + pass + +g_loaded_modules = {} +"index modules by absolute path" + +g_module=None +"the main module is special" + +def load_module(file_path, name=WSCRIPT_FILE): + "this function requires an absolute path" + try: + return g_loaded_modules[file_path] + except KeyError: + pass + + module = imp.new_module(name) + + try: + file = open(file_path, 'r') + except (IOError, OSError): + Params.fatal('The file %s could not be opened!' % file_path) + + import Common + d = module.__dict__ + d['install_files'] = Common.install_files + d['install_as'] = Common.install_as + d['symlink_as'] = Common.symlink_as + + module_dir = os.path.dirname(file_path) + sys.path.insert(0, module_dir) + exec file in module.__dict__ + sys.path.remove(module_dir) + if file: file.close() + + g_loaded_modules[file_path] = module + + return module + +def set_main_module(file_path): + "Load custom options, if defined" + global g_module + g_module = load_module(file_path, 'wscript_main') + + # remark: to register the module globally, use the following: + # sys.modules['wscript_main'] = g_module + +def to_hashtable(s): + tbl = {} + lst = s.split('\n') + for line in lst: + if not line: continue + mems = line.split('=') + tbl[mems[0]] = mems[1] + return tbl + +try: + import struct, fcntl, termios +except ImportError: + def get_term_cols(): + return 55 +else: + def get_term_cols(): + dummy_lines, cols = struct.unpack("HHHH", \ + fcntl.ioctl(sys.stdout.fileno(),termios.TIOCGWINSZ , \ + struct.pack("HHHH", 0, 0, 0, 0)))[:2] + return cols + + +def progress_line(state, total, col1, col2): + n = len(str(total)) + + global g_ind, g_ind_idx + g_ind_idx += 1 + ind = g_ind[g_ind_idx % 4] + + if hasattr(Params.g_build, 'ini'): + ini = Params.g_build.ini + else: + ini = Params.g_build.ini = time.time() + + pc = (100.*state)/total + eta = time.strftime('%H:%M:%S', time.gmtime(time.time() - ini)) + fs = "[%%%dd/%%%dd][%%s%%2d%%%%%%s][%s][" % (n, n, ind) + left = fs % (state, total, col1, pc, col2) + right = '][%s%s%s]' % (col1, eta, col2) + + cols = get_term_cols() - len(left) - len(right) + 2*len(col1) + 2*len(col2) + if cols < 7: cols = 7 + + ratio = int((cols*state)/total) - 1 + + bar = ('='*ratio+'>').ljust(cols) + msg = Params.g_progress % (left, bar, right) + + return msg + +def split_path(path): + "Split path into components. Supports UNC paths on Windows" + if sys.platform == 'win32': + # splitunc is defined by os.path for Windows only + h,t = os.path.splitunc(path) + if not h: return __split_dirs(t) + return [h] + __split_dirs(t)[1:] + else: + if not path: return [''] + x = path.split('/') + if path[0] == '/': x = ['/']+x[1:] + return x + +def __split_dirs(path): + h,t = os.path.split(path) + if not h: return [t] + if h == path: return [h] + if not t: return __split_dirs(h) + else: return __split_dirs(h) + [t] + +_quote_define_name_translation = None +"lazily construct a translation table for mapping invalid characters to valid ones" + +def quote_define_name(path): + "Converts a string to a constant name, foo/zbr-xpto.h -> FOO_ZBR_XPTO_H" + global _quote_define_name_translation + if _quote_define_name_translation is None: + invalid_chars = [chr(x) for x in xrange(256)] + for valid in string.digits + string.uppercase: invalid_chars.remove(valid) + _quote_define_name_translation = string.maketrans(''.join(invalid_chars), '_'*len(invalid_chars)) + + return string.translate(string.upper(path), _quote_define_name_translation) + +def quote_whitespace(path): + return (path.strip().find(' ') > 0 and '"%s"' % path or path).replace('""', '"') + +def trimquotes(s): + if not s: return '' + s = s.rstrip() + if s[0] == "'" and s[-1] == "'": return s[1:-1] + return s + +