PNG  IHDRX cHRMz&u0`:pQ<bKGD pHYsodtIME MeqIDATxw]Wug^Qd˶ 6`!N:!@xI~)%7%@Bh&`lnjVF29gΨ4E$|>cɚ{gk= %,a KX%,a KX%,a KX%,a KX%,a KX%,a KX%, b` ǟzeאfp]<!SJmɤY޲ڿ,%c ~ع9VH.!Ͳz&QynֺTkRR.BLHi٪:l;@(!MԴ=žI,:o&N'Kù\vRmJ雵֫AWic H@" !: Cé||]k-Ha oݜ:y F())u]aG7*JV@J415p=sZH!=!DRʯvɱh~V\}v/GKY$n]"X"}t@ xS76^[bw4dsce)2dU0 CkMa-U5tvLƀ~mlMwfGE/-]7XAƟ`׮g ewxwC4\[~7@O-Q( a*XGƒ{ ՟}$_y3tĐƤatgvێi|K=uVyrŲlLӪuܿzwk$m87k( `múcE)"@rK( z4$D; 2kW=Xb$V[Ru819קR~qloѱDyįݎ*mxw]y5e4K@ЃI0A D@"BDk_)N\8͜9dz"fK0zɿvM /.:2O{ Nb=M=7>??Zuo32 DLD@D| &+֎C #B8ַ`bOb $D#ͮҪtx]%`ES`Ru[=¾!@Od37LJ0!OIR4m]GZRJu$‡c=%~s@6SKy?CeIh:[vR@Lh | (BhAMy=݃  G"'wzn޺~8ԽSh ~T*A:xR[ܹ?X[uKL_=fDȊ؂p0}7=D$Ekq!/t.*2ʼnDbŞ}DijYaȲ(""6HA;:LzxQ‘(SQQ}*PL*fc\s `/d'QXW, e`#kPGZuŞuO{{wm[&NBTiiI0bukcA9<4@SӊH*؎4U/'2U5.(9JuDfrޱtycU%j(:RUbArLֺN)udA':uGQN"-"Is.*+k@ `Ojs@yU/ H:l;@yyTn}_yw!VkRJ4P)~y#)r,D =ě"Q]ci'%HI4ZL0"MJy 8A{ aN<8D"1#IJi >XjX֔#@>-{vN!8tRݻ^)N_╗FJEk]CT՟ YP:_|H1@ CBk]yKYp|og?*dGvzنzӴzjֺNkC~AbZƷ`.H)=!QͷVTT(| u78y֮}|[8-Vjp%2JPk[}ԉaH8Wpqhwr:vWª<}l77_~{s۴V+RCģ%WRZ\AqHifɤL36: #F:p]Bq/z{0CU6ݳEv_^k7'>sq*+kH%a`0ԣisqにtү04gVgW΂iJiS'3w.w}l6MC2uԯ|>JF5`fV5m`Y**Db1FKNttu]4ccsQNnex/87+}xaUW9y>ͯ骵G{䩓Գ3+vU}~jJ.NFRD7<aJDB1#ҳgSb,+CS?/ VG J?|?,2#M9}B)MiE+G`-wo߫V`fio(}S^4e~V4bHOYb"b#E)dda:'?}׮4繏`{7Z"uny-?ǹ;0MKx{:_pÚmFמ:F " .LFQLG)Q8qN q¯¯3wOvxDb\. BKD9_NN &L:4D{mm o^tֽ:q!ƥ}K+<"m78N< ywsard5+вz~mnG)=}lYݧNj'QJS{S :UYS-952?&O-:W}(!6Mk4+>A>j+i|<<|;ر^߉=HE|V#F)Emm#}/"y GII웻Jі94+v뾧xu~5C95~ūH>c@덉pʃ1/4-A2G%7>m;–Y,cyyaln" ?ƻ!ʪ<{~h~i y.zZB̃/,雋SiC/JFMmBH&&FAbϓO^tubbb_hZ{_QZ-sύodFgO(6]TJA˯#`۶ɟ( %$&+V'~hiYy>922 Wp74Zkq+Ovn錄c>8~GqܲcWꂎz@"1A.}T)uiW4="jJ2W7mU/N0gcqܗOO}?9/wìXžΏ0 >֩(V^Rh32!Hj5`;O28؇2#ݕf3 ?sJd8NJ@7O0 b־?lldщ̡&|9C.8RTWwxWy46ah嘦mh٤&l zCy!PY?: CJyв]dm4ǜҐR޻RլhX{FƯanшQI@x' ao(kUUuxW_Ñ줮[w8 FRJ(8˼)_mQ _!RJhm=!cVmm ?sFOnll6Qk}alY}; "baӌ~M0w,Ggw2W:G/k2%R,_=u`WU R.9T"v,<\Ik޽/2110Ӿxc0gyC&Ny޽JҢrV6N ``یeA16"J³+Rj*;BϜkZPJaÍ<Jyw:NP8/D$ 011z֊Ⱳ3ι֘k1V_"h!JPIΣ'ɜ* aEAd:ݺ>y<}Lp&PlRfTb1]o .2EW\ͮ]38؋rTJsǏP@芎sF\> P^+dYJLbJ C-xϐn> ι$nj,;Ǖa FU *择|h ~izť3ᤓ`K'-f tL7JK+vf2)V'-sFuB4i+m+@My=O҈0"|Yxoj,3]:cо3 $#uŘ%Y"y죯LebqtҢVzq¼X)~>4L׶m~[1_k?kxֺQ`\ |ٛY4Ѯr!)N9{56(iNq}O()Em]=F&u?$HypWUeB\k]JɩSع9 Zqg4ZĊo oMcjZBU]B\TUd34ݝ~:7ڶSUsB0Z3srx 7`:5xcx !qZA!;%͚7&P H<WL!džOb5kF)xor^aujƍ7 Ǡ8/p^(L>ὴ-B,{ۇWzֺ^k]3\EE@7>lYBȝR.oHnXO/}sB|.i@ɥDB4tcm,@ӣgdtJ!lH$_vN166L__'Z)y&kH;:,Y7=J 9cG) V\hjiE;gya~%ks_nC~Er er)muuMg2;֫R)Md) ,¶ 2-wr#F7<-BBn~_(o=KO㭇[Xv eN_SMgSҐ BS헃D%g_N:/pe -wkG*9yYSZS.9cREL !k}<4_Xs#FmҶ:7R$i,fi!~' # !6/S6y@kZkZcX)%5V4P]VGYq%H1!;e1MV<!ϐHO021Dp= HMs~~a)ަu7G^];git!Frl]H/L$=AeUvZE4P\.,xi {-~p?2b#amXAHq)MWǾI_r`S Hz&|{ +ʖ_= (YS(_g0a03M`I&'9vl?MM+m~}*xT۲(fY*V4x@29s{DaY"toGNTO+xCAO~4Ϳ;p`Ѫ:>Ҵ7K 3}+0 387x\)a"/E>qpWB=1 ¨"MP(\xp߫́A3+J] n[ʼnӼaTbZUWb={~2ooKױӰp(CS\S筐R*JغV&&"FA}J>G֐p1ٸbk7 ŘH$JoN <8s^yk_[;gy-;߉DV{c B yce% aJhDȶ 2IdйIB/^n0tNtџdcKj4϶v~- CBcgqx9= PJ) dMsjpYB] GD4RDWX +h{y`,3ꊕ$`zj*N^TP4L:Iz9~6s) Ga:?y*J~?OrMwP\](21sZUD ?ܟQ5Q%ggW6QdO+\@ ̪X'GxN @'4=ˋ+*VwN ne_|(/BDfj5(Dq<*tNt1х!MV.C0 32b#?n0pzj#!38}޴o1KovCJ`8ŗ_"]] rDUy޲@ Ȗ-;xџ'^Y`zEd?0„ DAL18IS]VGq\4o !swV7ˣι%4FѮ~}6)OgS[~Q vcYbL!wG3 7띸*E Pql8=jT\꘿I(z<[6OrR8ºC~ډ]=rNl[g|v TMTղb-o}OrP^Q]<98S¤!k)G(Vkwyqyr޽Nv`N/e p/~NAOk \I:G6]4+K;j$R:Mi #*[AȚT,ʰ,;N{HZTGMoּy) ]%dHء9Պ䠬|<45,\=[bƟ8QXeB3- &dҩ^{>/86bXmZ]]yޚN[(WAHL$YAgDKp=5GHjU&99v簪C0vygln*P)9^͞}lMuiH!̍#DoRBn9l@ xA/_v=ȺT{7Yt2N"4!YN`ae >Q<XMydEB`VU}u]嫇.%e^ánE87Mu\t`cP=AD/G)sI"@MP;)]%fH9'FNsj1pVhY&9=0pfuJ&gޤx+k:!r˭wkl03׼Ku C &ѓYt{.O.zҏ z}/tf_wEp2gvX)GN#I ݭ߽v/ .& и(ZF{e"=V!{zW`, ]+LGz"(UJp|j( #V4, 8B 0 9OkRrlɱl94)'VH9=9W|>PS['G(*I1==C<5"Pg+x'K5EMd؞Af8lG ?D FtoB[je?{k3zQ vZ;%Ɠ,]E>KZ+T/ EJxOZ1i #T<@ I}q9/t'zi(EMqw`mYkU6;[t4DPeckeM;H}_g pMww}k6#H㶏+b8雡Sxp)&C $@'b,fPߑt$RbJ'vznuS ~8='72_`{q纶|Q)Xk}cPz9p7O:'|G~8wx(a 0QCko|0ASD>Ip=4Q, d|F8RcU"/KM opKle M3#i0c%<7׿p&pZq[TR"BpqauIp$ 8~Ĩ!8Սx\ւdT>>Z40ks7 z2IQ}ItԀ<-%S⍤};zIb$I 5K}Q͙D8UguWE$Jh )cu4N tZl+[]M4k8֦Zeq֮M7uIqG 1==tLtR,ƜSrHYt&QP윯Lg' I,3@P'}'R˪e/%-Auv·ñ\> vDJzlӾNv5:|K/Jb6KI9)Zh*ZAi`?S {aiVDԲuy5W7pWeQJk֤#5&V<̺@/GH?^τZL|IJNvI:'P=Ϛt"¨=cud S Q.Ki0 !cJy;LJR;G{BJy޺[^8fK6)=yʊ+(k|&xQ2`L?Ȓ2@Mf 0C`6-%pKpm')c$׻K5[J*U[/#hH!6acB JA _|uMvDyk y)6OPYjœ50VT K}cǻP[ $:]4MEA.y)|B)cf-A?(e|lɉ#P9V)[9t.EiQPDѠ3ϴ;E:+Օ t ȥ~|_N2,ZJLt4! %ա]u {+=p.GhNcŞQI?Nd'yeh n7zi1DB)1S | S#ًZs2|Ɛy$F SxeX{7Vl.Src3E℃Q>b6G ўYCmtկ~=K0f(=LrAS GN'ɹ9<\!a`)֕y[uՍ[09` 9 +57ts6}b4{oqd+J5fa/,97J#6yν99mRWxJyѡyu_TJc`~W>l^q#Ts#2"nD1%fS)FU w{ܯ R{ ˎ󅃏џDsZSQS;LV;7 Od1&1n$ N /.q3~eNɪ]E#oM~}v֯FڦwyZ=<<>Xo稯lfMFV6p02|*=tV!c~]fa5Y^Q_WN|Vs 0ҘދU97OI'N2'8N֭fgg-}V%y]U4 峧p*91#9U kCac_AFңĪy뚇Y_AiuYyTTYЗ-(!JFLt›17uTozc. S;7A&&<ԋ5y;Ro+:' *eYJkWR[@F %SHWP 72k4 qLd'J "zB6{AC0ƁA6U.'F3:Ȅ(9ΜL;D]m8ڥ9}dU "v!;*13Rg^fJyShyy5auA?ɩGHRjo^]׽S)Fm\toy 4WQS@mE#%5ʈfFYDX ~D5Ϡ9tE9So_aU4?Ѽm%&c{n>.KW1Tlb}:j uGi(JgcYj0qn+>) %\!4{LaJso d||u//P_y7iRJ߬nHOy) l+@$($VFIQ9%EeKʈU. ia&FY̒mZ=)+qqoQn >L!qCiDB;Y<%} OgBxB!ØuG)WG9y(Ą{_yesuZmZZey'Wg#C~1Cev@0D $a@˲(.._GimA:uyw֬%;@!JkQVM_Ow:P.s\)ot- ˹"`B,e CRtaEUP<0'}r3[>?G8xU~Nqu;Wm8\RIkբ^5@k+5(By'L&'gBJ3ݶ!/㮻w҅ yqPWUg<e"Qy*167΃sJ\oz]T*UQ<\FԎ`HaNmڜ6DysCask8wP8y9``GJ9lF\G g's Nn͵MLN֪u$| /|7=]O)6s !ĴAKh]q_ap $HH'\1jB^s\|- W1:=6lJBqjY^LsPk""`]w)󭃈,(HC ?䔨Y$Sʣ{4Z+0NvQkhol6C.婧/u]FwiVjZka&%6\F*Ny#8O,22+|Db~d ~Çwc N:FuuCe&oZ(l;@ee-+Wn`44AMK➝2BRՈt7g*1gph9N) *"TF*R(#'88pm=}X]u[i7bEc|\~EMn}P瘊J)K.0i1M6=7'_\kaZ(Th{K*GJyytw"IO-PWJk)..axӝ47"89Cc7ĐBiZx 7m!fy|ϿF9CbȩV 9V-՛^pV̌ɄS#Bv4-@]Vxt-Z, &ֺ*diؠ2^VXbs֔Ìl.jQ]Y[47gj=幽ex)A0ip׳ W2[ᎇhuE^~q흙L} #-b۸oFJ_QP3r6jr+"nfzRJTUqoaۍ /$d8Mx'ݓ= OՃ| )$2mcM*cЙj}f };n YG w0Ia!1Q.oYfr]DyISaP}"dIӗթO67jqR ҊƐƈaɤGG|h;t]䗖oSv|iZqX)oalv;۩meEJ\!8=$4QU4Xo&VEĊ YS^E#d,yX_> ۘ-e\ "Wa6uLĜZi`aD9.% w~mB(02G[6y.773a7 /=o7D)$Z 66 $bY^\CuP. (x'"J60׿Y:Oi;F{w佩b+\Yi`TDWa~|VH)8q/=9!g߆2Y)?ND)%?Ǐ`k/sn:;O299yB=a[Ng 3˲N}vLNy;*?x?~L&=xyӴ~}q{qE*IQ^^ͧvü{Huu=R|>JyUlZV, B~/YF!Y\u_ݼF{_C)LD]m {H 0ihhadd nUkf3oٺCvE\)QJi+֥@tDJkB$1!Đr0XQ|q?d2) Ӣ_}qv-< FŊ߫%roppVBwü~JidY4:}L6M7f٬F "?71<2#?Jyy4뷢<_a7_=Q E=S1И/9{+93֮E{ǂw{))?maÆm(uLE#lïZ  ~d];+]h j?!|$F}*"4(v'8s<ŏUkm7^7no1w2ؗ}TrͿEk>p'8OB7d7R(A 9.*Mi^ͳ; eeUwS+C)uO@ =Sy]` }l8^ZzRXj[^iUɺ$tj))<sbDJfg=Pk_{xaKo1:-uyG0M ԃ\0Lvuy'ȱc2Ji AdyVgVh!{]/&}}ċJ#%d !+87<;qN޼Nفl|1N:8ya  8}k¾+-$4FiZYÔXk*I&'@iI99)HSh4+2G:tGhS^繿 Kتm0 вDk}֚+QT4;sC}rՅE,8CX-e~>G&'9xpW,%Fh,Ry56Y–hW-(v_,? ; qrBk4-V7HQ;ˇ^Gv1JVV%,ik;D_W!))+BoS4QsTM;gt+ndS-~:11Sgv!0qRVh!"Ȋ(̦Yl.]PQWgٳE'`%W1{ndΗBk|Ž7ʒR~,lnoa&:ü$ 3<a[CBݮwt"o\ePJ=Hz"_c^Z.#ˆ*x z̝grY]tdkP*:97YľXyBkD4N.C_[;F9`8& !AMO c `@BA& Ost\-\NX+Xp < !bj3C&QL+*&kAQ=04}cC!9~820G'PC9xa!w&bo_1 Sw"ܱ V )Yl3+ס2KoXOx]"`^WOy :3GO0g;%Yv㐫(R/r (s } u B &FeYZh0y> =2<Ϟc/ -u= c&׭,.0"g"7 6T!vl#sc>{u/Oh Bᾈ)۴74]x7 gMӒ"d]U)}" v4co[ ɡs 5Gg=XR14?5A}D "b{0$L .\4y{_fe:kVS\\O]c^W52LSBDM! C3Dhr̦RtArx4&agaN3Cf<Ԉp4~ B'"1@.b_/xQ} _߃҉/gٓ2Qkqp0շpZ2fԫYz< 4L.Cyυι1t@鎫Fe sYfsF}^ V}N<_`p)alٶ "(XEAVZ<)2},:Ir*#m_YӼ R%a||EƼIJ,,+f"96r/}0jE/)s)cjW#w'Sʯ5<66lj$a~3Kʛy 2:cZ:Yh))+a߭K::N,Q F'qB]={.]h85C9cr=}*rk?vwV렵ٸW Rs%}rNAkDv|uFLBkWY YkX מ|)1!$#3%y?pF<@<Rr0}: }\J [5FRxY<9"SQdE(Q*Qʻ)q1E0B_O24[U'],lOb ]~WjHޏTQ5Syu wq)xnw8~)c 쫬gٲߠ H% k5dƝk> kEj,0% b"vi2Wس_CuK)K{n|>t{P1򨾜j>'kEkƗBg*H%'_aY6Bn!TL&ɌOb{c`'d^{t\i^[uɐ[}q0lM˕G:‚4kb祔c^:?bpg… +37stH:0}en6x˟%/<]BL&* 5&fK9Mq)/iyqtA%kUe[ڛKN]Ě^,"`/ s[EQQm?|XJ߅92m]G.E΃ח U*Cn.j_)Tѧj̿30ڇ!A0=͜ar I3$C^-9#|pk!)?7.x9 @OO;WƝZBFU keZ75F6Tc6"ZȚs2y/1 ʵ:u4xa`C>6Rb/Yм)^=+~uRd`/|_8xbB0?Ft||Z\##|K 0>>zxv8۴吅q 8ĥ)"6>~\8:qM}#͚'ĉ#p\׶ l#bA?)|g g9|8jP(cr,BwV (WliVxxᡁ@0Okn;ɥh$_ckCgriv}>=wGzβ KkBɛ[˪ !J)h&k2%07δt}!d<9;I&0wV/ v 0<H}L&8ob%Hi|޶o&h1L|u֦y~󛱢8fٲUsւ)0oiFx2}X[zVYr_;N(w]_4B@OanC?gĦx>мgx>ΛToZoOMp>40>V Oy V9iq!4 LN,ˢu{jsz]|"R޻&'ƚ{53ўFu(<٪9:΋]B;)B>1::8;~)Yt|0(pw2N%&X,URBK)3\zz&}ax4;ǟ(tLNg{N|Ǽ\G#C9g$^\}p?556]/RP.90 k,U8/u776s ʪ_01چ|\N 0VV*3H鴃J7iI!wG_^ypl}r*jɤSR 5QN@ iZ#1ٰy;_\3\BQQ x:WJv츟ٯ$"@6 S#qe딇(/P( Dy~TOϻ<4:-+F`0||;Xl-"uw$Цi󼕝mKʩorz"mϺ$F:~E'ҐvD\y?Rr8_He@ e~O,T.(ފR*cY^m|cVR[8 JҡSm!ΆԨb)RHG{?MpqrmN>߶Y)\p,d#xۆWY*,l6]v0h15M˙MS8+EdI='LBJIH7_9{Caз*Lq,dt >+~ّeʏ?xԕ4bBAŚjﵫ!'\Ը$WNvKO}ӽmSşذqsOy?\[,d@'73'j%kOe`1.g2"e =YIzS2|zŐƄa\U,dP;jhhhaxǶ?КZ՚.q SE+XrbOu%\GتX(H,N^~]JyEZQKceTQ]VGYqnah;y$cQahT&QPZ*iZ8UQQM.qo/T\7X"u?Mttl2Xq(IoW{R^ ux*SYJ! 4S.Jy~ BROS[V|žKNɛP(L6V^|cR7i7nZW1Fd@ Ara{詑|(T*dN]Ko?s=@ |_EvF]׍kR)eBJc" MUUbY6`~V޴dJKß&~'d3i WWWWWW
Current Directory: /opt/saltstack/salt/lib/python3.10/site-packages/cffi
Viewing File: /opt/saltstack/salt/lib/python3.10/site-packages/cffi/recompiler.py
import os, sys, io from . import ffiplatform, model from .error import VerificationError from .cffi_opcode import * VERSION_BASE = 0x2601 VERSION_EMBEDDED = 0x2701 VERSION_CHAR16CHAR32 = 0x2801 USE_LIMITED_API = (sys.platform != 'win32' or sys.version_info < (3, 0) or sys.version_info >= (3, 5)) class GlobalExpr: def __init__(self, name, address, type_op, size=0, check_value=0): self.name = name self.address = address self.type_op = type_op self.size = size self.check_value = check_value def as_c_expr(self): return ' { "%s", (void *)%s, %s, (void *)%s },' % ( self.name, self.address, self.type_op.as_c_expr(), self.size) def as_python_expr(self): return "b'%s%s',%d" % (self.type_op.as_python_bytes(), self.name, self.check_value) class FieldExpr: def __init__(self, name, field_offset, field_size, fbitsize, field_type_op): self.name = name self.field_offset = field_offset self.field_size = field_size self.fbitsize = fbitsize self.field_type_op = field_type_op def as_c_expr(self): spaces = " " * len(self.name) return (' { "%s", %s,\n' % (self.name, self.field_offset) + ' %s %s,\n' % (spaces, self.field_size) + ' %s %s },' % (spaces, self.field_type_op.as_c_expr())) def as_python_expr(self): raise NotImplementedError def as_field_python_expr(self): if self.field_type_op.op == OP_NOOP: size_expr = '' elif self.field_type_op.op == OP_BITFIELD: size_expr = format_four_bytes(self.fbitsize) else: raise NotImplementedError return "b'%s%s%s'" % (self.field_type_op.as_python_bytes(), size_expr, self.name) class StructUnionExpr: def __init__(self, name, type_index, flags, size, alignment, comment, first_field_index, c_fields): self.name = name self.type_index = type_index self.flags = flags self.size = size self.alignment = alignment self.comment = comment self.first_field_index = first_field_index self.c_fields = c_fields def as_c_expr(self): return (' { "%s", %d, %s,' % (self.name, self.type_index, self.flags) + '\n %s, %s, ' % (self.size, self.alignment) + '%d, %d ' % (self.first_field_index, len(self.c_fields)) + ('/* %s */ ' % self.comment if self.comment else '') + '},') def as_python_expr(self): flags = eval(self.flags, G_FLAGS) fields_expr = [c_field.as_field_python_expr() for c_field in self.c_fields] return "(b'%s%s%s',%s)" % ( format_four_bytes(self.type_index), format_four_bytes(flags), self.name, ','.join(fields_expr)) class EnumExpr: def __init__(self, name, type_index, size, signed, allenums): self.name = name self.type_index = type_index self.size = size self.signed = signed self.allenums = allenums def as_c_expr(self): return (' { "%s", %d, _cffi_prim_int(%s, %s),\n' ' "%s" },' % (self.name, self.type_index, self.size, self.signed, self.allenums)) def as_python_expr(self): prim_index = { (1, 0): PRIM_UINT8, (1, 1): PRIM_INT8, (2, 0): PRIM_UINT16, (2, 1): PRIM_INT16, (4, 0): PRIM_UINT32, (4, 1): PRIM_INT32, (8, 0): PRIM_UINT64, (8, 1): PRIM_INT64, }[self.size, self.signed] return "b'%s%s%s\\x00%s'" % (format_four_bytes(self.type_index), format_four_bytes(prim_index), self.name, self.allenums) class TypenameExpr: def __init__(self, name, type_index): self.name = name self.type_index = type_index def as_c_expr(self): return ' { "%s", %d },' % (self.name, self.type_index) def as_python_expr(self): return "b'%s%s'" % (format_four_bytes(self.type_index), self.name) # ____________________________________________________________ class Recompiler: _num_externpy = 0 def __init__(self, ffi, module_name, target_is_python=False): self.ffi = ffi self.module_name = module_name self.target_is_python = target_is_python self._version = VERSION_BASE def needs_version(self, ver): self._version = max(self._version, ver) def collect_type_table(self): self._typesdict = {} self._generate("collecttype") # all_decls = sorted(self._typesdict, key=str) # # prepare all FUNCTION bytecode sequences first self.cffi_types = [] for tp in all_decls: if tp.is_raw_function: assert self._typesdict[tp] is None self._typesdict[tp] = len(self.cffi_types) self.cffi_types.append(tp) # placeholder for tp1 in tp.args: assert isinstance(tp1, (model.VoidType, model.BasePrimitiveType, model.PointerType, model.StructOrUnionOrEnum, model.FunctionPtrType)) if self._typesdict[tp1] is None: self._typesdict[tp1] = len(self.cffi_types) self.cffi_types.append(tp1) # placeholder self.cffi_types.append('END') # placeholder # # prepare all OTHER bytecode sequences for tp in all_decls: if not tp.is_raw_function and self._typesdict[tp] is None: self._typesdict[tp] = len(self.cffi_types) self.cffi_types.append(tp) # placeholder if tp.is_array_type and tp.length is not None: self.cffi_types.append('LEN') # placeholder assert None not in self._typesdict.values() # # collect all structs and unions and enums self._struct_unions = {} self._enums = {} for tp in all_decls: if isinstance(tp, model.StructOrUnion): self._struct_unions[tp] = None elif isinstance(tp, model.EnumType): self._enums[tp] = None for i, tp in enumerate(sorted(self._struct_unions, key=lambda tp: tp.name)): self._struct_unions[tp] = i for i, tp in enumerate(sorted(self._enums, key=lambda tp: tp.name)): self._enums[tp] = i # # emit all bytecode sequences now for tp in all_decls: method = getattr(self, '_emit_bytecode_' + tp.__class__.__name__) method(tp, self._typesdict[tp]) # # consistency check for op in self.cffi_types: assert isinstance(op, CffiOp) self.cffi_types = tuple(self.cffi_types) # don't change any more def _enum_fields(self, tp): # When producing C, expand all anonymous struct/union fields. # That's necessary to have C code checking the offsets of the # individual fields contained in them. When producing Python, # don't do it and instead write it like it is, with the # corresponding fields having an empty name. Empty names are # recognized at runtime when we import the generated Python # file. expand_anonymous_struct_union = not self.target_is_python return tp.enumfields(expand_anonymous_struct_union) def _do_collect_type(self, tp): if not isinstance(tp, model.BaseTypeByIdentity): if isinstance(tp, tuple): for x in tp: self._do_collect_type(x) return if tp not in self._typesdict: self._typesdict[tp] = None if isinstance(tp, model.FunctionPtrType): self._do_collect_type(tp.as_raw_function()) elif isinstance(tp, model.StructOrUnion): if tp.fldtypes is not None and ( tp not in self.ffi._parser._included_declarations): for name1, tp1, _, _ in self._enum_fields(tp): self._do_collect_type(self._field_type(tp, name1, tp1)) else: for _, x in tp._get_items(): self._do_collect_type(x) def _generate(self, step_name): lst = self.ffi._parser._declarations.items() for name, (tp, quals) in sorted(lst): kind, realname = name.split(' ', 1) try: method = getattr(self, '_generate_cpy_%s_%s' % (kind, step_name)) except AttributeError: raise VerificationError( "not implemented in recompile(): %r" % name) try: self._current_quals = quals method(tp, realname) except Exception as e: model.attach_exception_info(e, name) raise # ---------- ALL_STEPS = ["global", "field", "struct_union", "enum", "typename"] def collect_step_tables(self): # collect the declarations for '_cffi_globals', '_cffi_typenames', etc. self._lsts = {} for step_name in self.ALL_STEPS: self._lsts[step_name] = [] self._seen_struct_unions = set() self._generate("ctx") self._add_missing_struct_unions() # for step_name in self.ALL_STEPS: lst = self._lsts[step_name] if step_name != "field": lst.sort(key=lambda entry: entry.name) self._lsts[step_name] = tuple(lst) # don't change any more # # check for a possible internal inconsistency: _cffi_struct_unions # should have been generated with exactly self._struct_unions lst = self._lsts["struct_union"] for tp, i in self._struct_unions.items(): assert i < len(lst) assert lst[i].name == tp.name assert len(lst) == len(self._struct_unions) # same with enums lst = self._lsts["enum"] for tp, i in self._enums.items(): assert i < len(lst) assert lst[i].name == tp.name assert len(lst) == len(self._enums) # ---------- def _prnt(self, what=''): self._f.write(what + '\n') def write_source_to_f(self, f, preamble): if self.target_is_python: assert preamble is None self.write_py_source_to_f(f) else: assert preamble is not None self.write_c_source_to_f(f, preamble) def _rel_readlines(self, filename): g = open(os.path.join(os.path.dirname(__file__), filename), 'r') lines = g.readlines() g.close() return lines def write_c_source_to_f(self, f, preamble): self._f = f prnt = self._prnt if self.ffi._embedding is not None: prnt('#define _CFFI_USE_EMBEDDING') if not USE_LIMITED_API: prnt('#define _CFFI_NO_LIMITED_API') # # first the '#include' (actually done by inlining the file's content) lines = self._rel_readlines('_cffi_include.h') i = lines.index('#include "parse_c_type.h"\n') lines[i:i+1] = self._rel_readlines('parse_c_type.h') prnt(''.join(lines)) # # if we have ffi._embedding != None, we give it here as a macro # and include an extra file base_module_name = self.module_name.split('.')[-1] if self.ffi._embedding is not None: prnt('#define _CFFI_MODULE_NAME "%s"' % (self.module_name,)) prnt('static const char _CFFI_PYTHON_STARTUP_CODE[] = {') self._print_string_literal_in_array(self.ffi._embedding) prnt('0 };') prnt('#ifdef PYPY_VERSION') prnt('# define _CFFI_PYTHON_STARTUP_FUNC _cffi_pypyinit_%s' % ( base_module_name,)) prnt('#elif PY_MAJOR_VERSION >= 3') prnt('# define _CFFI_PYTHON_STARTUP_FUNC PyInit_%s' % ( base_module_name,)) prnt('#else') prnt('# define _CFFI_PYTHON_STARTUP_FUNC init%s' % ( base_module_name,)) prnt('#endif') lines = self._rel_readlines('_embedding.h') i = lines.index('#include "_cffi_errors.h"\n') lines[i:i+1] = self._rel_readlines('_cffi_errors.h') prnt(''.join(lines)) self.needs_version(VERSION_EMBEDDED) # # then paste the C source given by the user, verbatim. prnt('/************************************************************/') prnt() prnt(preamble) prnt() prnt('/************************************************************/') prnt() # # the declaration of '_cffi_types' prnt('static void *_cffi_types[] = {') typeindex2type = dict([(i, tp) for (tp, i) in self._typesdict.items()]) for i, op in enumerate(self.cffi_types): comment = '' if i in typeindex2type: comment = ' // ' + typeindex2type[i]._get_c_name() prnt('/* %2d */ %s,%s' % (i, op.as_c_expr(), comment)) if not self.cffi_types: prnt(' 0') prnt('};') prnt() # # call generate_cpy_xxx_decl(), for every xxx found from # ffi._parser._declarations. This generates all the functions. self._seen_constants = set() self._generate("decl") # # the declaration of '_cffi_globals' and '_cffi_typenames' nums = {} for step_name in self.ALL_STEPS: lst = self._lsts[step_name] nums[step_name] = len(lst) if nums[step_name] > 0: prnt('static const struct _cffi_%s_s _cffi_%ss[] = {' % ( step_name, step_name)) for entry in lst: prnt(entry.as_c_expr()) prnt('};') prnt() # # the declaration of '_cffi_includes' if self.ffi._included_ffis: prnt('static const char * const _cffi_includes[] = {') for ffi_to_include in self.ffi._included_ffis: try: included_module_name, included_source = ( ffi_to_include._assigned_source[:2]) except AttributeError: raise VerificationError( "ffi object %r includes %r, but the latter has not " "been prepared with set_source()" % ( self.ffi, ffi_to_include,)) if included_source is None: raise VerificationError( "not implemented yet: ffi.include() of a Python-based " "ffi inside a C-based ffi") prnt(' "%s",' % (included_module_name,)) prnt(' NULL') prnt('};') prnt() # # the declaration of '_cffi_type_context' prnt('static const struct _cffi_type_context_s _cffi_type_context = {') prnt(' _cffi_types,') for step_name in self.ALL_STEPS: if nums[step_name] > 0: prnt(' _cffi_%ss,' % step_name) else: prnt(' NULL, /* no %ss */' % step_name) for step_name in self.ALL_STEPS: if step_name != "field": prnt(' %d, /* num_%ss */' % (nums[step_name], step_name)) if self.ffi._included_ffis: prnt(' _cffi_includes,') else: prnt(' NULL, /* no includes */') prnt(' %d, /* num_types */' % (len(self.cffi_types),)) flags = 0 if self._num_externpy: flags |= 1 # set to mean that we use extern "Python" prnt(' %d, /* flags */' % flags) prnt('};') prnt() # # the init function prnt('#ifdef __GNUC__') prnt('# pragma GCC visibility push(default) /* for -fvisibility= */') prnt('#endif') prnt() prnt('#ifdef PYPY_VERSION') prnt('PyMODINIT_FUNC') prnt('_cffi_pypyinit_%s(const void *p[])' % (base_module_name,)) prnt('{') if self._num_externpy: prnt(' if (((intptr_t)p[0]) >= 0x0A03) {') prnt(' _cffi_call_python_org = ' '(void(*)(struct _cffi_externpy_s *, char *))p[1];') prnt(' }') prnt(' p[0] = (const void *)0x%x;' % self._version) prnt(' p[1] = &_cffi_type_context;') prnt('#if PY_MAJOR_VERSION >= 3') prnt(' return NULL;') prnt('#endif') prnt('}') # on Windows, distutils insists on putting init_cffi_xyz in # 'export_symbols', so instead of fighting it, just give up and # give it one prnt('# ifdef _MSC_VER') prnt(' PyMODINIT_FUNC') prnt('# if PY_MAJOR_VERSION >= 3') prnt(' PyInit_%s(void) { return NULL; }' % (base_module_name,)) prnt('# else') prnt(' init%s(void) { }' % (base_module_name,)) prnt('# endif') prnt('# endif') prnt('#elif PY_MAJOR_VERSION >= 3') prnt('PyMODINIT_FUNC') prnt('PyInit_%s(void)' % (base_module_name,)) prnt('{') prnt(' return _cffi_init("%s", 0x%x, &_cffi_type_context);' % ( self.module_name, self._version)) prnt('}') prnt('#else') prnt('PyMODINIT_FUNC') prnt('init%s(void)' % (base_module_name,)) prnt('{') prnt(' _cffi_init("%s", 0x%x, &_cffi_type_context);' % ( self.module_name, self._version)) prnt('}') prnt('#endif') prnt() prnt('#ifdef __GNUC__') prnt('# pragma GCC visibility pop') prnt('#endif') self._version = None def _to_py(self, x): if isinstance(x, str): return "b'%s'" % (x,) if isinstance(x, (list, tuple)): rep = [self._to_py(item) for item in x] if len(rep) == 1: rep.append('') return "(%s)" % (','.join(rep),) return x.as_python_expr() # Py2: unicode unexpected; Py3: bytes unexp. def write_py_source_to_f(self, f): self._f = f prnt = self._prnt # # header prnt("# auto-generated file") prnt("import _cffi_backend") # # the 'import' of the included ffis num_includes = len(self.ffi._included_ffis or ()) for i in range(num_includes): ffi_to_include = self.ffi._included_ffis[i] try: included_module_name, included_source = ( ffi_to_include._assigned_source[:2]) except AttributeError: raise VerificationError( "ffi object %r includes %r, but the latter has not " "been prepared with set_source()" % ( self.ffi, ffi_to_include,)) if included_source is not None: raise VerificationError( "not implemented yet: ffi.include() of a C-based " "ffi inside a Python-based ffi") prnt('from %s import ffi as _ffi%d' % (included_module_name, i)) prnt() prnt("ffi = _cffi_backend.FFI('%s'," % (self.module_name,)) prnt(" _version = 0x%x," % (self._version,)) self._version = None # # the '_types' keyword argument self.cffi_types = tuple(self.cffi_types) # don't change any more types_lst = [op.as_python_bytes() for op in self.cffi_types] prnt(' _types = %s,' % (self._to_py(''.join(types_lst)),)) typeindex2type = dict([(i, tp) for (tp, i) in self._typesdict.items()]) # # the keyword arguments from ALL_STEPS for step_name in self.ALL_STEPS: lst = self._lsts[step_name] if len(lst) > 0 and step_name != "field": prnt(' _%ss = %s,' % (step_name, self._to_py(lst))) # # the '_includes' keyword argument if num_includes > 0: prnt(' _includes = (%s,),' % ( ', '.join(['_ffi%d' % i for i in range(num_includes)]),)) # # the footer prnt(')') # ---------- def _gettypenum(self, type): # a KeyError here is a bug. please report it! :-) return self._typesdict[type] def _convert_funcarg_to_c(self, tp, fromvar, tovar, errcode): extraarg = '' if isinstance(tp, model.BasePrimitiveType) and not tp.is_complex_type(): if tp.is_integer_type() and tp.name != '_Bool': converter = '_cffi_to_c_int' extraarg = ', %s' % tp.name elif isinstance(tp, model.UnknownFloatType): # don't check with is_float_type(): it may be a 'long # double' here, and _cffi_to_c_double would loose precision converter = '(%s)_cffi_to_c_double' % (tp.get_c_name(''),) else: cname = tp.get_c_name('') converter = '(%s)_cffi_to_c_%s' % (cname, tp.name.replace(' ', '_')) if cname in ('char16_t', 'char32_t'): self.needs_version(VERSION_CHAR16CHAR32) errvalue = '-1' # elif isinstance(tp, model.PointerType): self._convert_funcarg_to_c_ptr_or_array(tp, fromvar, tovar, errcode) return # elif (isinstance(tp, model.StructOrUnionOrEnum) or isinstance(tp, model.BasePrimitiveType)): # a struct (not a struct pointer) as a function argument; # or, a complex (the same code works) self._prnt(' if (_cffi_to_c((char *)&%s, _cffi_type(%d), %s) < 0)' % (tovar, self._gettypenum(tp), fromvar)) self._prnt(' %s;' % errcode) return # elif isinstance(tp, model.FunctionPtrType): converter = '(%s)_cffi_to_c_pointer' % tp.get_c_name('') extraarg = ', _cffi_type(%d)' % self._gettypenum(tp) errvalue = 'NULL' # else: raise NotImplementedError(tp) # self._prnt(' %s = %s(%s%s);' % (tovar, converter, fromvar, extraarg)) self._prnt(' if (%s == (%s)%s && PyErr_Occurred())' % ( tovar, tp.get_c_name(''), errvalue)) self._prnt(' %s;' % errcode) def _extra_local_variables(self, tp, localvars, freelines): if isinstance(tp, model.PointerType): localvars.add('Py_ssize_t datasize') localvars.add('struct _cffi_freeme_s *large_args_free = NULL') freelines.add('if (large_args_free != NULL)' ' _cffi_free_array_arguments(large_args_free);') def _convert_funcarg_to_c_ptr_or_array(self, tp, fromvar, tovar, errcode): self._prnt(' datasize = _cffi_prepare_pointer_call_argument(') self._prnt(' _cffi_type(%d), %s, (char **)&%s);' % ( self._gettypenum(tp), fromvar, tovar)) self._prnt(' if (datasize != 0) {') self._prnt(' %s = ((size_t)datasize) <= 640 ? ' '(%s)alloca((size_t)datasize) : NULL;' % ( tovar, tp.get_c_name(''))) self._prnt(' if (_cffi_convert_array_argument(_cffi_type(%d), %s, ' '(char **)&%s,' % (self._gettypenum(tp), fromvar, tovar)) self._prnt(' datasize, &large_args_free) < 0)') self._prnt(' %s;' % errcode) self._prnt(' }') def _convert_expr_from_c(self, tp, var, context): if isinstance(tp, model.BasePrimitiveType): if tp.is_integer_type() and tp.name != '_Bool': return '_cffi_from_c_int(%s, %s)' % (var, tp.name) elif isinstance(tp, model.UnknownFloatType): return '_cffi_from_c_double(%s)' % (var,) elif tp.name != 'long double' and not tp.is_complex_type(): cname = tp.name.replace(' ', '_') if cname in ('char16_t', 'char32_t'): self.needs_version(VERSION_CHAR16CHAR32) return '_cffi_from_c_%s(%s)' % (cname, var) else: return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( var, self._gettypenum(tp)) elif isinstance(tp, (model.PointerType, model.FunctionPtrType)): return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( var, self._gettypenum(tp)) elif isinstance(tp, model.ArrayType): return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( var, self._gettypenum(model.PointerType(tp.item))) elif isinstance(tp, model.StructOrUnion): if tp.fldnames is None: raise TypeError("'%s' is used as %s, but is opaque" % ( tp._get_c_name(), context)) return '_cffi_from_c_struct((char *)&%s, _cffi_type(%d))' % ( var, self._gettypenum(tp)) elif isinstance(tp, model.EnumType): return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( var, self._gettypenum(tp)) else: raise NotImplementedError(tp) # ---------- # typedefs def _typedef_type(self, tp, name): return self._global_type(tp, "(*(%s *)0)" % (name,)) def _generate_cpy_typedef_collecttype(self, tp, name): self._do_collect_type(self._typedef_type(tp, name)) def _generate_cpy_typedef_decl(self, tp, name): pass def _typedef_ctx(self, tp, name): type_index = self._typesdict[tp] self._lsts["typename"].append(TypenameExpr(name, type_index)) def _generate_cpy_typedef_ctx(self, tp, name): tp = self._typedef_type(tp, name) self._typedef_ctx(tp, name) if getattr(tp, "origin", None) == "unknown_type": self._struct_ctx(tp, tp.name, approxname=None) elif isinstance(tp, model.NamedPointerType): self._struct_ctx(tp.totype, tp.totype.name, approxname=tp.name, named_ptr=tp) # ---------- # function declarations def _generate_cpy_function_collecttype(self, tp, name): self._do_collect_type(tp.as_raw_function()) if tp.ellipsis and not self.target_is_python: self._do_collect_type(tp) def _generate_cpy_function_decl(self, tp, name): assert not self.target_is_python assert isinstance(tp, model.FunctionPtrType) if tp.ellipsis: # cannot support vararg functions better than this: check for its # exact type (including the fixed arguments), and build it as a # constant function pointer (no CPython wrapper) self._generate_cpy_constant_decl(tp, name) return prnt = self._prnt numargs = len(tp.args) if numargs == 0: argname = 'noarg' elif numargs == 1: argname = 'arg0' else: argname = 'args' # # ------------------------------ # the 'd' version of the function, only for addressof(lib, 'func') arguments = [] call_arguments = [] context = 'argument of %s' % name for i, type in enumerate(tp.args): arguments.append(type.get_c_name(' x%d' % i, context)) call_arguments.append('x%d' % i) repr_arguments = ', '.join(arguments) repr_arguments = repr_arguments or 'void' if tp.abi: abi = tp.abi + ' ' else: abi = '' name_and_arguments = '%s_cffi_d_%s(%s)' % (abi, name, repr_arguments) prnt('static %s' % (tp.result.get_c_name(name_and_arguments),)) prnt('{') call_arguments = ', '.join(call_arguments) result_code = 'return ' if isinstance(tp.result, model.VoidType): result_code = '' prnt(' %s%s(%s);' % (result_code, name, call_arguments)) prnt('}') # prnt('#ifndef PYPY_VERSION') # ------------------------------ # prnt('static PyObject *') prnt('_cffi_f_%s(PyObject *self, PyObject *%s)' % (name, argname)) prnt('{') # context = 'argument of %s' % name for i, type in enumerate(tp.args): arg = type.get_c_name(' x%d' % i, context) prnt(' %s;' % arg) # localvars = set() freelines = set() for type in tp.args: self._extra_local_variables(type, localvars, freelines) for decl in sorted(localvars): prnt(' %s;' % (decl,)) # if not isinstance(tp.result, model.VoidType): result_code = 'result = ' context = 'result of %s' % name result_decl = ' %s;' % tp.result.get_c_name(' result', context) prnt(result_decl) prnt(' PyObject *pyresult;') else: result_decl = None result_code = '' # if len(tp.args) > 1: rng = range(len(tp.args)) for i in rng: prnt(' PyObject *arg%d;' % i) prnt() prnt(' if (!PyArg_UnpackTuple(args, "%s", %d, %d, %s))' % ( name, len(rng), len(rng), ', '.join(['&arg%d' % i for i in rng]))) prnt(' return NULL;') prnt() # for i, type in enumerate(tp.args): self._convert_funcarg_to_c(type, 'arg%d' % i, 'x%d' % i, 'return NULL') prnt() # prnt(' Py_BEGIN_ALLOW_THREADS') prnt(' _cffi_restore_errno();') call_arguments = ['x%d' % i for i in range(len(tp.args))] call_arguments = ', '.join(call_arguments) prnt(' { %s%s(%s); }' % (result_code, name, call_arguments)) prnt(' _cffi_save_errno();') prnt(' Py_END_ALLOW_THREADS') prnt() # prnt(' (void)self; /* unused */') if numargs == 0: prnt(' (void)noarg; /* unused */') if result_code: prnt(' pyresult = %s;' % self._convert_expr_from_c(tp.result, 'result', 'result type')) for freeline in freelines: prnt(' ' + freeline) prnt(' return pyresult;') else: for freeline in freelines: prnt(' ' + freeline) prnt(' Py_INCREF(Py_None);') prnt(' return Py_None;') prnt('}') # prnt('#else') # ------------------------------ # # the PyPy version: need to replace struct/union arguments with # pointers, and if the result is a struct/union, insert a first # arg that is a pointer to the result. We also do that for # complex args and return type. def need_indirection(type): return (isinstance(type, model.StructOrUnion) or (isinstance(type, model.PrimitiveType) and type.is_complex_type())) difference = False arguments = [] call_arguments = [] context = 'argument of %s' % name for i, type in enumerate(tp.args): indirection = '' if need_indirection(type): indirection = '*' difference = True arg = type.get_c_name(' %sx%d' % (indirection, i), context) arguments.append(arg) call_arguments.append('%sx%d' % (indirection, i)) tp_result = tp.result if need_indirection(tp_result): context = 'result of %s' % name arg = tp_result.get_c_name(' *result', context) arguments.insert(0, arg) tp_result = model.void_type result_decl = None result_code = '*result = ' difference = True if difference: repr_arguments = ', '.join(arguments) repr_arguments = repr_arguments or 'void' name_and_arguments = '%s_cffi_f_%s(%s)' % (abi, name, repr_arguments) prnt('static %s' % (tp_result.get_c_name(name_and_arguments),)) prnt('{') if result_decl: prnt(result_decl) call_arguments = ', '.join(call_arguments) prnt(' { %s%s(%s); }' % (result_code, name, call_arguments)) if result_decl: prnt(' return result;') prnt('}') else: prnt('# define _cffi_f_%s _cffi_d_%s' % (name, name)) # prnt('#endif') # ------------------------------ prnt() def _generate_cpy_function_ctx(self, tp, name): if tp.ellipsis and not self.target_is_python: self._generate_cpy_constant_ctx(tp, name) return type_index = self._typesdict[tp.as_raw_function()] numargs = len(tp.args) if self.target_is_python: meth_kind = OP_DLOPEN_FUNC elif numargs == 0: meth_kind = OP_CPYTHON_BLTN_N # 'METH_NOARGS' elif numargs == 1: meth_kind = OP_CPYTHON_BLTN_O # 'METH_O' else: meth_kind = OP_CPYTHON_BLTN_V # 'METH_VARARGS' self._lsts["global"].append( GlobalExpr(name, '_cffi_f_%s' % name, CffiOp(meth_kind, type_index), size='_cffi_d_%s' % name)) # ---------- # named structs or unions def _field_type(self, tp_struct, field_name, tp_field): if isinstance(tp_field, model.ArrayType): actual_length = tp_field.length if actual_length == '...': ptr_struct_name = tp_struct.get_c_name('*') actual_length = '_cffi_array_len(((%s)0)->%s)' % ( ptr_struct_name, field_name) tp_item = self._field_type(tp_struct, '%s[0]' % field_name, tp_field.item) tp_field = model.ArrayType(tp_item, actual_length) return tp_field def _struct_collecttype(self, tp): self._do_collect_type(tp) if self.target_is_python: # also requires nested anon struct/unions in ABI mode, recursively for fldtype in tp.anonymous_struct_fields(): self._struct_collecttype(fldtype) def _struct_decl(self, tp, cname, approxname): if tp.fldtypes is None: return prnt = self._prnt checkfuncname = '_cffi_checkfld_%s' % (approxname,) prnt('_CFFI_UNUSED_FN') prnt('static void %s(%s *p)' % (checkfuncname, cname)) prnt('{') prnt(' /* only to generate compile-time warnings or errors */') prnt(' (void)p;') for fname, ftype, fbitsize, fqual in self._enum_fields(tp): try: if ftype.is_integer_type() or fbitsize >= 0: # accept all integers, but complain on float or double if fname != '': prnt(" (void)((p->%s) | 0); /* check that '%s.%s' is " "an integer */" % (fname, cname, fname)) continue # only accept exactly the type declared, except that '[]' # is interpreted as a '*' and so will match any array length. # (It would also match '*', but that's harder to detect...) while (isinstance(ftype, model.ArrayType) and (ftype.length is None or ftype.length == '...')): ftype = ftype.item fname = fname + '[0]' prnt(' { %s = &p->%s; (void)tmp; }' % ( ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual), fname)) except VerificationError as e: prnt(' /* %s */' % str(e)) # cannot verify it, ignore prnt('}') prnt('struct _cffi_align_%s { char x; %s y; };' % (approxname, cname)) prnt() def _struct_ctx(self, tp, cname, approxname, named_ptr=None): type_index = self._typesdict[tp] reason_for_not_expanding = None flags = [] if isinstance(tp, model.UnionType): flags.append("_CFFI_F_UNION") if tp.fldtypes is None: flags.append("_CFFI_F_OPAQUE") reason_for_not_expanding = "opaque" if (tp not in self.ffi._parser._included_declarations and (named_ptr is None or named_ptr not in self.ffi._parser._included_declarations)): if tp.fldtypes is None: pass # opaque elif tp.partial or any(tp.anonymous_struct_fields()): pass # field layout obtained silently from the C compiler else: flags.append("_CFFI_F_CHECK_FIELDS") if tp.packed: if tp.packed > 1: raise NotImplementedError( "%r is declared with 'pack=%r'; only 0 or 1 are " "supported in API mode (try to use \"...;\", which " "does not require a 'pack' declaration)" % (tp, tp.packed)) flags.append("_CFFI_F_PACKED") else: flags.append("_CFFI_F_EXTERNAL") reason_for_not_expanding = "external" flags = '|'.join(flags) or '0' c_fields = [] if reason_for_not_expanding is None: enumfields = list(self._enum_fields(tp)) for fldname, fldtype, fbitsize, fqual in enumfields: fldtype = self._field_type(tp, fldname, fldtype) self._check_not_opaque(fldtype, "field '%s.%s'" % (tp.name, fldname)) # cname is None for _add_missing_struct_unions() only op = OP_NOOP if fbitsize >= 0: op = OP_BITFIELD size = '%d /* bits */' % fbitsize elif cname is None or ( isinstance(fldtype, model.ArrayType) and fldtype.length is None): size = '(size_t)-1' else: size = 'sizeof(((%s)0)->%s)' % ( tp.get_c_name('*') if named_ptr is None else named_ptr.name, fldname) if cname is None or fbitsize >= 0: offset = '(size_t)-1' elif named_ptr is not None: offset = '((char *)&((%s)0)->%s) - (char *)0' % ( named_ptr.name, fldname) else: offset = 'offsetof(%s, %s)' % (tp.get_c_name(''), fldname) c_fields.append( FieldExpr(fldname, offset, size, fbitsize, CffiOp(op, self._typesdict[fldtype]))) first_field_index = len(self._lsts["field"]) self._lsts["field"].extend(c_fields) # if cname is None: # unknown name, for _add_missing_struct_unions size = '(size_t)-2' align = -2 comment = "unnamed" else: if named_ptr is not None: size = 'sizeof(*(%s)0)' % (named_ptr.name,) align = '-1 /* unknown alignment */' else: size = 'sizeof(%s)' % (cname,) align = 'offsetof(struct _cffi_align_%s, y)' % (approxname,) comment = None else: size = '(size_t)-1' align = -1 first_field_index = -1 comment = reason_for_not_expanding self._lsts["struct_union"].append( StructUnionExpr(tp.name, type_index, flags, size, align, comment, first_field_index, c_fields)) self._seen_struct_unions.add(tp) def _check_not_opaque(self, tp, location): while isinstance(tp, model.ArrayType): tp = tp.item if isinstance(tp, model.StructOrUnion) and tp.fldtypes is None: raise TypeError( "%s is of an opaque type (not declared in cdef())" % location) def _add_missing_struct_unions(self): # not very nice, but some struct declarations might be missing # because they don't have any known C name. Check that they are # not partial (we can't complete or verify them!) and emit them # anonymously. lst = list(self._struct_unions.items()) lst.sort(key=lambda tp_order: tp_order[1]) for tp, order in lst: if tp not in self._seen_struct_unions: if tp.partial: raise NotImplementedError("internal inconsistency: %r is " "partial but was not seen at " "this point" % (tp,)) if tp.name.startswith('$') and tp.name[1:].isdigit(): approxname = tp.name[1:] elif tp.name == '_IO_FILE' and tp.forcename == 'FILE': approxname = 'FILE' self._typedef_ctx(tp, 'FILE') else: raise NotImplementedError("internal inconsistency: %r" % (tp,)) self._struct_ctx(tp, None, approxname) def _generate_cpy_struct_collecttype(self, tp, name): self._struct_collecttype(tp) _generate_cpy_union_collecttype = _generate_cpy_struct_collecttype def _struct_names(self, tp): cname = tp.get_c_name('') if ' ' in cname: return cname, cname.replace(' ', '_') else: return cname, '_' + cname def _generate_cpy_struct_decl(self, tp, name): self._struct_decl(tp, *self._struct_names(tp)) _generate_cpy_union_decl = _generate_cpy_struct_decl def _generate_cpy_struct_ctx(self, tp, name): self._struct_ctx(tp, *self._struct_names(tp)) _generate_cpy_union_ctx = _generate_cpy_struct_ctx # ---------- # 'anonymous' declarations. These are produced for anonymous structs # or unions; the 'name' is obtained by a typedef. def _generate_cpy_anonymous_collecttype(self, tp, name): if isinstance(tp, model.EnumType): self._generate_cpy_enum_collecttype(tp, name) else: self._struct_collecttype(tp) def _generate_cpy_anonymous_decl(self, tp, name): if isinstance(tp, model.EnumType): self._generate_cpy_enum_decl(tp) else: self._struct_decl(tp, name, 'typedef_' + name) def _generate_cpy_anonymous_ctx(self, tp, name): if isinstance(tp, model.EnumType): self._enum_ctx(tp, name) else: self._struct_ctx(tp, name, 'typedef_' + name) # ---------- # constants, declared with "static const ..." def _generate_cpy_const(self, is_int, name, tp=None, category='const', check_value=None): if (category, name) in self._seen_constants: raise VerificationError( "duplicate declaration of %s '%s'" % (category, name)) self._seen_constants.add((category, name)) # prnt = self._prnt funcname = '_cffi_%s_%s' % (category, name) if is_int: prnt('static int %s(unsigned long long *o)' % funcname) prnt('{') prnt(' int n = (%s) <= 0;' % (name,)) prnt(' *o = (unsigned long long)((%s) | 0);' ' /* check that %s is an integer */' % (name, name)) if check_value is not None: if check_value > 0: check_value = '%dU' % (check_value,) prnt(' if (!_cffi_check_int(*o, n, %s))' % (check_value,)) prnt(' n |= 2;') prnt(' return n;') prnt('}') else: assert check_value is None prnt('static void %s(char *o)' % funcname) prnt('{') prnt(' *(%s)o = %s;' % (tp.get_c_name('*'), name)) prnt('}') prnt() def _generate_cpy_constant_collecttype(self, tp, name): is_int = tp.is_integer_type() if not is_int or self.target_is_python: self._do_collect_type(tp) def _generate_cpy_constant_decl(self, tp, name): is_int = tp.is_integer_type() self._generate_cpy_const(is_int, name, tp) def _generate_cpy_constant_ctx(self, tp, name): if not self.target_is_python and tp.is_integer_type(): type_op = CffiOp(OP_CONSTANT_INT, -1) else: if self.target_is_python: const_kind = OP_DLOPEN_CONST else: const_kind = OP_CONSTANT type_index = self._typesdict[tp] type_op = CffiOp(const_kind, type_index) self._lsts["global"].append( GlobalExpr(name, '_cffi_const_%s' % name, type_op)) # ---------- # enums def _generate_cpy_enum_collecttype(self, tp, name): self._do_collect_type(tp) def _generate_cpy_enum_decl(self, tp, name=None): for enumerator in tp.enumerators: self._generate_cpy_const(True, enumerator) def _enum_ctx(self, tp, cname): type_index = self._typesdict[tp] type_op = CffiOp(OP_ENUM, -1) if self.target_is_python: tp.check_not_partial() for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): self._lsts["global"].append( GlobalExpr(enumerator, '_cffi_const_%s' % enumerator, type_op, check_value=enumvalue)) # if cname is not None and '$' not in cname and not self.target_is_python: size = "sizeof(%s)" % cname signed = "((%s)-1) <= 0" % cname else: basetp = tp.build_baseinttype(self.ffi, []) size = self.ffi.sizeof(basetp) signed = int(int(self.ffi.cast(basetp, -1)) < 0) allenums = ",".join(tp.enumerators) self._lsts["enum"].append( EnumExpr(tp.name, type_index, size, signed, allenums)) def _generate_cpy_enum_ctx(self, tp, name): self._enum_ctx(tp, tp._get_c_name()) # ---------- # macros: for now only for integers def _generate_cpy_macro_collecttype(self, tp, name): pass def _generate_cpy_macro_decl(self, tp, name): if tp == '...': check_value = None else: check_value = tp # an integer self._generate_cpy_const(True, name, check_value=check_value) def _generate_cpy_macro_ctx(self, tp, name): if tp == '...': if self.target_is_python: raise VerificationError( "cannot use the syntax '...' in '#define %s ...' when " "using the ABI mode" % (name,)) check_value = None else: check_value = tp # an integer type_op = CffiOp(OP_CONSTANT_INT, -1) self._lsts["global"].append( GlobalExpr(name, '_cffi_const_%s' % name, type_op, check_value=check_value)) # ---------- # global variables def _global_type(self, tp, global_name): if isinstance(tp, model.ArrayType): actual_length = tp.length if actual_length == '...': actual_length = '_cffi_array_len(%s)' % (global_name,) tp_item = self._global_type(tp.item, '%s[0]' % global_name) tp = model.ArrayType(tp_item, actual_length) return tp def _generate_cpy_variable_collecttype(self, tp, name): self._do_collect_type(self._global_type(tp, name)) def _generate_cpy_variable_decl(self, tp, name): prnt = self._prnt tp = self._global_type(tp, name) if isinstance(tp, model.ArrayType) and tp.length is None: tp = tp.item ampersand = '' else: ampersand = '&' # This code assumes that casts from "tp *" to "void *" is a # no-op, i.e. a function that returns a "tp *" can be called # as if it returned a "void *". This should be generally true # on any modern machine. The only exception to that rule (on # uncommon architectures, and as far as I can tell) might be # if 'tp' were a function type, but that is not possible here. # (If 'tp' is a function _pointer_ type, then casts from "fn_t # **" to "void *" are again no-ops, as far as I can tell.) decl = '*_cffi_var_%s(void)' % (name,) prnt('static ' + tp.get_c_name(decl, quals=self._current_quals)) prnt('{') prnt(' return %s(%s);' % (ampersand, name)) prnt('}') prnt() def _generate_cpy_variable_ctx(self, tp, name): tp = self._global_type(tp, name) type_index = self._typesdict[tp] if self.target_is_python: op = OP_GLOBAL_VAR else: op = OP_GLOBAL_VAR_F self._lsts["global"].append( GlobalExpr(name, '_cffi_var_%s' % name, CffiOp(op, type_index))) # ---------- # extern "Python" def _generate_cpy_extern_python_collecttype(self, tp, name): assert isinstance(tp, model.FunctionPtrType) self._do_collect_type(tp) _generate_cpy_dllexport_python_collecttype = \ _generate_cpy_extern_python_plus_c_collecttype = \ _generate_cpy_extern_python_collecttype def _extern_python_decl(self, tp, name, tag_and_space): prnt = self._prnt if isinstance(tp.result, model.VoidType): size_of_result = '0' else: context = 'result of %s' % name size_of_result = '(int)sizeof(%s)' % ( tp.result.get_c_name('', context),) prnt('static struct _cffi_externpy_s _cffi_externpy__%s =' % name) prnt(' { "%s.%s", %s, 0, 0 };' % ( self.module_name, name, size_of_result)) prnt() # arguments = [] context = 'argument of %s' % name for i, type in enumerate(tp.args): arg = type.get_c_name(' a%d' % i, context) arguments.append(arg) # repr_arguments = ', '.join(arguments) repr_arguments = repr_arguments or 'void' name_and_arguments = '%s(%s)' % (name, repr_arguments) if tp.abi == "__stdcall": name_and_arguments = '_cffi_stdcall ' + name_and_arguments # def may_need_128_bits(tp): return (isinstance(tp, model.PrimitiveType) and tp.name == 'long double') # size_of_a = max(len(tp.args)*8, 8) if may_need_128_bits(tp.result): size_of_a = max(size_of_a, 16) if isinstance(tp.result, model.StructOrUnion): size_of_a = 'sizeof(%s) > %d ? sizeof(%s) : %d' % ( tp.result.get_c_name(''), size_of_a, tp.result.get_c_name(''), size_of_a) prnt('%s%s' % (tag_and_space, tp.result.get_c_name(name_and_arguments))) prnt('{') prnt(' char a[%s];' % size_of_a) prnt(' char *p = a;') for i, type in enumerate(tp.args): arg = 'a%d' % i if (isinstance(type, model.StructOrUnion) or may_need_128_bits(type)): arg = '&' + arg type = model.PointerType(type) prnt(' *(%s)(p + %d) = %s;' % (type.get_c_name('*'), i*8, arg)) prnt(' _cffi_call_python(&_cffi_externpy__%s, p);' % name) if not isinstance(tp.result, model.VoidType): prnt(' return *(%s)p;' % (tp.result.get_c_name('*'),)) prnt('}') prnt() self._num_externpy += 1 def _generate_cpy_extern_python_decl(self, tp, name): self._extern_python_decl(tp, name, 'static ') def _generate_cpy_dllexport_python_decl(self, tp, name): self._extern_python_decl(tp, name, 'CFFI_DLLEXPORT ') def _generate_cpy_extern_python_plus_c_decl(self, tp, name): self._extern_python_decl(tp, name, '') def _generate_cpy_extern_python_ctx(self, tp, name): if self.target_is_python: raise VerificationError( "cannot use 'extern \"Python\"' in the ABI mode") if tp.ellipsis: raise NotImplementedError("a vararg function is extern \"Python\"") type_index = self._typesdict[tp] type_op = CffiOp(OP_EXTERN_PYTHON, type_index) self._lsts["global"].append( GlobalExpr(name, '&_cffi_externpy__%s' % name, type_op, name)) _generate_cpy_dllexport_python_ctx = \ _generate_cpy_extern_python_plus_c_ctx = \ _generate_cpy_extern_python_ctx def _print_string_literal_in_array(self, s): prnt = self._prnt prnt('// # NB. this is not a string because of a size limit in MSVC') if not isinstance(s, bytes): # unicode s = s.encode('utf-8') # -> bytes else: s.decode('utf-8') # got bytes, check for valid utf-8 try: s.decode('ascii') except UnicodeDecodeError: s = b'# -*- encoding: utf8 -*-\n' + s for line in s.splitlines(True): comment = line if type('//') is bytes: # python2 line = map(ord, line) # make a list of integers else: # python3 # type(line) is bytes, which enumerates like a list of integers comment = ascii(comment)[1:-1] prnt(('// ' + comment).rstrip()) printed_line = '' for c in line: if len(printed_line) >= 76: prnt(printed_line) printed_line = '' printed_line += '%d,' % (c,) prnt(printed_line) # ---------- # emitting the opcodes for individual types def _emit_bytecode_VoidType(self, tp, index): self.cffi_types[index] = CffiOp(OP_PRIMITIVE, PRIM_VOID) def _emit_bytecode_PrimitiveType(self, tp, index): prim_index = PRIMITIVE_TO_INDEX[tp.name] self.cffi_types[index] = CffiOp(OP_PRIMITIVE, prim_index) def _emit_bytecode_UnknownIntegerType(self, tp, index): s = ('_cffi_prim_int(sizeof(%s), (\n' ' ((%s)-1) | 0 /* check that %s is an integer type */\n' ' ) <= 0)' % (tp.name, tp.name, tp.name)) self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s) def _emit_bytecode_UnknownFloatType(self, tp, index): s = ('_cffi_prim_float(sizeof(%s) *\n' ' (((%s)1) / 2) * 2 /* integer => 0, float => 1 */\n' ' )' % (tp.name, tp.name)) self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s) def _emit_bytecode_RawFunctionType(self, tp, index): self.cffi_types[index] = CffiOp(OP_FUNCTION, self._typesdict[tp.result]) index += 1 for tp1 in tp.args: realindex = self._typesdict[tp1] if index != realindex: if isinstance(tp1, model.PrimitiveType): self._emit_bytecode_PrimitiveType(tp1, index) else: self.cffi_types[index] = CffiOp(OP_NOOP, realindex) index += 1 flags = int(tp.ellipsis) if tp.abi is not None: if tp.abi == '__stdcall': flags |= 2 else: raise NotImplementedError("abi=%r" % (tp.abi,)) self.cffi_types[index] = CffiOp(OP_FUNCTION_END, flags) def _emit_bytecode_PointerType(self, tp, index): self.cffi_types[index] = CffiOp(OP_POINTER, self._typesdict[tp.totype]) _emit_bytecode_ConstPointerType = _emit_bytecode_PointerType _emit_bytecode_NamedPointerType = _emit_bytecode_PointerType def _emit_bytecode_FunctionPtrType(self, tp, index): raw = tp.as_raw_function() self.cffi_types[index] = CffiOp(OP_POINTER, self._typesdict[raw]) def _emit_bytecode_ArrayType(self, tp, index): item_index = self._typesdict[tp.item] if tp.length is None: self.cffi_types[index] = CffiOp(OP_OPEN_ARRAY, item_index) elif tp.length == '...': raise VerificationError( "type %s badly placed: the '...' array length can only be " "used on global arrays or on fields of structures" % ( str(tp).replace('/*...*/', '...'),)) else: assert self.cffi_types[index + 1] == 'LEN' self.cffi_types[index] = CffiOp(OP_ARRAY, item_index) self.cffi_types[index + 1] = CffiOp(None, str(tp.length)) def _emit_bytecode_StructType(self, tp, index): struct_index = self._struct_unions[tp] self.cffi_types[index] = CffiOp(OP_STRUCT_UNION, struct_index) _emit_bytecode_UnionType = _emit_bytecode_StructType def _emit_bytecode_EnumType(self, tp, index): enum_index = self._enums[tp] self.cffi_types[index] = CffiOp(OP_ENUM, enum_index) if sys.version_info >= (3,): NativeIO = io.StringIO else: class NativeIO(io.BytesIO): def write(self, s): if isinstance(s, unicode): s = s.encode('ascii') super(NativeIO, self).write(s) def _make_c_or_py_source(ffi, module_name, preamble, target_file, verbose): if verbose: print("generating %s" % (target_file,)) recompiler = Recompiler(ffi, module_name, target_is_python=(preamble is None)) recompiler.collect_type_table() recompiler.collect_step_tables() f = NativeIO() recompiler.write_source_to_f(f, preamble) output = f.getvalue() try: with open(target_file, 'r') as f1: if f1.read(len(output) + 1) != output: raise IOError if verbose: print("(already up-to-date)") return False # already up-to-date except IOError: tmp_file = '%s.~%d' % (target_file, os.getpid()) with open(tmp_file, 'w') as f1: f1.write(output) try: os.rename(tmp_file, target_file) except OSError: os.unlink(target_file) os.rename(tmp_file, target_file) return True def make_c_source(ffi, module_name, preamble, target_c_file, verbose=False): assert preamble is not None return _make_c_or_py_source(ffi, module_name, preamble, target_c_file, verbose) def make_py_source(ffi, module_name, target_py_file, verbose=False): return _make_c_or_py_source(ffi, module_name, None, target_py_file, verbose) def _modname_to_file(outputdir, modname, extension): parts = modname.split('.') try: os.makedirs(os.path.join(outputdir, *parts[:-1])) except OSError: pass parts[-1] += extension return os.path.join(outputdir, *parts), parts # Aaargh. Distutils is not tested at all for the purpose of compiling # DLLs that are not extension modules. Here are some hacks to work # around that, in the _patch_for_*() functions... def _patch_meth(patchlist, cls, name, new_meth): old = getattr(cls, name) patchlist.append((cls, name, old)) setattr(cls, name, new_meth) return old def _unpatch_meths(patchlist): for cls, name, old_meth in reversed(patchlist): setattr(cls, name, old_meth) def _patch_for_embedding(patchlist): if sys.platform == 'win32': # we must not remove the manifest when building for embedding! from distutils.msvc9compiler import MSVCCompiler _patch_meth(patchlist, MSVCCompiler, '_remove_visual_c_ref', lambda self, manifest_file: manifest_file) if sys.platform == 'darwin': # we must not make a '-bundle', but a '-dynamiclib' instead from distutils.ccompiler import CCompiler def my_link_shared_object(self, *args, **kwds): if '-bundle' in self.linker_so: self.linker_so = list(self.linker_so) i = self.linker_so.index('-bundle') self.linker_so[i] = '-dynamiclib' return old_link_shared_object(self, *args, **kwds) old_link_shared_object = _patch_meth(patchlist, CCompiler, 'link_shared_object', my_link_shared_object) def _patch_for_target(patchlist, target): from distutils.command.build_ext import build_ext # if 'target' is different from '*', we need to patch some internal # method to just return this 'target' value, instead of having it # built from module_name if target.endswith('.*'): target = target[:-2] if sys.platform == 'win32': target += '.dll' elif sys.platform == 'darwin': target += '.dylib' else: target += '.so' _patch_meth(patchlist, build_ext, 'get_ext_filename', lambda self, ext_name: target) def recompile(ffi, module_name, preamble, tmpdir='.', call_c_compiler=True, c_file=None, source_extension='.c', extradir=None, compiler_verbose=1, target=None, debug=None, **kwds): if not isinstance(module_name, str): module_name = module_name.encode('ascii') if ffi._windows_unicode: ffi._apply_windows_unicode(kwds) if preamble is not None: embedding = (ffi._embedding is not None) if embedding: ffi._apply_embedding_fix(kwds) if c_file is None: c_file, parts = _modname_to_file(tmpdir, module_name, source_extension) if extradir: parts = [extradir] + parts ext_c_file = os.path.join(*parts) else: ext_c_file = c_file # if target is None: if embedding: target = '%s.*' % module_name else: target = '*' # ext = ffiplatform.get_extension(ext_c_file, module_name, **kwds) updated = make_c_source(ffi, module_name, preamble, c_file, verbose=compiler_verbose) if call_c_compiler: patchlist = [] cwd = os.getcwd() try: if embedding: _patch_for_embedding(patchlist) if target != '*': _patch_for_target(patchlist, target) if compiler_verbose: if tmpdir == '.': msg = 'the current directory is' else: msg = 'setting the current directory to' print('%s %r' % (msg, os.path.abspath(tmpdir))) os.chdir(tmpdir) outputfilename = ffiplatform.compile('.', ext, compiler_verbose, debug) finally: os.chdir(cwd) _unpatch_meths(patchlist) return outputfilename else: return ext, updated else: if c_file is None: c_file, _ = _modname_to_file(tmpdir, module_name, '.py') updated = make_py_source(ffi, module_name, c_file, verbose=compiler_verbose) if call_c_compiler: return c_file else: return None, updated