Aceasta este comanda perlxs care poate fi rulată în furnizorul de găzduire gratuit OnWorks folosind una dintre multiplele noastre stații de lucru online gratuite, cum ar fi Ubuntu Online, Fedora Online, emulator online Windows sau emulator online MAC OS
PROGRAM:
NUME
perlxs - manual de referință în limba XS
DESCRIERE
Introducere
XS este un format de fișier de descriere a interfeței utilizat pentru a crea o interfață de extensie între
Codul Perl și C (sau o bibliotecă C) pe care doriți să îl utilizați cu Perl. Interfața XS este
combinat cu biblioteca pentru a crea o nouă bibliotecă care poate fi apoi fie dinamic
încărcat sau legat static în perl. Descrierea interfeței XS este scrisă în XS
limba și este componenta de bază a interfeței extensiei Perl.
Înainte de a scrie XS, citiți secțiunea „Avertismente” de mai jos.
An XSUB formează unitatea de bază a interfeței XS. După compilarea de către xsubpp
compilator, fiecare XSUB echivalează cu o definiție a funcției C care va furniza lipiciul între
Convenții de apelare Perl și convenții de apelare C.
Codul glue extrage argumentele din stiva Perl, convertește aceste valori Perl în
formatele așteptate de o funcție C, apelați această funcție C, transferă valorile returnate ale
Funcția C înapoi la Perl. Valorile returnate aici pot fi o valoare de returnare C convențională sau orice C
argumente ale funcției care pot servi ca parametri de ieșire. Aceste valori returnate pot fi transmise
înapoi la Perl fie punându-le în stiva Perl, fie modificând argumentele
furnizate din partea Perl.
Cele de mai sus este o vedere oarecum simplificată a ceea ce se întâmplă cu adevărat. Din moment ce Perl permite mai mult
convențiile de apelare flexibile decât C, XSUB-urile pot face mult mai mult în practică, cum ar fi verificarea
parametrii de intrare pentru valabilitate, aruncarea de excepții (sau returnarea listei undef/vide) dacă
valoarea returnată de la funcția C indică eșec, apelând diferite funcții C pe baza
numerele și tipurile de argumente, oferind o interfață orientată pe obiecte etc.
Desigur, s-ar putea scrie un astfel de cod lipici direct în C. Cu toate acestea, ar fi un obositor
sarcină, mai ales dacă trebuie să scrieți lipici pentru mai multe funcții C și/sau una nu este
suficient de familiarizat cu disciplina stivă Perl și alte asemenea arcane. XS vine la
salvați aici: în loc să scrieți acest cod lipici C cu mâna lungă, se poate scrie un mai mult
scurtătură concisă descriere de ceea ce ar trebui să fie făcut de lipici, și lăsați compilatorul XS
xsubpp se ocupă de restul.
Limbajul XS vă permite să descrieți maparea dintre modul în care este utilizată rutina C și
cum este utilizată rutina Perl corespunzătoare. De asemenea, permite crearea de rutine Perl
care sunt traduse direct în cod C și care nu sunt legate de un C preexistent
funcţie. În cazurile în care interfața C coincide cu interfața Perl, XSUB
declarația este aproape identică cu o declarație a unei funcții C (în stilul K&R). În așa
circumstanțe, există un alt instrument numit „h2xs” care este capabil să traducă un întreg C
fișierul antet într-un fișier XS corespunzător care va oferi lipici funcțiilor/macro-urilor
descrise în fișierul antet.
Se apelează compilatorul XS xsubpp. Acest compilator creează constructele necesare pentru a lăsa
un XSUB manipulează valorile Perl și creează lipiciul necesar pentru a permite lui Perl să apeleze XSUB.
Compilatorul folosește hărți de tip pentru a determina cum să mapați parametrii funcției C și valorile de ieșire
la valorile Perl și înapoi. Typemap implicit (care vine cu Perl) gestionează multe obișnuite
tipurile C. Poate fi necesară și o hartă de tip suplimentară pentru a gestiona orice structuri speciale și
tipuri pentru biblioteca care este legată. Pentru mai multe informații despre hărți de tip, consultați perlxstypemap.
Un fișier în format XS începe cu o secțiune în limbaj C care merge până la primul „MODULE ="
directivă. Alte directive XS și definiții XSUB pot urma această linie. Limba"
folosit în această parte a fișierului este de obicei denumit limba XS. xsubpp
recunoaște și omite POD (vezi perlpod) atât în secțiunile limbajului C cât și în XS, care
permite fișierului XS să conțină documentație încorporată.
Consultați perlxstut pentru un tutorial despre întregul proces de creare a extensiilor.
Notă: Pentru unele extensii, sistemul SWIG al lui Dave Beazley poate oferi mult mai mult
mecanism convenabil pentru crearea codului de lipici de extensie. Vedeahttp://www.swig.org/> pentru
mai multe informatii.
On drum
Multe dintre exemplele care urmează se vor concentra pe crearea unei interfețe între Perl
și funcțiile de bibliotecă de legături ONC+ RPC. The rpcb_gettime() funcția este obișnuită
demonstrează multe caracteristici ale limbajului XS. Această funcție are doi parametri; primul
este un parametru de intrare, iar al doilea este un parametru de ieșire. Funcția returnează și a
valoare de stare.
bool_t rpcb_gettime(const char *gazdă, time_t *timep);
Din C această funcție va fi apelată cu următoarele instrucțiuni.
#include
stare bool_t;
time_t timep;
status = rpcb_gettime( "localhost", &timep );
Dacă un XSUB este creat pentru a oferi o traducere directă între această funcție și Perl, atunci
acest XSUB va fi folosit din Perl cu următorul cod. $status și $timep
variabilele vor conține rezultatul funcției.
utilizați RPC;
$status = rpcb_gettime( "localhost", $timep );
Următorul fișier XS arată o subrutină XS, sau XSUB, care demonstrează una posibilă
interfață către rpcb_gettime() funcţie. Acest XSUB reprezintă o traducere directă
între C și Perl și astfel păstrează interfața chiar și din Perl. Acest XSUB va fi
invocat din Perl cu utilizarea prezentată mai sus. Rețineți că primele trei #include
declarațiile, pentru „EXTERN.h”, „perl.h” și „XSUB.h”, vor fi întotdeauna prezente la
începutul unui fișier XS. Această abordare și altele vor fi extinse mai târziu
document. O #define pentru „PERL_NO_GET_CONTEXT” ar trebui să fie prezentă pentru a prelua interpretul
context mai eficient, vezi perlguts pentru detalii.
#define PERL_NO_GET_CONTEXT
#include „EXTERN.h”
#include „perl.h”
#include „XSUB.h”
#include
MODUL = RPC PACHET = RPC
bool_t
rpcb_gettime(gazdă,timep)
char *gazdă
time_t &timep
IEȘIRE:
timep
Orice extensie la Perl, inclusiv cele care conțin XSUB-uri, ar trebui să aibă un modul Perl la
servește ca bootstrap care trage extensia în Perl. Acest modul va exporta fișierul
funcțiile și variabilele extensiei la programul Perl și va provoca extensia
XSUB-urile să fie conectate în Perl. Următorul modul va fi folosit pentru majoritatea exemplelor
în acest document și ar trebui să fie folosit din Perl cu comanda „utilizare” așa cum a fost arătat mai devreme.
Modulele Perl sunt explicate mai detaliat mai târziu în acest document.
pachet RPC;
solicita Exportator;
necesită DynaLoader;
@ISA = qw(Exportator DynaLoader);
@EXPORT = qw( rpcb_gettime );
bootstrap RPC;
1;
De-a lungul acestui document, o varietate de interfețe pentru rpcb_gettime() XSUB va fi
explorat. XSUB-urile își vor lua parametrii în ordine diferite sau vor lua diferite
numere de parametri. În fiecare caz, XSUB este o abstractizare între Perl și real
C rpcb_gettime() funcția, iar XSUB trebuie să se asigure întotdeauna că real rpcb_gettime()
funcția este apelată cu parametrii corecti. Această abstractizare va permite
programator pentru a crea o interfață mai asemănătoare cu Perl pentru funcția C.
Anatomie of an XSUB
Cele mai simple XSUB-uri constau din 3 părți: o descriere a valorii returnate, numele lui
Rutina XSUB și numele argumentelor sale și o descriere a tipurilor sau formatelor
argumente.
Următorul XSUB permite unui program Perl să acceseze o funcție de bibliotecă C numită păcat().
XSUB va imita funcția C care ia un singur argument și returnează o singură valoare.
dubla
păcat (x)
dublu x
Opțional, se poate îmbina descrierea tipurilor și lista numelor de argumente,
rescriind aceasta ca
dubla
păcat (x dublu)
Acest lucru face ca acest XSUB să arate similar cu o declarație ANSI C. Un punct și virgulă opțional este
permis după lista de argumente, ca în
dubla
sin(dublu x);
Parametrii cu tipuri de pointer C pot avea semantică diferită: funcții C cu similare
declarații
bool șir_pare_ca_un_număr(car *s);
bool make_char_uppercase(char *c);
sunt folosite într-un mod absolut incompatibil. Parametrii acestor funcții ar putea fi
descris xsubpp asa:
char * s
char &c
Ambele declarații XS corespund tipului C „char*”, dar au diferite
semantică, vezi „Operatorul & Unary”.
Este convenabil să ne gândim că operatorul indirect „*” ar trebui considerat ca o parte
de tip și operatorul de adresă „&” ar trebui să fie considerate parte a variabilei. Vedea
perlxstypemap pentru mai multe informații despre gestionarea calificatorilor și a operatorilor unari în tipurile C.
Numele funcției și tipul de returnare trebuie plasate pe linii separate și ar trebui să fie la nivel
reglat la stânga.
INCORECT CORECT
dublu sin(x) dublu
dublu x sin(x)
dublu x
Restul descrierii funcției poate fi indentat sau ajustat la stânga. Următoarele
exemplu arată o funcție cu corpul ei ajustat la stânga. Majoritatea exemplelor din acest document vor
indentați corpul pentru o mai bună lizibilitate.
CORECTĂ
dubla
păcat (x)
dublu x
XSUB-urile mai complicate pot conține multe alte secțiuni. Fiecare secțiune a unui XSUB începe
cu cuvântul cheie corespunzător, cum ar fi INIT: sau CLEANUP:. Cu toate acestea, primele două rânduri
a unui XSUB conțin întotdeauna aceleași date: descrieri ale tipului de returnare și numele de
funcția și parametrii acesteia. Orice urmează imediat după acestea este considerat a fi
o secțiune INPUT: dacă nu este marcată în mod explicit cu un alt cuvânt cheie. (Consultați „INTRAREA:
cuvânt cheie".)
O secțiune XSUB continuă până când este găsit un alt cuvânt cheie de început de secțiune.
Argument Stivui
Stiva de argumente Perl este folosită pentru a stoca valorile care sunt trimise ca parametri către
XSUB și pentru a stoca valorile returnate ale XSUB-ului. În realitate, toate funcțiile Perl (inclusiv
cele non-XSUB) își păstrează valorile pe această stivă în același timp, fiecare limitată la propriile sale
gama de poziții pe stivă. În acest document prima poziţie pe acel stivă care
aparține funcției active va fi denumită poziția 0 pentru acea funcție.
XSUB-urile se referă la argumentele stivei lor cu macrocomandă ST(x), În cazul în care x se referă la o poziție în
acest XSUB face parte din stivă. Poziția 0 pentru acea funcție ar fi cunoscută de XSUB ca
ST(0). Parametrii de intrare ai XSUB și valorile returnate de ieșire încep întotdeauna la ST(0).
Pentru multe cazuri simple, xsubpp compilatorul va genera codul necesar pentru a gestiona
stiva de argumente prin încorporarea fragmentelor de cod găsite în hărțile de tip. În cazuri mai complexe
programatorul trebuie să furnizeze codul.
RETVAL Variabil
Variabila RETVAL este o variabilă C specială care este declarată automat pentru dvs. C
tipul de RETVAL se potrivește cu tipul de returnare al funcției de bibliotecă C. The xsubpp compilator
va declara această variabilă în fiecare XSUB cu tip de returnare non-"void". În mod implicit,
funcția C generată va folosi RETVAL pentru a păstra valoarea returnată a funcției de bibliotecă C
fiind chemat. În cazuri simple se va plasa valoarea RETVAL ST(0) al argumentului
stiva unde poate fi primit de Perl ca valoare returnată a XSUB.
Dacă XSUB are un tip de returnare „void”, atunci compilatorul nu va declara un RETVAL
variabilă pentru acea funcție. Când utilizați un PPCODE: secțiunea fără manipulare a RETVAL
este necesară, secțiunea poate folosi manipularea directă a stivei pentru a plasa valorile de ieșire
pe stivă.
Dacă directiva PPCODE: nu este utilizată, valoarea returnată „void” ar trebui utilizată numai pentru subrutine
care nu returnează o valoare, chiar if COD: este folosită directiva care setează ST(0) în mod explicit.
Versiunile mai vechi ale acestui document recomandă utilizarea valorii returnate „void” în astfel de cazuri. Aceasta
s-a descoperit că acest lucru ar putea duce la erori de securitate în cazurile în care XSUB a fost cu adevărat „vid”. Acest
practica este acum depreciată și este posibil să nu fie acceptată la o versiune viitoare. Folosește
returnează valoarea „SV *” în astfel de cazuri. (În prezent, „xsubpp” conține un cod euristic care
încearcă să dezambiguizeze între funcțiile „cu adevărat-void” și „veche-practice-declarate-ca-vile”.
Prin urmare, codul dvs. este la cheremul acestei euristici, cu excepția cazului în care utilizați „SV *” ca valoare de returnare.)
Revenind SV-uri, SFTP si HV-uri prin RETVAL
Când utilizați RETVAL pentru a returna un „SV *”, există ceva magie în spatele lui
scene care ar trebui menționate. Când manipulați stiva de argumente folosind
Macro ST(x), de exemplu, de obicei trebuie să acordați o atenție deosebită numărărilor de referință.
(Pentru mai multe despre numărul de referințe, consultați perlguts.) Pentru a vă face viața mai ușoară, tiparta
fișierul face automat „RETVAL” mortal atunci când returnați un „SV *”. Astfel, cel
următoarele două XSUB sunt mai mult sau mai puțin echivalente:
anula
alfa()
PPCODE:
ST(0) = newSVpv("Bună lume",0);
sv_2muritor(ST(0));
XSRETURN(1);
SV *
beta()
COD:
RETVAL = newSVpv("Bună lume",0);
IEȘIRE:
RETVAL
Acest lucru este destul de util, deoarece de obicei îmbunătățește lizibilitatea. În timp ce acest lucru funcționează bine pentru un „SV
*”, din păcate nu este la fel de ușor să ai „AV *” sau „HV *” ca valoare de returnare. să
sa poata scrie:
AV *
array ()
COD:
RETVAL = newAV();
/* face ceva cu RETVAL */
IEȘIRE:
RETVAL
Dar din cauza unei erori neremediabile (remedierea acesteia ar sparge o mulțime de module CPAN existente) în
typemap, numărul de referințe al „AV *” nu este decrementat corespunzător. Astfel, cel
de mai sus XSUB ar pierde memorie ori de câte ori este apelat. Aceeași problemă există și pentru „HV
*”, „CV *” și „SVREF” (care indică o referință scalară, nu un „SV *”) general. În XS
cod pe perls începând cu perl 5.16, puteți suprascrie hărțile de tip pentru oricare dintre acestea
tipuri cu o versiune care are o gestionare adecvată a refcounts. În secțiunea „TYPEMAP”, procedați
AV* T_AVREF_REFCOUNT_FIXED
pentru a obține varianta reparată. Pentru compatibilitate cu versiunile mai vechi de perl, tu
poate, în schimb, să scadă manual numărul de referințe atunci când returnați unul dintre
tipurile menționate mai sus folosind „sv_2mortal”:
AV *
array ()
COD:
RETVAL = newAV();
sv_2mortal((SV*)RETVAL);
/* face ceva cu RETVAL */
IEȘIRE:
RETVAL
Amintiți-vă că nu trebuie să faceți acest lucru pentru un „SV *”. Documentația de referință pentru toți
hărțile de tip de bază pot fi găsite în perlxstypemap.
MODULUL Cuvânt cheie
Cuvântul cheie MODULE este folosit pentru a porni codul XS și pentru a specifica pachetul
funcții care sunt în curs de definire. Tot textul care precede primul cuvânt cheie MODULE este
considerat cod C și este transmis la ieșire cu POD dezlipit, dar altfel
neatins. Fiecare modul XS va avea o funcție de bootstrap care este folosită pentru a conecta XSUB-urile
în Perl. Numele pachetului acestei funcții de bootstrap se va potrivi cu valoarea ultimei
Instrucțiunea MODULE în fișierele sursă XS. Valoarea MODULUI ar trebui să rămână întotdeauna
constantă în același fișier XS, deși acest lucru nu este necesar.
Următorul exemplu va porni codul XS și va plasa toate funcțiile într-un pachet
numit RPC.
MODUL = RPC
PACHET Cuvânt cheie
Când funcțiile dintr-un fișier sursă XS trebuie separate în pachete, PACHETUL
ar trebui folosit cuvântul cheie. Acest cuvânt cheie este folosit împreună cu cuvântul cheie MODULE și trebuie să urmeze
imediat după el când este folosit.
MODUL = RPC PACHET = RPC
[Codul XS în pachetul RPC]
MODUL = PACHET RPC = RPCB
[Codul XS în pachetul RPCB]
MODUL = RPC PACHET = RPC
[Codul XS în pachetul RPC]
Același nume de pachet poate fi folosit de mai multe ori, permițând codul necontiguu. Acest
este util dacă aveți un principiu de comandă mai puternic decât numele pachetelor.
Deși acest cuvânt cheie este opțional și în unele cazuri oferă informații redundante, acesta
trebuie folosit întotdeauna. Acest cuvânt cheie va asigura că XSUB-urile apar în câmpul dorit
pachet.
PREFIX Cuvânt cheie
Cuvântul cheie PREFIX desemnează prefixele care ar trebui eliminate din funcția Perl
nume. Dacă funcția C este „rpcb_gettime()” și valoarea PREFIX este „rpcb_”, atunci Perl
va vedea această funcție ca „gettime()”.
Acest cuvânt cheie ar trebui să urmeze cuvântul cheie PACKAGE atunci când este utilizat. Dacă PACHETUL nu este folosit atunci
PREFIX ar trebui să urmeze cuvântul cheie MODULE.
MODUL = PREFIX RPC = rpc_
MODUL = PACHET RPC = PREFIX RPCB = rpcb_
IEȘIRE: Cuvânt cheie
Cuvântul cheie OUTPUT: indică faptul că anumiți parametri ai funcției ar trebui actualizați (nou
valorile făcute vizibile pentru Perl) când XSUB se termină sau că anumite valori ar trebui să fie
a revenit la funcția Perl de apelare. Pentru funcții simple care nu au COD: sau
PPCODE: secțiune, cum ar fi păcat() funcția de mai sus, variabila RETVAL este automat
desemnată ca valoare de ieșire. Pentru funcții mai complexe, xsubpp compilatorul va avea nevoie
ajută la determinarea care variabile sunt variabile de ieșire.
Acest cuvânt cheie va fi folosit în mod normal pentru a completa cuvântul cheie CODE:. Variabila RETVAL
nu este recunoscută ca o variabilă de ieșire când este prezent cuvântul cheie CODE:. IEȘIRE:
cuvântul cheie este folosit în această situație pentru a spune compilatorului că RETVAL este într-adevăr o ieșire
variabilă.
Cuvântul cheie OUTPUT: poate fi folosit și pentru a indica faptul că sunt ieșiți parametrii funcției
variabile. Acest lucru poate fi necesar atunci când un parametru a fost modificat în cadrul funcției
iar programatorul ar dori ca actualizarea să fie văzută de Perl.
bool_t
rpcb_gettime(gazdă,timep)
char *gazdă
time_t &timep
IEȘIRE:
timep
Cuvântul cheie OUTPUT: va permite, de asemenea, maparea unui parametru de ieșire la o piesă potrivită
de cod, mai degrabă decât la o hartă de tipuri.
bool_t
rpcb_gettime(gazdă,timep)
char *gazdă
time_t &timep
IEȘIRE:
timep sv_setnv(ST(1), timp (dublu);
xsubpp emite un „SvSETMAGIC()” automat pentru toți parametrii din secțiunea OUTPUT a
XSUB, cu excepția RETVAL. Acesta este comportamentul de obicei dorit, deoarece se îngrijește în mod corespunzător
invocarea „setului” magic asupra parametrilor de ieșire (necesar pentru parametrii elementului hash sau matrice
care trebuie create dacă nu au existat). Dacă din anumite motive, acest comportament nu este
dorit, secțiunea OUTPUT poate conține o linie „SETMAGIC: DISABLE” pentru a o dezactiva pentru
restul parametrilor din secțiunea OUTPUT. La fel, „SETMAGIC: ENABLE” poate fi
folosit pentru a-l reactiva pentru restul secțiunii OUTPUT. Vedeți perlguts pentru mai multe
detalii despre magia „setată”.
NO_OUTPUT Cuvânt cheie
NO_OUTPUT poate fi plasat ca primul simbol al XSUB. Acest cuvânt cheie indică faptul că
în timp ce subrutina C pentru care oferim o interfață are un tip de returnare non-"void", returnarea
valoarea acestei subrutine C nu trebuie returnată din subrutina Perl generată.
Cu acest cuvânt cheie prezent „Variabila RETVAL” este creată, iar în apelul generat la
subrutinei căreia îi este atribuită această variabilă, dar valoarea acestei variabile nu merge
pentru a fi utilizat în codul generat automat.
Acest cuvânt cheie are sens numai dacă „RETVAL” va fi accesat de către utilizator
cod. Este deosebit de util să faceți o interfață de funcție mai asemănătoare cu Perl, în special
când valoarea de returnare C este doar un indicator de stare de eroare. De exemplu,
NO_OUTPUT int
delete_file(car *nume)
APEL POSTAL:
dacă (RETVAL != 0)
croak("Eroare %d la ștergerea fișierului '%s'", RETVAL, nume);
Aici, funcția XS generată nu returnează nimic la succes și o va face die () cu
mesaj de eroare semnificativ la eroare.
COD: Cuvânt cheie
Acest cuvânt cheie este folosit în XSUB-uri mai complicate care necesită o manipulare specială pentru C
funcţie. Variabila RETVAL este încă declarată, dar nu va fi returnată decât dacă este
specificat în secțiunea IEȘIRE:.
Următorul XSUB este pentru o funcție C care necesită o manipulare specială a parametrilor săi.
Utilizarea Perl este dată mai întâi.
$status = rpcb_gettime( "localhost", $timep );
Urmează XSUB.
bool_t
rpcb_gettime(gazdă,timep)
char *gazdă
time_t timep
COD:
RETVAL = rpcb_gettime( gazdă, &timep );
IEȘIRE:
timep
RETVAL
INIT: Cuvânt cheie
Cuvântul cheie INIT: permite inițializarea să fie inserată în XSUB înaintea compilatorului
generează apelul la funcția C. Spre deosebire de cuvântul cheie CODE: de mai sus, acest cuvânt cheie o face
nu afectează modul în care compilatorul gestionează RETVAL.
bool_t
rpcb_gettime(gazdă,timep)
char *gazdă
time_t &timep
INIT:
printf("# Gazda este %s\n", gazda);
IEȘIRE:
timep
O altă utilizare a secțiunii INIT: este de a verifica precondițiile înainte de a efectua un apel către
functia C:
lung lung
lldiv(a,b)
lung lung a
lung lung b
INIT:
dacă (a == 0 && b == 0)
XSRETURN_UNDEF;
dacă (b == 0)
croak("lldiv: nu se poate împărți la 0");
NO_INIT Cuvânt cheie
Cuvântul cheie NO_INIT este folosit pentru a indica faptul că un parametru de funcție este utilizat doar ca un
valoarea de ieșire. The xsubpp compilatorul va genera în mod normal cod pentru a citi valorile tuturor
parametrii funcției din stiva de argumente și atribuiți-i variabilelor C la intrarea în
functia. NO_INIT va spune compilatorului că unii parametri vor fi utilizați pentru ieșire
mai degrabă decât pentru intrare și că acestea vor fi gestionate înainte ca funcția să se încheie.
Următorul exemplu arată o variație a rpcb_gettime() funcţie. Această funcție
folosește variabila timep doar ca variabilă de ieșire și nu-i pasă de inițiala ei
cuprins.
bool_t
rpcb_gettime(gazdă,timep)
char *gazdă
time_t &timep = NO_INIT
IEȘIRE:
timep
TYPEMAP: Cuvânt cheie
Începând cu Perl 5.16, puteți încorpora hărți de tip în codul dvs. XS în loc de sau în
suplimentar la hărți de tip într-un fișier separat. Mai multe astfel de hărți de tip încorporate vor fi
procesate în ordinea apariției în codul XS și ca fișierele locale de tip map
prioritate față de hărțile de tip implicite, hărțile de tipări încorporate pot suprascrie anterioare
definiții ale strofelor TYPEMAP, INPUT și OUTPUT. Sintaxa pentru hărțile de tip încorporate este
TYPEMAP: <
... codul de tip map aici...
AICI
unde cuvântul cheie „TYPEMAP” trebuie să apară în prima coloană a unui rând nou.
Consultați perlxstypemap pentru detalii despre scrierea typemap-urilor.
Inițializare Funcţie parametrii
Parametrii funcției C sunt inițializați în mod normal cu valorile lor din stiva de argumente
(care, la rândul său, conține parametrii care au fost transferați la XSUB din Perl). The
hărțile de tip conțin segmentele de cod care sunt folosite pentru a traduce valorile Perl în C
parametrii. Cu toate acestea, programatorului i se permite să suprascrie hărțile de tip și să furnizeze
cod de inițializare alternativ (sau suplimentar). Codul de inițializare începe cu primul
"=", ";" sau „+” pe o linie din secțiunea INPUT:. Singura excepție se întâmplă dacă acest „;”
termină linia, apoi acest „;” este ignorat în liniște.
Următorul cod demonstrează cum se furnizează codul de inițializare pentru parametrii funcției.
Codul de inițializare este evaluat între ghilimele duble de către compilator înainte de a fi adăugat
la ieșire, deci orice ar trebui interpretat literal [în principal „$”, „@”, sau „\\”]
trebuie protejat cu bare oblice inverse. Variabilele $var, $arg și $type pot fi folosite ca în
hărți de tip.
bool_t
rpcb_gettime(gazdă,timep)
char *gazdă = (char *)SvPV_nolen($arg);
time_t &timep = 0;
IEȘIRE:
timep
Acesta nu ar trebui folosit pentru a furniza valori implicite pentru parametri. Unul ar folosi în mod normal
asta atunci când un parametru de funcție trebuie să fie procesat de o altă funcție de bibliotecă înainte de a putea
fi folosit. Parametrii impliciti sunt tratați în secțiunea următoare.
Dacă inițializarea începe cu „=", atunci este scoasă în declarație pentru intrare
variabilă, înlocuind inițializarea furnizată de typemap. Dacă inițializarea
începe cu ";" sau „+”, apoi se efectuează după ce toate variabilele de intrare au fost
declarat. În ";" în cazul în care inițializarea furnizată în mod normal de hartă de tip nu este
efectuat. Pentru cazul „+”, declarația pentru variabilă va include
inițializare din harta de tip. O variabilă globală, %v, este disponibilă pentru cele cu adevărat rare
cazul în care informațiile de la o inițializare sunt necesare într-o altă inițializare.
Iată un exemplu cu adevărat obscur:
bool_t
rpcb_gettime(gazdă,timep)
time_t &timep; /* \$v{timep}=@{[$v{timep}=$arg]} */
char *gazdă + SvOK($v{timep}) ? SvPV_nolen($arg): NULL;
IEȘIRE:
timep
Construcția „\$v{timep}=@{[$v{timep}=$arg]}” folosită în exemplul de mai sus are un dublu
scop: în primul rând, când această linie este procesată de xsubpp, fragmentul Perl „$v{timep}=$arg”
este evaluat. În al doilea rând, textul fragmentului evaluat este scos în fișierul C generat
fișier (în interiorul unui comentariu C)! În timpul procesării liniei "char *host", $arg va evalua
la ST(0), iar $v{timep} va evalua la ST(1).
Mod implicit Parametru Valori
Valorile implicite pentru argumentele XSUB pot fi specificate prin plasarea unei instrucțiuni de atribuire în
lista de parametri. Valoarea implicită poate fi un număr, un șir sau șir special
„NO_INIT”. Valorile implicite trebuie folosite întotdeauna numai pentru parametrii din dreapta.
Pentru a permite XSUB pentru rpcb_gettime() pentru a avea o valoare implicită a gazdei parametrii la
XSUB ar putea fi rearanjat. XSUB va apela apoi realul rpcb_gettime() funcționează cu
parametrii în ordinea corectă. Acest XSUB poate fi apelat din Perl cu oricare dintre
urmatoarele afirmatii:
$status = rpcb_gettime( $timep, $gazdă);
$status = rpcb_gettime( $timep );
XSUB va arăta ca codul care urmează. Un bloc COD: este folosit pentru a apela
real rpcb_gettime() funcția cu parametrii în ordinea corectă pentru acea funcție.
bool_t
rpcb_gettime(timep,host="localhost")
char *gazdă
time_t timep = NO_INIT
COD:
RETVAL = rpcb_gettime( gazdă, &timep );
IEȘIRE:
timep
RETVAL
PREINIT: Cuvânt cheie
Cuvântul cheie PREINIT: permite ca variabile suplimentare să fie declarate imediat înainte sau după
sunt emise declaraţii ale parametrilor din secţiunea INPUT:.
Dacă o variabilă este declarată în interiorul unei secțiuni CODE: va urma orice cod tip map care este
emis pentru parametrii de intrare. Acest lucru poate duce la sfârșitul declarației după C
cod, care este o eroare de sintaxă C. Erori similare pot apărea cu un tip explicit „;” sau
Se folosește inițializarea parametrilor de tip „+” (vezi „Inițializarea parametrilor funcției”).
Declararea acestor variabile într-o secțiune INIT: nu va ajuta.
În astfel de cazuri, pentru a forța o variabilă suplimentară să fie declarată împreună cu declarații
a altor variabile, plasați declarația într-o secțiune PREINIT:. Cuvântul cheie PREINIT:
poate fi folosit o dată sau de mai multe ori în cadrul unui XSUB.
Următoarele exemple sunt echivalente, dar dacă codul utilizează hărți de tip complexe, atunci
primul exemplu este mai sigur.
bool_t
rpcb_gettime(timep)
time_t timep = NO_INIT
PREINIT:
char *host = "localhost";
COD:
RETVAL = rpcb_gettime( gazdă, &timep );
IEȘIRE:
timep
RETVAL
Pentru acest caz particular, un cuvânt cheie INIT: ar genera același cod C ca și PREINIT:
cuvânt cheie. Un alt exemplu corect, dar predispus la erori:
bool_t
rpcb_gettime(timep)
time_t timep = NO_INIT
COD:
char *host = "localhost";
RETVAL = rpcb_gettime( gazdă, &timep );
IEȘIRE:
timep
RETVAL
O altă modalitate de a declara „gazdă” este să utilizați un bloc C în secțiunea CODE::
bool_t
rpcb_gettime(timep)
time_t timep = NO_INIT
COD:
{
char *host = "localhost";
RETVAL = rpcb_gettime( gazdă, &timep );
}
IEȘIRE:
timep
RETVAL
Capacitatea de a pune declarații suplimentare înainte ca intrările hărții de tip să fie procesate este
foarte util în cazurile în care conversiile typemap manipulează o stare globală:
MyObject
mutare(o)
PREINIT:
MyState st = global_state;
INTRARE:
MyObject o;
CURĂȚĂ:
resetare_la(starea_globală, st);
Aici presupunem că conversia în „MyObject” în secțiunea INPUT: și din MyObject când
procesarea RETVAL va modifica o variabilă globală „global_state”. După aceste conversii
sunt efectuate, restabilim vechea valoare a „global_state” (pentru a evita scurgerile de memorie, pt
exemplu).
Există o altă modalitate de a tranzacționa claritatea pentru compactitate: secțiunile INPUT permit declararea
C variabile care nu apar în lista de parametri a unei subrutine. Astfel cele de mai sus
cod pentru mutare() poate fi rescris ca
MyObject
mutare(o)
MyState st = global_state;
MyObject o;
CURĂȚĂ:
resetare_la(starea_globală, st);
si codul pentru rpcb_gettime() poate fi rescris ca
bool_t
rpcb_gettime(timep)
time_t timep = NO_INIT
char *host = "localhost";
C_ARGS:
gazdă, &timep
IEȘIRE:
timep
RETVAL
DOMENIUL DE APLICARE: Cuvânt cheie
Cuvântul cheie SCOPE: permite activarea domeniului pentru un anumit XSUB. Dacă este activat,
XSUB va invoca automat ENTER și LEAVE.
Pentru a suporta mapări de tip potențial complexe, dacă o intrare tip hartă utilizată de un XSUB conține
un comentariu de genul „/*scope*/”, apoi scoping-ul va fi activat automat pentru acel XSUB.
Pentru a activa domeniul de aplicare:
DOMENIUL DE APLICARE: ACTIVARE
Pentru a dezactiva domeniul de aplicare:
DOMENIUL DE APLICARE: DEZACTIVAT
INTRARE: Cuvânt cheie
Parametrii XSUB sunt de obicei evaluați imediat după introducerea XSUB. The
INPUT: cuvântul cheie poate fi folosit pentru a forța acei parametri să fie evaluați puțin mai târziu. The
INPUT: cuvântul cheie poate fi folosit de mai multe ori într-un XSUB și poate fi folosit pentru a enumera unul sau
mai multe variabile de intrare. Acest cuvânt cheie este folosit împreună cu cuvântul cheie PREINIT:.
Următorul exemplu arată cum parametrul de intrare „timep” poate fi evaluat târziu, după a
PREINIT.
bool_t
rpcb_gettime(gazdă,timep)
char *gazdă
PREINIT:
time_t tt;
INTRARE:
time_t timep
COD:
RETVAL = rpcb_gettime( gazdă, &tt );
timep = tt;
IEȘIRE:
timep
RETVAL
Următorul exemplu arată fiecare parametru de intrare evaluat cu întârziere.
bool_t
rpcb_gettime(gazdă,timep)
PREINIT:
time_t tt;
INTRARE:
char *gazdă
PREINIT:
char *h;
INTRARE:
time_t timep
COD:
h = gazdă;
RETVAL = rpcb_gettime( h, &tt );
timep = tt;
IEȘIRE:
timep
RETVAL
Deoarece secțiunile INPUT permit declararea variabilelor C care nu apar în parametru
lista unei subrutine, aceasta poate fi scurtată la:
bool_t
rpcb_gettime(gazdă,timep)
time_t tt;
char *gazdă;
char *h = gazdă;
time_t timep;
COD:
RETVAL = rpcb_gettime( h, &tt );
timep = tt;
IEȘIRE:
timep
RETVAL
(Ne-am folosit cunoștințele că conversia de intrare pentru „char *” este una „simplu”, deci „gazdă”
este inițializată pe linia de declarație, iar atribuirea noastră „h = gazdă” nu este efectuată
din timp. În caz contrar, ar trebui să aveți atribuirea „h = gazdă” într-un CODE: sau INIT:
secțiune.)
IN/OUTLIST/IN_OUTLIST/OUT/IN_OUT Cuvinte cheie
În lista de parametri pentru un XSUB, se pot precede numele parametrilor de
Cuvinte cheie „IN”/”OUTLIST”/”IN_OUTLIST”/”OUT”/”IN_OUT”. Cuvântul cheie „IN” este implicit
alte cuvinte cheie indică modul în care interfața Perl ar trebui să difere de interfața C.
Parametrii precedați de cuvintele cheie „OUTLIST”/”IN_OUTLIST”/”OUT”/”IN_OUT” sunt considerați a fi
folosit de subrutina C de indicii. Cuvintele cheie „OUTLIST”/„OUT” indică faptul că C
subrutina nu inspectează memoria indicată de acest parametru, ci va scrie
acest indicator pentru a furniza valori suplimentare de returnare.
Parametrii precedați de cuvântul cheie „OUTLIST” nu apar în semnătura de utilizare a
funcția Perl generată.
Parametri precedați de „IN_OUTLIST”/”IN_OUT”/”OUT” do apar ca parametri pentru Perl
funcţie. Cu excepția parametrilor „OUT”, acești parametri sunt convertiți în
tipul C corespunzător, apoi pointerii către aceste date sunt dați ca argumente pentru C
funcţie. Este de așteptat ca funcția C să scrie prin acești pointeri.
Lista de returnare a funcției Perl generată constă din valoarea de returnare C din
funcție (cu excepția cazului în care XSUB este de tipul de returnare „void” sau a fost folosit „Cuvântul cheie NO_OUTPUT”)
urmat de toți parametrii „OUTLIST” și „IN_OUTLIST” (în ordinea apariției).
La întoarcerea de la XSUB, parametrul Perl "IN_OUT"/"OUT" va fi modificat pentru a avea
valori scrise de funcţia C.
De exemplu, un XSUB
anula
day_month(OUTLIST zi, IN unix_time, OUTLIST luna)
zi int
int unix_time
int luna
ar trebui folosit din Perl ca
my ($zi, $lună) = day_month(time);
Semnătura C a funcției corespunzătoare ar trebui să fie
void day_month(int *day, int unix_time, int *month);
Cuvintele cheie "IN"/"OUTLIST"/"IN_OUTLIST"/"IN_OUT"/"OUT" pot fi combinate cu stilul ANSI
declarații, ca în
anula
day_month(OUTLIST int zi, int unix_time, OUTLIST int luna)
(aici cuvântul cheie opțional „IN” este omis).
Parametrii „IN_OUT” sunt identici cu parametrii introduși cu „The & Unary
Operator" și introduse în secțiunea "IEȘIRE:" (vezi "Ieșirea: Cuvânt cheie").
Parametrii „IN_OUTLIST” sunt foarte asemănători, singura diferență fiind că valoarea C
funcția scrie prin pointer nu ar modifica parametrul Perl, ci este introdusă în
lista de ieșiri.
Parametrul „OUTLIST”/„OUT” diferă de parametrii „IN_OUTLIST”/„IN_OUT” numai prin
valoarea inițială a parametrului Perl nu este citită (și nu este dată funcției C
- care primește niște gunoi în schimb). De exemplu, aceeași funcție C ca mai sus poate fi
interfaţat cu ca
void day_month(OUT int zi, int unix_time, OUT int luna);
or
anula
day_month(ziua, ora_unix, luna)
int &day = NO_INIT
int unix_time
int &lună = NO_INIT
IEȘIRE:
zi
lună
Cu toate acestea, funcția Perl generată este numită în stil foarte C-ish:
mea ($zi, $lună);
zi_lună($zi, oră, $lună);
„lungime (NUME)” Cuvânt cheie
Dacă unul dintre argumentele de intrare în funcția C este lungimea unui șir de argument „NUME”,
se poate înlocui numele argumentului de lungime cu „lungime(NUME)” în XSUB
declaraţie. Acest argument trebuie omis când este apelată funcția Perl generată.
De exemplu,
anula
dump_chars(car *s, l scurt)
{
scurt n = 0;
în timp ce (n < l) {
printf("s[%d] = \"\\%#03o\"\n", n, (int)s[n]);
n++;
}
}
MODUL = x PACHET = x
void dump_chars(car *s, lungimi scurte)
ar trebui să fie numit „dump_chars($string)”.
Această directivă este acceptată numai cu declarații de funcție de tip ANSI.
Lungime variabilă Parametru liste
XSUB-urile pot avea liste de parametri cu lungime variabilă, specificând o elipsă „(...)” în
lista de parametri. Această utilizare a punctelor de suspensie este similară cu cea găsită în ANSI C
programatorul este capabil să determine numărul de argumente transmise XSUB prin examinare
variabila „articole” pe care xsubpp consumabile de compilator pentru toate XSUB-urile. Folosind aceasta
mecanism se poate crea un XSUB care acceptă o listă de parametri de lungime necunoscută.
gazdă parametru pentru rpcb_gettime() XSUB poate fi opțional, astfel încât punctele de suspensie pot fi utilizate
pentru a indica faptul că XSUB va prelua un număr variabil de parametri. Perl ar trebui să poată
pentru a apela acest XSUB cu oricare dintre următoarele afirmații.
$status = rpcb_gettime( $timep, $gazdă);
$status = rpcb_gettime( $timep );
Urmează codul XS, cu puncte de suspensie.
bool_t
rpcb_gettime(timep, ...)
time_t timep = NO_INIT
PREINIT:
char *host = "localhost";
COD:
if( elemente > 1 )
gazdă = (char *)SvPV_nolen(ST(1));
RETVAL = rpcb_gettime( gazdă, &timep );
IEȘIRE:
timep
RETVAL
C_ARGS: Cuvânt cheie
Cuvântul cheie C_ARGS: permite crearea de XSUBS care au o secvență de apelare diferită de
Perl decât din C, fără a fi nevoie să scrieți secțiunea CODE: sau PPCODE:. Conținutul
C_ARGS: paragraful este pus ca argument pentru funcția C apelată fără nicio modificare.
De exemplu, să presupunem că o funcție C este declarată ca
simbolic nth_derivative(int n, funcție simbolică, int flags);
și că steaguri implicite sunt păstrate într-o variabilă globală C „default_flags”. Să presupunem că
doriți să creați o interfață care se numește ca
$second_deriv = $funcție->a n-a_derivată(2);
Pentru a face acest lucru, declarați XSUB ca
simbolic
nth_derivative(funcție, n)
funcţie simbolică
int n
C_ARGS:
n, function, default_flags
PPCODE: Cuvânt cheie
Cuvântul cheie PPCODE: este o formă alternativă a cuvântului cheie CODE: și este folosit pentru a spune
xsubpp compilator pe care programatorul furnizează codul pentru a controla stiva de argumente
pentru valorile returnate de XSUB. Ocazional, cineva va dori ca un XSUB să returneze o listă de
valori mai degrabă decât o singură valoare. În aceste cazuri, trebuie să utilizați PPCODE: și apoi
împingeți în mod explicit lista de valori din stivă. Cuvintele cheie PPCODE: și CODE: ar trebui
nu pot fi utilizate împreună în cadrul aceluiași XSUB.
Diferența reală dintre secțiunile PPCODE: și CODE: este în inițializarea "SP"
macro (care înseamnă curent indicatorul stivei Perl), și în manipularea datelor pe
stiva la întoarcerea de la un XSUB. În COD: secțiunile SP păstrează valoarea care a fost
la intrarea în XSUB: SP este pe indicatorul funcției (care urmează ultimul parametru).
În PPCODE: secțiunile SP sunt mutate înapoi la începutul listei de parametri, care
permite macrocomenzilor „PUSH*()” să plaseze valorile de ieșire în locul în care Perl se așteaptă ca acestea să fie când
XSUB revine înapoi la Perl.
Trailerul generat pentru o secțiune CODE: asigură că numărul de valori returnate Perl
va vedea este fie 0, fie 1 (în funcție de „nul” al valorii de returnare a C
funcția și euristicile menționate în „Variabila RETVAL”). Trailerul generat pentru a
PPCODE: secțiunea se bazează pe numărul de valori returnate și pe numărul de ori „SP”
a fost actualizat de macrocomenzile „[X]PUSH*()”.
Rețineți că macrocomenzile ST(i), „XST_m*()” și „XSRETURN*()” funcționează la fel de bine în secțiunile CODE:
și PPCODE: secțiuni.
Următorul XSUB va apela C rpcb_gettime() funcția și va returna cele două ieșiri ale sale
valori, timp și stare, la Perl ca o singură listă.
anula
rpcb_gettime(gazdă)
char *gazdă
PREINIT:
time_t timep;
stare bool_t;
PPCODE:
status = rpcb_gettime( gazdă, &timep );
EXTINDERE(SP, 2);
PUSH-uri(sv_2mortal(newSViv(status)));
PUSH-uri(sv_2mortal(newSViv(timep)));
Observați că programatorul trebuie să furnizeze codul C necesar pentru a avea realul
rpcb_gettime() funcția apelată și pentru a avea valorile returnate plasate corect pe
stiva de argumente.
Tipul de returnare „void” pentru această funcție îi spune xsubpp compilator care RETVAL
variabilă nu este necesară sau utilizată și că nu trebuie creată. În majoritatea scenariilor,
tipul de returnare void ar trebui utilizat cu directiva PPCODE:.
EXTINDE() macro este folosită pentru a face loc pe stiva de argumente pentru 2 valori returnate. The
PPCODE: directiva provoacă xsubpp compilator pentru a crea un pointer de stivă disponibil ca „SP”,
și acest indicator este folosit în EXTINDE() macro. Valorile sunt atunci
împins pe stivă cu împinge () macro.
Acum rpcb_gettime() funcția poate fi folosită din Perl cu următoarea instrucțiune.
($status, $timep) = rpcb_gettime("localhost");
Când manipulați parametrii de ieșire cu o secțiune PPCODE, asigurați-vă că gestionați magia „setată”.
în mod corespunzător. Consultați perlguts pentru detalii despre magia „setată”.
Revenind Nedef Și Gol liste
Ocazional, programatorul va dori să returneze pur și simplu „undef” sau o listă goală dacă a
funcția eșuează mai degrabă decât o valoare de stare separată. The rpcb_gettime() oferte de funcții
tocmai aceasta situatie. Dacă funcția reușește, am dori să returnăm ora
iar dacă eșuează, am dori să ne întoarcem undef. În următorul cod Perl,
valoarea $timep va fi fie undef, fie va fi un timp valid.
$timep = rpcb_gettime( "localhost" );
Următorul XSUB utilizează tipul de returnare „SV *” doar ca mnemonic și folosește un bloc CODE:
pentru a indica compilatorului că programatorul a furnizat tot codul necesar. The
sv_newmortal() call va inițializa valoarea returnată la undef, făcând ca implicită
valoare returnată.
SV *
rpcb_gettime(gazdă)
char * gazdă
PREINIT:
time_t timep;
bool_t x;
COD:
ST(0) = sv_newmortal();
if(rpcb_gettime(gazdă, &timep))
sv_setnv( ST(0), timp (dublu);
Următorul exemplu demonstrează cum s-ar plasa un undef explicit în valoarea returnată,
dacă apare necesitatea.
SV *
rpcb_gettime(gazdă)
char * gazdă
PREINIT:
time_t timep;
bool_t x;
COD:
if( rpcb_gettime(gazdă, &timep ) ){
ST(0) = sv_newmortal();
sv_setnv( ST(0), timp (dublu);
}
altceva {
ST(0) = &PL_sv_undef;
}
Pentru a returna o listă goală, trebuie să utilizați un bloc PPCODE: și apoi să nu împingeți valorile returnate
stiva.
anula
rpcb_gettime(gazdă)
char *gazdă
PREINIT:
time_t timep;
PPCODE:
if(rpcb_gettime(gazdă, &timep))
PUSH-uri(sv_2mortal(newSViv(timep)));
altceva {
/* Nimic împins pe stivă, deci un gol
* lista este returnată implicit. */
}
Unii oameni pot fi înclinați să includă o „întoarcere” explicită în XSUB de mai sus, mai degrabă decât
lăsând controlul să cadă până la capăt. În acele situații, „XSRETURN_EMPTY” ar trebui să fie
folosit, în schimb. Acest lucru va asigura că stiva XSUB este reglată corect. Consulta
perlapi pentru alte macrocomenzi „XSRETURN”.
Deoarece macrocomenzile „XSRETURN_*” pot fi utilizate și cu blocurile CODE, se poate rescrie acest lucru
exemplu ca:
int
rpcb_gettime(gazdă)
char *gazdă
PREINIT:
time_t timep;
COD:
RETVAL = rpcb_gettime( gazdă, &timep );
dacă (RETVAL == 0)
XSRETURN_UNDEF;
IEȘIRE:
RETVAL
De fapt, se poate pune această verificare și într-o secțiune POSTCALL:. Împreună cu PREINIT:
simplificări, aceasta duce la:
int
rpcb_gettime(gazdă)
char *gazdă
time_t timep;
APEL POSTAL:
dacă (RETVAL == 0)
XSRETURN_UNDEF;
NECESIT: Cuvânt cheie
Cuvântul cheie REQUIRE: este folosit pentru a indica versiunea minimă a fișierului xsubpp este necesar un compilator
pentru a compila modulul XS. Un modul XS care conține următoarea declarație va
compila numai cu xsubpp versiunea 1.922 sau mai mare:
NECESIT: 1.922
CURĂȚĂ: Cuvânt cheie
Acest cuvânt cheie poate fi folosit atunci când un XSUB necesită proceduri speciale de curățare înaintea acestuia
încetează. Când este folosit cuvântul cheie CLEANUP:, acesta trebuie să urmeze orice CODE: sau OUTPUT:
blocuri care sunt prezente în XSUB. Codul specificat pentru blocul de curățare va fi
adăugat ca ultimele declarații în XSUB.
APEL POSTAL: Cuvânt cheie
Acest cuvânt cheie poate fi folosit atunci când un XSUB necesită proceduri speciale executate după C
se efectuează apelul subrutinei. Când este utilizat cuvântul cheie POSTCALL:, acesta trebuie să precedă OUTPUT:
și CLEANUP: blocuri care sunt prezente în XSUB.
Vedeți exemple în „Cuvântul cheie NO_OUTPUT” și „Returnarea listelor undef și goale”.
Blocul POSTCALL: nu are prea mult sens atunci când apelul subrutinei C este furnizat de
utilizator prin furnizarea fie a secțiunii CODE: fie PPCODE:.
BOOT: Cuvânt cheie
Cuvântul cheie BOOT: este folosit pentru a adăuga cod la funcția de bootstrap a extensiei. The
Funcția bootstrap este generată de xsubpp compilator și deține în mod normal instrucțiunile
necesar pentru a înregistra orice XSUB-uri cu Perl. Cu cuvântul cheie BOOT: programatorul poate spune
compilatorul pentru a adăuga instrucțiuni suplimentare la funcția de bootstrap.
Acest cuvânt cheie poate fi folosit oricând după primul cuvânt cheie MODULE și ar trebui să apară pe a
linie de la sine. Prima linie goală după cuvântul cheie va termina blocul de cod.
BOOT:
# Următorul mesaj va fi tipărit atunci când
# se execută funcția bootstrap.
printf("Bună ziua de la bootstrap!\n");
VERIFICARE VERSIUNE: Cuvânt cheie
Cuvântul cheie VERSIONCHECK: îi corespunde xsubpp„-versioncheck” și „-noversioncheck” ale lui
Opțiuni. Acest cuvânt cheie suprascrie opțiunile liniei de comandă. Verificarea versiunii este activată de
Mod implicit. Când verificarea versiunii este activată, modulul XS va încerca să verifice dacă este activată
versiunea se potrivește cu versiunea modulului PM.
Pentru a activa verificarea versiunii:
VERIFICARE VERSIUNE: ACTIVARE
Pentru a dezactiva verificarea versiunii:
VERIFICARE VERSIUNE: DEZACTIVAT
Rețineți că, dacă versiunea modulului PM este un NV (un număr în virgulă mobilă), va fi
încordat cu o posibilă pierdere de precizie (în prezent, tăiat la nouă zecimale)
astfel încât să nu se mai potrivească cu versiunea modulului XS. Citând $VERSION
se recomandă declarația pentru a-l transforma într-un șir dacă sunt folosite numere lungi de versiune.
PROTOTIPURI: Cuvânt cheie
Cuvântul cheie PROTOTYPES: îi corespunde xsubppOpțiunile „-prototypes” și „-noprototypes” ale lui.
Acest cuvânt cheie suprascrie opțiunile liniei de comandă. Prototipurile sunt activate implicit. Când
prototipurile sunt activate. XSUB-urilor li se vor da prototipuri Perl. Acest cuvânt cheie poate fi folosit
de mai multe ori într-un modul XS pentru a activa și dezactiva prototipurile pentru diferite părți ale
modul.
Pentru a activa prototipurile:
PROTOTIPURI: ACTIVARE
Pentru a dezactiva prototipurile:
PROTOTIPURI: DEZACTIVATĂ
PROTOTIP: Cuvânt cheie
Acest cuvânt cheie este similar cu cuvântul cheie PROTOTYPES: de mai sus, dar poate fi folosit pentru a forța xsubpp
pentru a utiliza un prototip specific pentru XSUB. Acest cuvânt cheie înlocuiește orice alt prototip
opțiuni și cuvinte cheie, dar afectează numai XSUB curent. Consultați „Prototipuri” în perlsub
pentru informații despre prototipurile Perl.
bool_t
rpcb_gettime(timep, ...)
time_t timep = NO_INIT
PROTOTIP: $;$
PREINIT:
char *host = "localhost";
COD:
if( elemente > 1 )
gazdă = (char *)SvPV_nolen(ST(1));
RETVAL = rpcb_gettime( gazdă, &timep );
IEȘIRE:
timep
RETVAL
Dacă prototipurile sunt activate, îl puteți dezactiva local pentru un anumit XSUB, ca în
următorul exemplu:
anula
rpcb_gettime_noproto()
PROTOTIP: DEZACTIVAT
...
A.K.A: Cuvânt cheie
Cuvântul cheie ALIAS: permite unui XSUB să aibă două sau mai multe nume unice Perl și să știe care
dintre aceste nume a fost folosit când a fost invocat. Numele Perl pot fi complet calificate cu
nume de pachete. Fiecare alias primește un index. Compilatorul va configura o variabilă numită
„ix” care conțin indexul alias-ului care a fost folosit. Când XSUB este apelat cu
numele său declarat „ix” va fi 0.
Următorul exemplu va crea aliasuri „FOO::gettime()” și „BAR::getit()” pentru aceasta
Funcția.
bool_t
rpcb_gettime(gazdă,timep)
char *gazdă
time_t &timep
A.K.A:
FOO::gettime = 1
BAR::getit = 2
INIT:
printf("# ix = %d\n", ix);
IEȘIRE:
timep
SUPRAÎNCĂRCARE: Cuvânt cheie
În loc să scrieți o interfață supraîncărcată folosind Perl pur, puteți folosi și OVERLOAD
cuvânt cheie pentru a defini nume suplimentare Perl pentru funcțiile dvs. (cum ar fi cuvântul cheie ALIAS:
de mai sus). Cu toate acestea, funcțiile supraîncărcate trebuie definite cu trei parametri (cu excepția
pentru nometoda() funcție care necesită patru parametri). Dacă vreo funcție are
OVERLOAD: cuvânt cheie, mai multe linii suplimentare vor fi definite în fișierul c generat de
xsubpp pentru a vă înregistra cu magia supraîncărcării.
Deoarece obiectele binecuvântate sunt de fapt stocate ca RV-uri, este util să folosiți hărțile de tip
caracteristici pentru a preprocesa parametrii și a extrage SV-ul real stocat în binecuvântatul RV.
Vedeți mai jos exemplul pentru T_PTROBJ_SPECIAL.
Pentru a utiliza cuvântul cheie OVERLOAD:, creați o funcție XS care necesită trei parametri de intrare (
sau folosiți definiția stilului c „...” astfel:
SV *
cmp (lobj, robj, swap)
My_Module_obj lobj
My_Module_obj robj
Schimb IV
SUPRAÎNCĂRCARE: cmp <=>
{ /* funcția definită aici */}
În acest caz, funcția va supraîncărca ambii operatori de comparație cu trei căi. Pentru
toate operațiunile de supraîncărcare folosind caractere non-alfa, trebuie să tastați parametrul fără
citarea, separarea supraîncărcărilor multiple cu spații albe. Rețineți că „” (stringify
supraîncărcare) ar trebui introdusă ca \"\" (adică escape).
DA ÎNAPOI: Cuvânt cheie
În plus față de cuvântul cheie OVERLOAD, dacă trebuie să controlați modul în care Perl generează automat lipsă
operatori supraîncărcați, puteți seta cuvântul cheie FALLBACK în secțiunea antetului modulului, cum ar fi
acest:
MODUL = RPC PACHET = RPC
FALLBACK: ADEVĂRAT
...
unde FALLBACK poate lua oricare dintre cele trei valori TRUE, FALSE sau UNDEF. Dacă nu setați
orice valoare FALLBACK când se utilizează OVERLOAD, este implicit UNDEF. FALLBACK nu este folosit decât
când au fost definite una sau mai multe funcții care utilizează OVERLOAD. Vă rugăm să vedeți „de rezervă” în
supraîncărcare pentru mai multe detalii.
INTERFATA: Cuvânt cheie
Acest cuvânt cheie declară XSUB curent ca deținător al semnăturii de apelare dată. Dacă
un text urmează acest cuvânt cheie, este considerat o listă de funcții care au acest lucru
semnătură și ar trebui să fie atașat la XSUB curent.
De exemplu, dacă aveți 4 funcții C multiplica(), divide(), adăuga(), scădea() toate având
semnatura:
simbolic f(simbolic, simbolic);
le puteți face pe toate să folosească același XSUB folosind asta:
simbolic
interface_s_ss(arg1, arg2)
simbolic arg1
simbolic arg2
INTERFATA:
înmulțiți împărțiți
adăugați scădeți
(Acesta este codul XSUB complet pentru 4 funcții Perl!) Patru funcții Perl generate
nume cu funcții C corespunzătoare.
Avantajul acestei abordări în comparație cu ALIAS: cuvânt cheie este că nu este nevoie
codificați o instrucțiune switch, fiecare funcție Perl (care împărtășește același XSUB) știe care C
funcția pe care ar trebui să o apeleze. În plus, se poate atașa o funcție suplimentară rest() at
runtime prin utilizarea
CV *mycv = newXSproto("Simbolic::restul",
XS_Symbolic_interface_s_ss, __FILE__, "$$");
XSINTERFACE_FUNC_SET(mycv, rest);
să zicem, de la un alt XSUB. (Acest exemplu presupune că nu a existat INTERFACE_MACRO:
secțiunea, altfel trebuie să folosiți altceva în loc de „XSINTERFACE_FUNC_SET”, vezi
secțiunea următoare.)
INTERFACE_MACRO: Cuvânt cheie
Acest cuvânt cheie permite definirea unei INTERFACE folosind un alt mod de extragere a unei funcții
pointer de la un XSUB. Textul care urmează acestui cuvânt cheie ar trebui să dea numele macrocomenzilor
care ar extrage/setare un indicator de funcție. Macrocomenzii extractoare primesc un tip de returnare,
„CV*” și „XSANY.any_dptr” pentru acest „CV*”. Macro-ului setter i se dă cv, iar
indicatorul funcției.
Valoarea implicită este „XSINTERFACE_FUNC” și „XSINTERFACE_FUNC_SET”. Un cuvânt cheie INTERFACE
cu o listă goală de funcții poate fi omis dacă se folosește cuvântul cheie INTERFACE_MACRO.
Să presupunem că în exemplul anterior funcţionează pointerii pentru multiplica(), divide(), adăuga(),
scădea() sunt păstrate într-o matrice C globală „fp[]” cu decalajele fiind „multiply_off”,
„divide_off”, „add_off”, „subtract_off”. Apoi se poate folosi
#define XSINTERFACE_FUNC_BYOFFSET(ret,cv,f) \
((XSINTERFACE_CVT_ANON(ret))fp[CvXSUBANY(cv).any_i32])
#define XSINTERFACE_FUNC_BYOFFSET_set(cv,f) \
CvXSUBANY(cv).any_i32 = CAT2( f, _off )
în secțiunea C,
simbolic
interface_s_ss(arg1, arg2)
simbolic arg1
simbolic arg2
INTERFACE_MACRO:
XSINTERFACE_FUNC_BYOFFSET
XSINTERFACE_FUNC_BYOFFSET_set
INTERFATA:
înmulțiți împărțiți
adăugați scădeți
în secțiunea XSUB.
INCLUDE: Cuvânt cheie
Acest cuvânt cheie poate fi folosit pentru a trage alte fișiere în modulul XS. Celelalte fișiere pot avea
cod XS. INCLUDE: poate fi folosit și pentru a rula o comandă pentru a genera codul XS care trebuie extras
în modul.
Fișierul Rpcb1.xsh conține funcția noastră „rpcb_gettime()”:
bool_t
rpcb_gettime(gazdă,timep)
char *gazdă
time_t &timep
IEȘIRE:
timep
Modulul XS poate folosi INCLUDE: pentru a trage acel fișier în el.
INCLUDE: Rpcb1.xsh
Dacă parametrii cuvântului cheie INCLUDE: sunt urmați de un pipe ("|"), atunci compilatorul
va interpreta parametrii ca o comandă. Această caracteristică este ușor depreciată în favoarea
directiva „INCLUDE_COMMAND:”, după cum este documentat mai jos.
INCLUDE: cat Rpcb1.xsh |
Nu utilizați acest lucru pentru a rula perl: "INCLUDE: perl |" va rula perl care se întâmplă să fie
primul pe calea ta și nu neapărat același perl care este folosit pentru a rula „xsubpp”. Vedea
„The INCLUDE_COMMAND: Keyword”.
INCLUDE_COMMAND: Cuvânt cheie
Rulează comanda furnizată și include rezultatul acesteia în documentul XS curent.
„INCLUDE_COMMAND” atribuie o semnificație specială jetonului $^X prin faptul că rulează același perl
interpret care rulează „xsubpp”:
INCLUDE_COMMAND: cat Rpcb1.xsh
INCLUDE_COMMAND: $^X -e...
CAZ: Cuvânt cheie
Cuvântul cheie CASE: permite unui XSUB să aibă mai multe părți distincte, fiecare parte acționând ca
un XSUB virtual. CAZ: este lacom și dacă este folosit, atunci toate celelalte cuvinte cheie XS trebuie să fie
cuprinse într-un CAZ:. Aceasta înseamnă că nimic nu poate precede primul CAZ: în XSUB și
orice care urmează ultimul CAZ: este inclus în acel caz.
UN CAZ: ar putea comuta printr-un parametru al XSUB, prin intermediul „ix” ALIAS: variabila (vezi „
ALIAS: Cuvânt cheie"), sau poate prin variabila „articole” (consultați „Parametrul de lungime variabilă
Liste"). Ultimul CAZ: devine cel lipsă caz dacă nu este asociat cu a
condiţional. Următorul exemplu arată CASE comutat prin „ix” cu o funcție
„rpcb_gettime()” având un alias „x_gettime()”. Când funcția este numită ca
„rpcb_gettime()” parametrii săi sunt obișnuiți „(char *gazdă, time_t *timep)”, dar când
funcția este numită „x_gettime()” parametrii săi sunt inversați, „(time_t *timep, char
*gazdă)".
lung
rpcb_gettime(a,b)
CAZ: ix == 1
A.K.A:
x_gettime = 1
INTRARE:
# „a” este timep, „b” este gazdă
char *b
time_t a = NO_INIT
COD:
RETVAL = rpcb_gettime( b, &a );
IEȘIRE:
a
RETVAL
CAZ:
# „a” este gazdă, „b” este timep
char *a
time_t &b = NO_INIT
IEȘIRE:
b
RETVAL
Această funcție poate fi apelată cu oricare dintre următoarele afirmații. Observați diferit
liste de argumente.
$status = rpcb_gettime( $gazdă, $timep );
$status = x_gettime( $timep, $gazdă);
EXPORT_XSUB_SYMBOLS: Cuvânt cheie
Cuvântul cheie EXPORT_XSUB_SYMBOLS: este probabil ceva de care nu veți avea nevoie niciodată. În perl
versiuni anterioare 5.16.0, acest cuvânt cheie nu face nimic. Începând cu 5.16, simboluri XSUB
nu mai sunt exportate implicit. Adică sunt funcții „statice”. Dacă includeți
EXPORT_XSUB_SYMBOLS: ACTIVARE
în codul dvs. XS, XSUB-urile care urmează această linie nu vor fi declarate „statice”. Puteți
mai târziu dezactivați acest lucru cu
EXPORT_XSUB_SYMBOLS: DEZACTIVAT
care, din nou, este implicit pe care probabil nu ar trebui să o modificați niciodată. Nu poți folosi asta
cuvânt cheie pe versiunile de perl înainte de 5.16 pentru a face XSUB-urile „statice”.
& Unar Operator
Operatorul unar „&” din secțiunea INPUT: este folosit pentru a spune xsubpp că ar trebui să se convertească
o valoare Perl către/de la C folosind tipul C din stânga lui „&”, dar furnizați un pointer către aceasta
valoare atunci când funcția C este apelată.
Acest lucru este util pentru a evita un bloc CODE: pentru o funcție C care preia un parametru de
referinţă. De obicei, parametrul nu ar trebui să fie de tip pointer (un „int” sau „long”, dar
nu un „int*” sau „long*”).
Următorul XSUB va genera cod C incorect. The xsubpp compilatorul va transforma acest lucru
în cod care apelează „rpcb_gettime()” cu parametrii „(char *host, time_t timep)”, dar
adevăratul „rpcb_gettime()” dorește ca parametrul „timep” să fie de tip „time_t*” și nu
„timp_t”.
bool_t
rpcb_gettime(gazdă,timep)
char *gazdă
time_t timep
IEȘIRE:
timep
Această problemă este corectată utilizând operatorul „&”. The xsubpp compilatorul se va transforma acum
aceasta în codul care apelează corect „rpcb_gettime()” cu parametrii „(char *host, time_t
*timep)". Face acest lucru prin trecerea "&" prin intermediul, astfel încât apelul funcției arată ca
„rpcb_gettime(gazdă, &timep)”.
bool_t
rpcb_gettime(gazdă,timep)
char *gazdă
time_t &timep
IEȘIRE:
timep
Se introduce POD, Comentarii si C Preprocesor Directivele
Directivele de preprocesor C sunt permise în BOOT:, PREINIT: INIT:, CODE:, PPCODE:,
POSTCALL: și CLEANUP: blocuri, precum și în afara funcțiilor. Comentariile sunt permise
oriunde după cuvântul cheie MODULE. Compilatorul va transmite directivele preprocesorului
prin neatins și va elimina rândurile comentate. Documentația POD este permisă oricând
punct, atât în secțiunile de limbaj C și XS. POD-ul trebuie terminat cu „=cut”
comanda; „xsubpp” va ieși cu o eroare dacă nu o face. Este foarte puțin probabil ca omul
codul C generat va fi confundat cu POD, deoarece majoritatea stilurilor de indentare au ca rezultat spații albe
în fața oricărei linii care începe cu „=". Fișierele XS generate de mașină pot cădea în această capcană
cu excepția cazului în care se acordă grijă ca un spațiu rupe secvența „\n=".
Comentariile pot fi adăugate la XSUB plasând un „#” ca primul non-spațiu alb al unei linii.
Trebuie avut grijă pentru a evita ca comentariul să arate ca o directivă de preprocesor C,
ca să nu fie interpretat ca atare. Cel mai simplu mod de a preveni acest lucru este să puneți spații albe
fața „#”.
Dacă utilizați directive de preprocesor pentru a alege una dintre cele două versiuni ale unei funcții, utilizați
#dacă ... versiunea 1
#else /* ... versiunea 2 */
#endif
si nu
#dacă ... versiunea 1
#endif
#dacă ... versiunea 2
#endif
pentru că altfel xsubpp va crede că ați făcut o definiție duplicată a
funcţie. De asemenea, puneți o linie goală înainte de #else/#endif, astfel încât să nu fie văzută ca parte
a corpului functional.
Utilizarea XS cu C ++
Dacă un nume XSUB conține „::”, acesta este considerat o metodă C++. Perl generat
funcția va presupune că primul său argument este un indicator de obiect. Indicatorul obiectului
va fi stocat într-o variabilă numită ACEST. Obiectul ar fi trebuit creat de C++ cu
il nou() funcția și ar trebui să fie binecuvântat de Perl cu sv_setref_pv() macro. The
binecuvântarea obiectului de către Perl poate fi gestionată de o hartă de tip. Este afișat un exemplu de hartă a tipurilor
la sfârşitul acestei secţiuni.
Dacă tipul de returnare al XSUB include „static”, metoda este considerată a fi statică
metodă. Va apela funcția C++ folosind clasa::metoda() sintaxă. Dacă metoda este
nu este static, funcția va fi apelată folosind THIS->metodă() sintaxă.
Următoarele exemple vor folosi următoarea clasă C++.
culoarea clasei {
public:
culoare();
~culoare();
int albastru();
void set_blue( int );
privat:
int c_blue;
};
XSUB-urile pentru albastru() si set_blue() metodele sunt definite cu numele clasei dar
parametrul pentru obiect (THIS, sau „self”) este implicit și nu este listat.
int
Culoarea albastra()
anula
culoare::set_blue(val)
int val
Ambele funcții Perl vor aștepta un obiect ca prim parametru. În C++ generat
codează obiectul se numește „THIS”, iar apelul de metodă va fi efectuat pe acest obiect.
Deci, în codul C++ albastru() si set_blue() metodele vor fi numite astfel:
RETVAL = ACEST->albastru();
ACEST->set_blue( val );
De asemenea, puteți scrie o singură metodă get/set folosind un argument opțional:
int
culoare::albastru (val = NO_INIT)
int val
PROTOTIP $;$
COD:
dacă (articole > 1)
ACEST->set_blue( val );
RETVAL = ACEST->albastru();
IEȘIRE:
RETVAL
Dacă numele funcției este DISTRUGE atunci funcția C++ „Șterge” va fi apelată și „ACESTA”
va fi dat ca parametru. Codul C++ generat pentru
anula
culoare::DISTRUGERE()
va arata asa:
culoare *ACESTA = ...; // Inițializat ca în typemap
șterge asta;
Dacă numele funcției este nou apoi funcția „nouă” C++ va fi apelată pentru a crea un
obiect C++ dinamic. XSUB va aștepta numele clasei, care va fi păstrat într-o variabilă
numită „CLASS”, pentru a fi dat ca prim argument.
culoare *
culoare::nou()
Codul C++ generat va apela „nou”.
RETVAL = culoare nouă();
Următorul este un exemplu de hartă de tipuri care ar putea fi folosită pentru acest exemplu C++.
TYPEMAP
culoare * O_OBJECT
REZULTATE
# Obiectul Perl este binecuvântat în „CLASS”, care ar trebui să fie a
# char* având numele pachetului pentru binecuvântare.
O_OBJECT
sv_setref_pv( $arg, CLASS, (void*)$var );
INTRARE
O_OBJECT
if( sv_isobject($arg) && (SvTYPE(SvRV($arg)) == SVt_PVMG) )
$var = ($tip)SvIV((SV*)SvRV( $arg ));
altceva {
warn("${Pachet}::$func_name() -- " .
„$var nu este o referință SV binecuvântată”);
XSRETURN_UNDEF;
}
interfaţă Strategie
Când proiectați o interfață între Perl și o bibliotecă C, o traducere directă din C în
XS (cum ar fi creat de „h2xs -x”) este adesea suficient. Cu toate acestea, uneori interfața
va arăta foarte asemănător C și uneori neintuitiv, mai ales când funcția C
modifică unul dintre parametrii săi sau returnează eșec în bandă (ca în „valori returnate negative
mean failure"). În cazurile în care programatorul dorește să creeze o interfață mai asemănătoare Perl
următoarea strategie poate ajuta la identificarea părților mai critice ale interfeței.
Identificați funcțiile C cu parametrii de intrare/ieșire sau de ieșire. XSUB-urile pentru acestea
funcțiile pot fi capabile să returneze liste la Perl.
Identificați funcțiile C care folosesc unele informații în bandă ca un indiciu al eșecului. Ar putea
fii candidați pentru a returna undef sau o listă goală în caz de eșec. Dacă eșecul poate fi
detectat fără un apel la funcția C, poate doriți să utilizați o secțiune INIT: pentru a raporta
esecul. Pentru eșecurile detectabile după revenirea funcției C, se poate folosi a
POSTCALL: secțiune pentru a procesa eșecul. În cazuri mai complicate utilizați CODE: sau PPCODE:
secțiuni.
Dacă multe funcții folosesc aceeași indicație de eșec bazată pe valoarea returnată, poate doriți
pentru a crea un typedef special pentru a face față acestei situații. A pune
typedef int negative_is_failure;
aproape de începutul fișierului XS și creați o intrare de tip OUTPUT pentru
„negative_is_failure” care convertește valorile negative în „undef”, sau poate cârâit()s. După
aceasta valoarea returnată de tipul „negative_is_failure” va crea mai multă interfață asemănătoare Perl.
Identificați ce valori sunt folosite doar de funcțiile C și XSUB în sine, de exemplu, când a
parametrul unei funcții ar trebui să fie conținutul unei variabile globale. Dacă Perl nu are nevoie
pentru a accesa conținutul valorii, atunci s-ar putea să nu fie necesară furnizarea unei traduceri
pentru acea valoare de la C la Perl.
Identificați pointerii din listele de parametri ai funcției C și valorile returnate. Câteva indicații
pot fi folosite pentru a implementa parametrii de intrare/ieșire sau de ieșire, aceștia pot fi gestionați în XS cu
operatorul unar „&” și, eventual, folosind cuvântul cheie NO_INIT. Unii o vor face
necesită manipularea unor tipuri precum „int *”, și trebuie să decideți ce Perl este util
traducerea va face într-un astfel de caz. Când semantica este clară, este indicat să se pună
traducerea într-un fișier typemap.
Identificați structurile utilizate de funcțiile C. În multe cazuri, poate fi util de utilizat
harta de tip T_PTROBJ pentru aceste structuri, astfel încât acestea să poată fi manipulate de Perl ca binecuvântate
obiecte. (Acest lucru este gestionat automat de „h2xs -x”.)
Dacă același tip C este utilizat în mai multe contexte diferite care necesită diferite
traduceri, „typedef” mai multe tipuri noi mapate la acest tip C și creați separat
typemap intrări pentru aceste noi tipuri. Utilizați aceste tipuri în declarațiile de tip returnare și
parametrii la XSUB-uri.
Perl Obiecte Și C Structuri
Când aveți de-a face cu structurile C, ar trebui să selectați oricare T_PTROBJ or T_PTRREF pentru XS
tip. Ambele tipuri sunt concepute pentru a gestiona pointerii către obiecte complexe. Tipul T_PTRREF
va permite obiectului Perl să nu fie binecuvântat în timp ce tipul T_PTROBJ necesită ca
obiect să fie binecuvântat. Folosind T_PTROBJ se poate realiza o formă de verificare de tip, deoarece
XSUB va încerca să verifice dacă obiectul Perl este de tipul așteptat.
Următorul cod XS arată getnetconfigent() funcție care este utilizată cu ONC+ TIRPC.
getnetconfigent() funcția va returna un pointer către o structură C și are C
prototipul prezentat mai jos. Exemplul va demonstra cum pointerul C va deveni Perl
referinţă. Perl va considera această referință ca fiind un indicator către un obiect binecuvântat și va
încercați să apelați un destructor pentru obiect. Un destructor va fi furnizat în XS
sursă pentru a elibera memoria folosită de getnetconfigent(). Destructorii în XS pot fi creați de
specificând o funcție XSUB al cărei nume se termină cu cuvântul DISTRUGE. Destructorii XS pot fi
folosit pentru a elibera memoria care ar fi putut fi blocată de un alt XSUB.
struct netconfig *getnetconfigent(const char *netid);
Un „typedef” va fi creat pentru „struct netconfig”. Obiectul Perl va fi binecuvântat într-un
clasă care se potrivește cu numele tipului C, cu eticheta „Ptr” atașată, iar numele ar trebui
nu au spații încorporate dacă va fi un nume de pachet Perl. Destructorul va fi plasat
într-o clasă corespunzătoare clasei obiectului și cuvântul cheie PREFIX va fi folosit pentru
tăiați numele cu cuvântul DISTRUGERE așa cum se va aștepta Perl.
typedef struct netconfig Netconfig;
MODUL = RPC PACHET = RPC
Netconfig *
getnetconfigent(netid)
char *netid
MODUL = PACHET RPC = PREFIX NetconfigPtr = rpcb_
anula
rpcb_DESTROY(netconf)
Netconfig *netconf
COD:
printf("Acum în NetconfigPtr::DESTROY\n");
gratuit( netconf );
Acest exemplu necesită următoarea intrare typemap. Consultați perlxstypemap pentru mai multe
informații despre adăugarea de noi hărți de tip pentru o extensie.
TYPEMAP
Netconfig * T_PTROBJ
Acest exemplu va fi folosit cu următoarele instrucțiuni Perl.
utilizați RPC;
$netconf = getnetconfigent("udp");
Când Perl distruge obiectul la care face referire $netconf, acesta va trimite obiectul către
funcția XSUB DETROY furnizată. Perl nu poate determina, și nu-i pasă, că acest lucru
obiectul este o structură C și nu un obiect Perl. În acest sens, nu există nicio diferență între
obiectul creat de getnetconfigent() XSUB și un obiect creat de un Perl normal
subrutină.
În condiții de siguranță depozitarea Static Date in XS
Începând cu Perl 5.8, a fost definit un cadru macro pentru a permite date statice
stocate în siguranță în module XS care vor fi accesate dintr-un Perl multi-threaded.
Deși concepute în primul rând pentru a fi utilizate cu Perl multi-threaded, macrocomenzile au fost
concepute astfel încât să funcționeze și cu Perl non-threaded.
Prin urmare, este recomandat ca aceste macrocomenzi să fie utilizate de toate modulele XS care fac
utilizarea datelor statice.
Cel mai simplu mod de a obține un set șablon de macrocomenzi de utilizat este prin specificarea „-g”
opțiunea ("--global") cu h2xs (vezi h2xs).
Mai jos este un exemplu de modul care utilizează macrocomenzi.
#define PERL_NO_GET_CONTEXT
#include „EXTERN.h”
#include „perl.h”
#include „XSUB.h”
/* Date globale */
#define MY_CXT_KEY „BlindMice::_guts” XS_VERSION
typedef struct {
număr de int;
nume caracter[3][100];
} my_cxt_t;
START_MY_CXT
MODUL = BlindMice PACKAGE = BlindMice
BOOT:
{
MY_CXT_INIT;
MY_CXT.count = 0;
strcpy(MY_CXT.name[0], „Niciunul”);
strcpy(MY_CXT.name[1], „Niciunul”);
strcpy(MY_CXT.name[2], „Niciunul”);
}
int
nouMouse(car * nume)
PREINIT:
dMY_CXT;
COD:
dacă (MY_CXT.count >= 3) {
warn(„Aveți deja 3 șoareci orbi”);
RETVAL = 0;
}
altceva {
RETVAL = ++ MY_CXT.count;
strcpy(MY_CXT.name[MY_CXT.count - 1], nume);
}
IEȘIRE:
RETVAL
char *
get_mouse_name(index)
index int
PREINIT:
dMY_CXT;
COD:
dacă (index > MY_CXT.count)
croak(„Sunt doar 3 șoareci orbi.”);
altfel
RETVAL = MY_CXT.name[index - 1];
IEȘIRE:
RETVAL
anula
CLONARE(...)
COD:
MY_CXT_CLONE;
MY_CXT REFERINȚE
MY_CXT_KEY
Această macrocomandă este utilizată pentru a defini o cheie unică pentru a se referi la datele statice pentru un XS
modul. Schema de denumire sugerată, așa cum este folosită de h2xs, este să folosești un șir care
constă din numele modulului, șirul „::_guts” și numărul versiunii modulului.
#define MY_CXT_KEY „MyModule::_guts” XS_VERSION
typedef my_cxt_t
Această struct typedef trebuie sa să fie numit întotdeauna „my_cxt_t”. Celelalte macrocomenzi „CXT*” presupun
existența numelui typedef „my_cxt_t”.
Declarați un typedef numit „my_cxt_t” care este o structură care conține toate datele
care trebuie să fie interpret-local.
typedef struct {
int some_value;
} my_cxt_t;
START_MY_CXT
Plasați întotdeauna macrocomanda START_MY_CXT direct după declarația „my_cxt_t”.
MY_CXT_INIT
Macrocomanda MY_CXT_INIT inițializează stocarea pentru structura „my_cxt_t”.
It trebuie sa fi apelat exact o dată, de obicei într-o secțiune BOOT:. Daca intretineti
mai mulți interpreți, ar trebui apelat o dată în fiecare instanță de interpret, cu excepția
pentru interpreții clonați din cei existenți. (Dar consultați „MY_CXT_CLONE” de mai jos.)
dMY_CXT
Utilizați macro-ul dMY_CXT (o declarație) în toate funcțiile care accesează MY_CXT.
MY_CXT
Utilizați macrocomanda MY_CXT pentru a accesa membrii structurii „my_cxt_t”. De exemplu, dacă
„my_cxt_t” este
typedef struct {
index int;
} my_cxt_t;
apoi utilizați acest lucru pentru a accesa membrul „index”.
dMY_CXT;
MY_CXT.index = 2;
aMY_CXT/pMY_CXT
„dMY_CXT” poate fi destul de costisitor de calculat și pentru a evita suprasolicitarea invocării
în fiecare funcție este posibil să se transmită declarația altor funcții folosind
macrocomenzile „aMY_CXT”/”pMY_CXT”, de ex
void sub1() {
dMY_CXT;
MY_CXT.index = 1;
sub2(aMY_CXT);
}
void sub2(pMY_CXT) {
MY_CXT.index = 2;
}
În mod analog cu „pTHX”, există forme echivalente pentru când macro-ul este primul sau
ultimul în mai multe argumente, unde un caracter de subliniere reprezintă o virgulă, adică „_aMY_CXT”,
„aMY_CXT_”, „_pMY_CXT” și „pMY_CXT_”.
MY_CXT_CLONE
În mod implicit, atunci când un interpret nou este creat ca o copie a unui interpret existent (de ex. via
„threads->create()”), ambii interpreți au aceeași structură fizică my_cxt_t.
Apelarea „MY_CXT_CLONE” (de obicei prin intermediul funcției „CLONE()” a pachetului), provoacă o
copie octet-cu-octet a structurii care urmează să fie luată și orice viitor dMY_CXT va provoca
copia să fie accesată în schimb.
MY_CXT_INIT_INTERP(my_perl)
dMY_CXT_INTERP(my_perl)
Acestea sunt versiuni ale macrocomenzilor care iau ca argument un interpret explicit.
Rețineți că aceste macrocomenzi vor funcționa numai împreună în cadrul acelaşi fișier sursă; adică a
dMY_CTX dintr-un fișier sursă va accesa o structură diferită de un dMY_CTX din altul
fișier sursă.
Conștient de fire sistem interfeţe
Pornind de la Perl 5.8, la nivel C/C++, Perl știe cum să încapsuleze interfețele de sistem/bibliotecă
care au versiuni conștient de fire (de ex getpwent_r()) în macrocomenzile frontend (de ex getpwent())
care gestionează corect interacțiunea multithreaded cu interpretul Perl. Asta va
se întâmplă în mod transparent, singurul lucru pe care trebuie să-l faci este să instanțiezi un interpret Perl.
Această împachetare are loc întotdeauna la compilarea sursei de bază Perl (PERL_CORE este definit) sau
Extensii de bază Perl (PERL_EXT este definit). La compilarea codului XS în afara nucleului Perl
împachetarea nu are loc. Rețineți, totuși, că amestecarea formelor _r (ca Perl
compilat pentru operație cu mai multe fire va face) și formele _r-mai puțin nu sunt nici bine-
definite (rezultate inconsecvente, coruperea datelor sau chiar blocările devin mai probabile), nici
este foarte portabil.
EXEMPLE
Fișier „RPC.xs”: interfață cu unele funcții de bibliotecă de legare ONC+ RPC.
#define PERL_NO_GET_CONTEXT
#include „EXTERN.h”
#include „perl.h”
#include „XSUB.h”
#include
typedef struct netconfig Netconfig;
MODUL = RPC PACHET = RPC
SV *
rpcb_gettime(gazdă="localhost")
char *gazdă
PREINIT:
time_t timep;
COD:
ST(0) = sv_newmortal();
if(rpcb_gettime(gazdă, &timep))
sv_setnv( ST(0), (dublu)timep );
Netconfig *
getnetconfigent(netid="udp")
char *netid
MODUL = PACHET RPC = PREFIX NetconfigPtr = rpcb_
anula
rpcb_DESTROY(netconf)
Netconfig *netconf
COD:
printf("NetconfigPtr::DESTROY\n");
gratuit( netconf );
Fișier „typemap”: typemap personalizată pentru RPC.xs. (cf. perlxstypemap)
TYPEMAP
Netconfig * T_PTROBJ
Fișier „RPC.pm”: modulul Perl pentru extensia RPC.
pachet RPC;
solicita Exportator;
necesită DynaLoader;
@ISA = qw(Exportator DynaLoader);
@EXPORT = qw(rpcb_gettime getnetconfigent);
bootstrap RPC;
1;
Fișier „rpctest.pl”: program de testare Perl pentru extensia RPC.
utilizați RPC;
$netconf = getnetconfigent();
$a = rpcb_gettime();
print "time = $a\n";
print "netconf = $netconf\n";
$netconf = getnetconfigent("tcp");
$a = rpcb_gettime("plop");
print "time = $a\n";
print "netconf = $netconf\n";
Avertismente
Codul XS are acces deplin la apelurile de sistem, inclusiv funcțiile bibliotecii C. Are astfel
capacitatea de a interfera cu lucrurile pe care nucleul Perl sau alte module le-au configurat,
cum ar fi handlere de semnal sau handle de fișiere. S-ar putea încurca cu memoria sau cu orice număr de
lucruri nocive. Nu.
Unele module au o buclă de evenimente, care așteaptă intrarea utilizatorului. Este foarte puțin probabil ca două
astfel de module ar funcționa adecvat împreună într-o singură aplicație Perl.
În general, interpretul perl se consideră centrul universului până la
Programul Perl merge. Codul XS este văzut ca un ajutor pentru a realiza lucruri pe care le perl
nu face, sau nu face suficient de repede, dar întotdeauna subordonat perl. Codul XS mai apropiat
aderă la acest model, cu atât vor apărea conflicte mai puțin probabile.
Un domeniu în care a existat conflict este în ceea ce privește localurile C. (Vezi perlcale.)
perl, cu o singură excepție și cu excepția cazului în care se spune altfel, stabilește localul subiacent
programul rulează în localitatea transmisă în el din mediu. Aceasta este o
diferență importantă față de un program generic în limbaj C, unde localitatea de bază este
Localizare „C”, cu excepția cazului în care programul o modifică. Începând cu v5.20, această locație de bază este
complet ascuns de codul perl pur în afara domeniului lexical al „use locale”, cu excepția
câteva apeluri de funcții în modulul POSIX care în mod necesar îl folosesc. Cu exceptia
localul subiacent, cu acea excepție este expus codului XS, afectând toată biblioteca C
rutine al căror comportament este dependent de localitate. Codul dvs. XS ar fi bine să nu presupuneți că
localitatea de bază este „C”. Excepția este categoria locală „LC_NUMERIC” și
Motivul pentru care este o excepție este că experiența a arătat că poate fi problematică pentru XS
cod, în timp ce nu am avut rapoarte de probleme cu celelalte categorii locale. Și
motivul pentru care această categorie este problematică este că caracterul folosit ca zecimală
punctul poate varia. Multe limbi europene folosesc virgulă, în timp ce engleza și, prin urmare, Perl sunt
așteptând un punct (U+002E: OPRIRE). Multe module pot gestiona doar caracterul radix
fiind un punct, și astfel perl încearcă să facă așa. Până prin Perl v5.20, încercarea a fost
doar pentru a seta „LC_NUMERIC” la pornire la localitatea „C”. Orice setlocale() in caz contrar
l-ar schimba; acest lucru a cauzat unele eșecuri. Prin urmare, începând cu v5.22, perl încearcă
păstrați „LC_NUMERIC” întotdeauna setat la „C” pentru codul XS.
Pentru a rezuma, iată la ce să vă așteptați și cum să gestionați localurile în codul XS:
Cod XS care nu știe local
Rețineți că, chiar dacă credeți că codul dvs. nu este conștient de localitate, poate apela un C
funcția de bibliotecă adică. Sperăm că pagina de manual pentru o astfel de funcție va indica
acea dependență, dar documentația este imperfectă.
Localitatea actuală este expusă codului XS, cu excepția posibilului „LC_NUMERIC” (explicat în
paragraful următor). Nu s-au raportat probleme cu celălalt
categorii. Perl inițializează lucrurile la pornire, astfel încât localitatea curentă să fie cea
care este indicat de mediul utilizatorului în vigoare la momentul respectiv. Vedea
„MEDIUL” în perllocale.
Cu toate acestea, până la v5.20, Perl a inițializat lucrurile la pornire, astfel încât „LC_NUMERIC”
a fost setat la localitatea „C”. Dar dacă vreun cod l-ar schimba, ar rămâne
schimbat. Aceasta înseamnă că modulul dvs. nu poate conta că „LC_NUMERIC” este ceva în
special, și nu vă puteți aștepta la numere în virgulă mobilă (inclusiv șiruri de versiuni).
au puncte în ele. Dacă nu permiteți un non-punct, codul dvs. s-ar putea rupe dacă cineva
oriunde a schimbat locația. Din acest motiv, v5.22 a schimbat comportamentul astfel încât Perl
încearcă să păstreze „LC_NUMERIC” în localitatea „C”, cu excepția operațiunilor interne
unde ar trebui să fie altceva. Codul XS care se comportă greșit se va putea schimba întotdeauna
localul oricum, dar cea mai comună instanță a acestui lucru este verificată și gestionată.
Cod XS conștient de localitate
Dacă se dorește localitatea din mediul utilizatorului, nu ar trebui să fie nevoie de XS
cod pentru a seta localul, cu excepția „LC_NUMERIC”, deoarece perl a configurat-o deja. XS
codul ar trebui să evite modificarea localizării, deoarece poate afecta negativ altele, fără legătură,
cod și este posibil să nu fie sigur pentru fire. Cu toate acestea, unele biblioteci extraterestre care pot fi numite fac
setați-o, cum ar fi „Gtk”. Acest lucru poate cauza probleme pentru nucleul perl și alte module.
Începând cu v5.20.1, apelarea funcției sync_locale() de la XS ar trebui să fie suficient
pentru a evita majoritatea acestor probleme. Înainte de aceasta, aveți nevoie de o declarație Perl pură care
face asta:
POSIX::setlocale(LC_ALL, POSIX::setlocale(LC_ALL));
În cazul în care codul dvs. XS poate avea nevoie de localul „LC_NUMERIC” subiacent, există
macrocomenzi disponibile pentru a accesa aceasta; vezi „Funcții și macrocomenzi legate de localitate” în perlapi.
XS VERSIUNE
Acest document acoperă funcțiile acceptate de „ExtUtils::ParseXS” (cunoscut și ca „xsubpp”)
3.13_01.
Utilizați perlxs online folosind serviciile onworks.net