Este es el comando perlxstut que se puede ejecutar en el proveedor de alojamiento gratuito de OnWorks utilizando una de nuestras múltiples estaciones de trabajo en línea gratuitas, como Ubuntu Online, Fedora Online, emulador en línea de Windows o emulador en línea de MAC OS.
PROGRAMA:
NOMBRE
perlxstut - Tutorial para escribir XSUB
DESCRIPCIÓN
Este tutorial educará al lector sobre los pasos necesarios para crear una extensión de Perl.
Se supone que el lector tiene acceso a perlguts, perlapi y perlxs.
Este tutorial comienza con ejemplos muy simples y se vuelve más complejo, con cada nuevo
ejemplo agregando nuevas características. Es posible que ciertos conceptos no se expliquen completamente hasta más adelante.
en el tutorial para facilitar lentamente al lector la creación de extensiones.
Este tutorial fue escrito desde el punto de vista de Unix. Donde sé que son de otra manera
diferente para otras plataformas (por ejemplo, Win32), los enumeraré. Si encuentras algo que
se perdió, hágamelo saber.
SPECIAL NOTAS
“piensen de nuevo sobre los incrementos de precio”
Este tutorial asume que el programa make que Perl está configurado para usar se llama
"hacer". En lugar de ejecutar "make" en los ejemplos siguientes, es posible que deba sustituir
cualquier programa de marca que Perl haya sido configurado para usar. Corriendo perl -V: hacer debería decir
usted lo que es.
Versión advertencia
Al escribir una extensión de Perl para consumo general, uno debe esperar que el
La extensión se utilizará con versiones de Perl diferentes de la versión disponible en su
máquina. Ya que está leyendo este documento, la versión de Perl en su máquina es
probablemente 5.005 o posterior, pero los usuarios de su extensión pueden tener versiones más antiguas.
Para comprender qué tipo de incompatibilidades uno puede esperar, y en el raro caso de que
la versión de Perl en su máquina es anterior a este documento, consulte la sección sobre
"Solución de problemas de estos ejemplos" para obtener más información.
Si su extensión utiliza algunas funciones de Perl que no están disponibles en versiones anteriores de
Perl, sus usuarios agradecerían una advertencia significativa temprana. Probablemente pondrías
esta información en el README archivo, pero hoy en día la instalación de extensiones puede ser
realizado automáticamente, guiado por CPAN.pm módulo u otras herramientas.
En instalaciones basadas en MakeMaker, Makefile.PL brinda la oportunidad más temprana de realizar
comprobaciones de versión. Uno puede poner algo como esto en Makefile.PL para este propósito:
eval {requiere 5.007}
o morir
############
### Este módulo utiliza un marco de comunicación que no está disponible
### antes de la versión 5.007 de Perl. Actualice su Perl antes
### instalando Kara :: Mba.
############
EOD
Dynamic carga y no Estático carga
Se piensa comúnmente que si un sistema no tiene la capacidad de cargar dinámicamente un
biblioteca, no puede construir XSUB. Esto es incorrecto. usted can construirlos, pero debes
vincular las subrutinas XSUB con el resto de Perl, creando un nuevo ejecutable. Esta
La situación es similar a Perl 4.
Este tutorial todavía se puede utilizar en un sistema de este tipo. El mecanismo de compilación XSUB comprobará el
sistema y construir una biblioteca cargable dinámicamente si es posible, o bien una biblioteca estática y
luego, opcionalmente, un nuevo ejecutable vinculado estáticamente con esa biblioteca estática vinculada.
Si desea construir un ejecutable enlazado estáticamente en un sistema que pueda dinámicamente
cargar bibliotecas, puede, en todos los ejemplos siguientes, donde el comando "" hacer "" sin
se ejecutan los argumentos, ejecute el comando "" make perl "" en su lugar.
Si ha generado un ejecutable vinculado estáticamente de este tipo por elección, entonces en lugar de
diciendo "" hacer prueba "", debería decir "" hacer test_static "". En sistemas que no se pueden construir
Bibliotecas cargables dinámicamente, simplemente decir "" hacer prueba "" es suficiente.
Temas y PERL_NO_GET_CONTEXT
Para compilaciones con subprocesos, perl requiere el puntero de contexto para el subproceso actual, sin
"PERL_NO_GET_CONTEXT", perl llamará a una función para recuperar el contexto.
Para un mejor rendimiento, incluya:
#definir PERL_NO_GET_CONTEXT
como se muestra a continuación.
Para obtener más detalles, consulte perlguts.
TUTORIAL
¡Ahora sigamos con el espectáculo!
EJEMPLO 1
Nuestra primera extensión será muy sencilla. Cuando llamamos a la rutina en la extensión,
imprimirá un mensaje conocido y regresará.
Ejecute "" h2xs -A -n Mytest "". Esto crea un directorio llamado Mytest, posiblemente bajo ext / if
ese directorio existe en el directorio de trabajo actual. Se crearán varios archivos
bajo el directorio Mytest, incluyendo MANIFEST, Makefile.PL, lib / Mytest.pm, Mytest.xs,
t / Mytest.t y Cambios.
El archivo MANIFEST contiene los nombres de todos los archivos recién creados en Mytest.
directorio.
El archivo Makefile.PL debería verse así:
use ExtUtils :: MakeMaker;
# Consulte lib / ExtUtils / MakeMaker.pm para obtener detalles sobre cómo influir
# el contenido del Makefile que está escrito.
WriteMakefile (
NOMBRE => 'Mytest',
VERSION_FROM => 'Mytest.pm', # encuentra $ VERSION
LIBS => [''], # p. Ej., '-Lm'
DEFINE => '', # por ejemplo, '-DHAVE_SOMETHING'
INC => '', # p. Ej., '-I / usr / include / other'
);
El archivo Mytest.pm debería comenzar con algo como esto:
paquete Mytest;
utilizar 5.008008;
uso estricto
use advertencias;
requiera exportador;
nuestro @ISA = qw (Exportador);
nuestro% EXPORT_TAGS = ('all' => [qw (
)]);
nuestro @EXPORT_OK = (@ {$ EXPORT_TAGS {'all'}});
nuestro @EXPORT = qw (
);
nuestra $ VERSION = '0.01';
requieren XSLoader;
XSLoader :: load ('Mytest', $ VERSION);
# Los métodos precargados van aquí.
1;
__FIN__
# A continuación se muestra el código auxiliar de la documentación de su módulo. Más te vale
# ¡editarlo!
El resto del archivo .pm contiene código de muestra para proporcionar documentación para el
extensión.
Finalmente, el archivo Mytest.xs debería verse así:
#definir PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"
MÓDULO = Mytest PAQUETE = Mytest
Editemos el archivo .xs agregando esto al final del archivo:
vacío
Hola()
CÓDIGO:
printf ("¡Hola, mundo! \ n");
Está bien que las líneas que comienzan en la línea "CODE:" no tengan sangría. Sin embargo, para
Para fines de legibilidad, se sugiere sangrar CÓDIGO: un nivel y las líneas
siguiendo un nivel más.
Ahora ejecutaremos "" perl Makefile.PL "". Esto creará un Makefile real, que hará las necesidades.
Su salida se parece a:
%perl Makefile.PL
Comprobando si su kit está completo ...
Se ve bien
Escribiendo Makefile para Mytest
%
Ahora, ejecutar make producirá un resultado parecido a esto (algunas líneas largas tienen
abreviado para mayor claridad y se han eliminado algunas líneas extrañas):
% hacer
cp lib / Mytest.pm blib / lib / Mytest.pm
perl xsubpp -typemap typemap Mytest.xs> Mytest.xsc && \
mv Miprueba.xsc Miprueba.c
Especifique el comportamiento de creación de prototipos para Mytest.xs (consulte el manual de perlxs)
cc -c Miprueba.c
Ejecución de Mkbootstrap para Mytest ()
chmod 644 Mytest.bs
rm -f blib / arch / auto / Mytest / Mytest.so
cc -shared -L / usr / local / lib Mytest.o -o blib / arch / auto / Mytest / Mytest.so
chmod 755 blib / arch / auto / Mytest / Mytest.so
cp Mytest.bs blib / arch / auto / Mytest / Mytest.bs
chmod 644 blib / arch / auto / Mytest / Mytest.bs
Manificando blib / man3 / Mytest.3pm
%
Puede ignorar con seguridad la línea sobre "comportamiento de creación de prototipos", que se explica en "El
PROTOTIPOS: Palabra clave "en perlxs.
Perl tiene su propia forma especial de escribir scripts de prueba fácilmente, pero solo para este ejemplo,
crearemos nuestro propio script de prueba. Cree un archivo llamado hola que tenga este aspecto:
#! / opt / perl5 / bin / perl
use ExtUtils :: testlib;
utilizar Mytest;
Mytest :: hola ();
Ahora hacemos que el script sea ejecutable ("chmod + x hello"), ejecutamos el script y deberíamos ver el
siguiente salida:
% ./Hola
Hola mundo
%
EJEMPLO 2
Ahora agreguemos a nuestra extensión una subrutina que tomará un solo argumento numérico como
ingrese y devuelva 1 si el número es par o 0 si el número es impar.
Agregue lo siguiente al final de Mytest.xs:
int
is_even (entrada)
entrada int
CÓDIGO:
RETVAL = (entrada% 2 == 0);
SALIDA:
RETVALO
No es necesario que haya espacios en blanco al comienzo de la línea "" int input "", pero sí
útil para mejorar la legibilidad. Colocar un punto y coma al final de esa línea también es
Opcional. Se puede colocar cualquier cantidad y tipo de espacio en blanco entre "" int "" y
""aporte"".
Ahora vuelva a ejecutar make para reconstruir nuestra nueva biblioteca compartida.
Ahora realice los mismos pasos que antes, generando un Makefile a partir del archivo Makefile.PL, y
ejecutando hacer.
Para probar que nuestra extensión funciona, ahora necesitamos mirar el archivo Mytest.t. Esta
El archivo está configurado para imitar el mismo tipo de estructura de prueba que tiene el propio Perl. Dentro de
el script de prueba, realiza una serie de pruebas para confirmar el comportamiento de la extensión,
imprimiendo "ok" cuando la prueba es correcta, "no ok" cuando no lo es.
use Test :: More tests => 4;
COMIENZO {use_ok ('Mytest')};
########################
# Inserte su código de prueba a continuación, el módulo Prueba :: Más se usa () ed aquí
# así que lea su página de manual (prueba perldoc :: Más) para obtener ayuda para escribir esto
# secuencia de comandos de prueba.
es (& Mytest ::incluso(0), 1);
es (& Mytest ::incluso(1), 0);
es (& Mytest ::incluso(2), 1);
Llamaremos al script de prueba a través del comando "" make test "". Deberías ver
salida que se parece a esto:
% hacer prueba
PERL_DL_NONLAZY = 1 / usr / bin / perl "-MExtUtils :: Command :: MM" "-e"
"test_harness (0, 'blib / lib', 'blib / arch')" t / *. t
t / Mytest .... ok
Todas las pruebas fueron exitosas.
Archivos = 1, Pruebas = 4, 0 segundos de reloj de pared (0.03 cusr + 0.00 csys = 0.03 CPU)
%
Qué tiene gone ¿en?
El programa h2xs es el punto de partida para la creación de extensiones. En ejemplos posteriores,
vea cómo podemos usar h2xs para leer archivos de encabezado y generar plantillas para conectarnos a C
rutinas.
h2xs crea varios archivos en el directorio de extensiones. El archivo Makefile.PL es un perl
script que generará un verdadero Makefile para construir la extensión. Nos acercaremos
míralo más tarde.
Los archivos .pm y .xs contienen la parte principal de la extensión. El archivo .xs contiene la C
rutinas que componen la extensión. El archivo .pm contiene rutinas que le dicen a Perl cómo
cargue su extensión.
Generando el Makefile y ejecutando "make" creó un directorio llamado blib (que significa
para "construir biblioteca") en el directorio de trabajo actual. Este directorio contendrá el
biblioteca compartida que construiremos. Una vez que lo hayamos probado, podemos instalarlo en su
ubicación final.
Invocar el script de prueba a través de "" make test "" hizo algo muy importante. Invocó a perl
con todos esos argumentos "-I" para que pueda encontrar los distintos archivos que forman parte del
extensión. Está muy importante que mientras todavía está probando las extensiones que usa
"" hacer prueba "". Si intenta ejecutar el script de prueba por sí solo, obtendrá un error fatal
error. Otro motivo por el que es importante utilizar "" make test "" para ejecutar el script de prueba es
que si está probando una actualización a una versión ya existente, use "" make test ""
asegura que probará su nueva extensión, no la versión ya existente.
Cuando Perl ve una "extensión de uso", busca un archivo con el mismo nombre que el
"use" 'extensión d que tiene un sufijo .pm. Si ese archivo no se puede encontrar, Perl muere con un
error fatal. La ruta de búsqueda predeterminada está contenida en la matriz @INC.
En nuestro caso, Mytest.pm le dice a perl que necesitará el exportador y el cargador dinámico.
extensiones. Luego establece las matrices @ISA y @EXPORT y el escalar $ VERSION; finalmente es
le dice a perl que arranque el módulo. Perl llamará a su rutina de carga dinámica (si hay
es uno) y cargue la biblioteca compartida.
Las dos matrices @ISA y @EXPORT son muy importantes. La matriz @ISA contiene una lista de
otros paquetes en los que buscar métodos (o subrutinas) que no existen en el
El paquete actual. Por lo general, esto solo es importante para las extensiones orientadas a objetos (que
hablaremos mucho más adelante), por lo que generalmente no es necesario modificarlo.
La matriz @EXPORT le dice a Perl cuáles de las variables y subrutinas de la extensión deben ser
colocado en el espacio de nombres del paquete de llamada. Porque no sabes si el usuario tiene
ya usó los nombres de sus variables y subrutinas, es de vital importancia
seleccione qué exportar. Hacer No métodos de exportación o nombres de variables by tu préstamo estudiantil sin un bien
razón.
Como regla general, si el módulo intenta estar orientado a objetos, no exporte
cualquier cosa. Si es solo una colección de funciones y variables, entonces puede exportarlas
a través de otra matriz, llamada @EXPORT_OK. Esta matriz no coloca automáticamente su
nombres de subrutinas y variables en el espacio de nombres a menos que el usuario solicite específicamente
que esto se haga.
Consulte perlmod para obtener más información.
La variable $ VERSION se utiliza para garantizar que el archivo .pm y la biblioteca compartida estén "en
sincronizar "entre sí. Cada vez que realice cambios en los archivos .pm o .xs, debe
Incrementar el valor de esta variable.
Escritura bueno compruébalo guiones
No se puede dejar de enfatizar la importancia de escribir buenos guiones de prueba. Deberías de cerca
siga el estilo "ok / not ok" que usa el propio Perl, para que sea muy fácil y
inequívoco para determinar el resultado de cada caso de prueba. Cuando encuentre y corrija un error, haga
asegúrese de agregar un caso de prueba para ello.
Al ejecutar "" make test "", se asegura de que su script Mytest.t se ejecute y utilice el
versión de su extensión. Si tiene muchos casos de prueba, guarde sus archivos de prueba en la "t"
directorio y use el sufijo ".t". Cuando ejecuta "" make test "", todos estos archivos de prueba
será ejecutado.
EJEMPLO 3
Nuestra tercera extensión tomará un argumento como entrada, redondeará ese valor y establecerá el
argumento al valor redondeado.
Agregue lo siguiente al final de Mytest.xs:
vacío
redondo (arg)
doble arg
CÓDIGO:
si (arg> 0.0) {
arg = piso (arg + 0.5);
} más si (arg <0.0) {
arg = ceil (arg - 0.5);
} Else {
argumento = 0.0;
}
SALIDA:
arg
Edite el archivo Makefile.PL para que la línea correspondiente se vea así:
'LIBS' => ['-lm'], # p. Ej., '-Lm'
Genere el Makefile y ejecute make. Cambie el número de prueba en Mytest.t a "9" y agregue el
siguientes pruebas:
$ i = -1.5; & Mytest :: round ($ i); es ($ i, -2.0);
$ i = -1.1; & Mytest :: round ($ i); es ($ i, -1.0);
$ i = 0.0; & Mytest :: round ($ i); es ($ i, 0.0);
$ i = 0.5; & Mytest :: round ($ i); es ($ i, 1.0);
$ i = 1.2; & Mytest :: round ($ i); es ($ i, 1.0);
Ejecutar "" make test "" debería imprimir ahora que las nueve pruebas están bien.
Observe que en estos nuevos casos de prueba, el argumento que se pasó a round fue una variable escalar.
Quizás se pregunte si puede redondear una constante o literal. Para ver que pasa
agregue temporalmente la siguiente línea a Mytest.t:
&Mi prueba::redondo(3);
Ejecute "" make test "" y observe que Perl muere con un error fatal. Perl no te dejará cambiar
el valor de las constantes!
Qué está haciendo new están aquí?
· Hemos realizado algunos cambios en Makefile.PL. En este caso, hemos especificado un extra
biblioteca para vincularse a la biblioteca compartida de la extensión, la biblioteca matemática libm en
este caso. Más adelante hablaremos sobre cómo escribir XSUB que pueden llamar a todas las rutinas en un
biblioteca.
· El valor de la función no se devuelve como valor de retorno de la función, sino
cambiando el valor de la variable que se pasó a la función. Podrías
Adiviné eso cuando viste que el valor de retorno de round es de tipo "void".
Entrada y Salida Parámetros
Usted especifica los parámetros que se pasarán al XSUB en la (s) línea (s) después de que
declarar el valor y el nombre de retorno de la función. Cada línea de parámetro de entrada comienza con
espacio en blanco opcional y puede tener un punto y coma de terminación opcional.
La lista de parámetros de salida aparece al final de la función, justo después de la
SALIDA: directiva. El uso de RETVAL le dice a Perl que desea enviar este valor como
el valor de retorno de la función XSUB. En el Ejemplo 3, queríamos colocar el "valor de retorno"
en la variable original que pasamos, por lo que la listamos (y no RETVAL) en el
SALIDA: sección.
La sección XSUBPP Programa
La sección xsubpp El programa toma el código XS en el archivo .xs y lo traduce al código C,
colocándolo en un archivo cuyo sufijo es .c. El código C creado hace un uso intensivo de C
funciones dentro de Perl.
La sección MAPA DE TIPOS presentar
La sección xsubpp El programa usa reglas para convertir de los tipos de datos de Perl (escalar, matriz, etc.) a
Tipos de datos de C (int, char, etc.). Estas reglas se almacenan en el archivo de mapa de tipos
($ PERLLIB / ExtUtils / typemap). Hay una breve discusión a continuación, pero todo el meollo
los detalles se pueden encontrar en perlxstypemap. Si tiene una versión lo suficientemente nueva de perl (5.16 y
up) o un compilador XS actualizado ("ExtUtils :: ParseXS" 3.13_01 o mejor), entonces puede
typemaps en línea en su XS en lugar de escribir archivos separados. De cualquier manera, este mapa de tipos
la cosa se divide en tres partes:
La primera sección asigna varios tipos de datos C a un nombre, que se corresponde de alguna manera con el
varios tipos de Perl. La segunda sección contiene código C que xsubpp utiliza para manejar la entrada
parámetros. La tercera sección contiene código C que xsubpp utiliza para manejar la salida
parámetros.
Echemos un vistazo a una parte del archivo .c creado para nuestra extensión. El nombre del archivo es
Miprueba.c:
XS (XS_Mytest_round)
{
dXSARGS;
si (artículos! = 1)
Perl_croak (aTHX_ "Uso: Mytest :: round (arg)");
PERL_UNUSED_VAR (cv); / * -W * /
{
doble arg = (doble) SvNV (ST(0)); / * XXXXX * /
si (arg> 0.0) {
arg = piso (arg + 0.5);
} más si (arg <0.0) {
arg = ceil (arg - 0.5);
} Else {
argumento = 0.0;
}
sv_setnv (ST(0), (doble) arg); / * XXXXX * /
SvSETMAGIC (ST(0));
}
XSRETURN_VACÍO;
}
Observe las dos líneas comentadas con "XXXXX". Si marca la primera parte del mapa de tipos
archivo (o sección), verá que los dobles son de tipo T_DOUBLE. En la parte INPUT del
typemap, un argumento que es T_DOUBLE se asigna a la variable arg llamando al
rutina SvNV en algo, luego convertirlo en doble y luego asignarlo a la variable arg.
De manera similar, en la sección OUTPUT, una vez que arg tiene su valor final, se pasa al
La función sv_setnv se devolverá a la subrutina de llamada. Estas dos funciones son
explicado en perlguts; hablaremos más tarde sobre lo que es "ST(0) "significa en la sección
en la pila de argumentos.
advertencia de seguridad para el hogar Salida Argumentos
En general, no es una buena idea escribir extensiones que modifiquen sus parámetros de entrada,
como en el Ejemplo 3. En su lugar, probablemente debería devolver varios valores en una matriz y dejar
la persona que llama los maneja (lo haremos en un ejemplo posterior). Sin embargo, para mejorar
acomodar la llamada a rutinas C preexistentes, que a menudo modifican sus parámetros de entrada,
este comportamiento es tolerado.
EJEMPLO 4
En este ejemplo, ahora comenzaremos a escribir XSUB que interactuarán con C predefinidos
Bibliotecas. Para empezar, construiremos una pequeña biblioteca propia, luego dejaremos que h2xs escriba
nuestros archivos .pm y .xs.
Cree un nuevo directorio llamado Mytest2 al mismo nivel que el directorio Mytest. En el
Mytest2 directorio, cree otro directorio llamado mylib y cd en ese directorio.
Aquí crearemos algunos archivos que generarán una biblioteca de prueba. Estos incluirán una C
archivo de origen y un archivo de encabezado. También crearemos un Makefile.PL en este directorio. Luego
nos aseguraremos de que ejecutar make en el nivel Mytest2 ejecutará automáticamente este
Makefile.PL y el archivo Makefile resultante.
En el directorio mylib, cree un archivo mylib.h con este aspecto:
#definir PRUEBA 4
extern double foo (int, long, const char *);
También cree un archivo mylib.c que tenga este aspecto:
#incluir
#include "./mylib.h"
doble
foo (int a, long b, const char * c)
{
return (a + b + atof (c) + TESTVAL);
}
Y finalmente cree un archivo Makefile.PL que se vea así:
use ExtUtils :: MakeMaker;
$ Verbose = 1;
WriteMakefile (
NOMBRE => 'Mytest2 :: mylib',
SALTAR => [qw (todo estático static_lib dynamic dynamic_lib)],
clean => {'ARCHIVOS' => 'libmylib $ (LIB_EXT)'},
);
sub MY :: top_targets {
'
todo :: estático
pure_all :: estático
estática :: libmylib $ (LIB_EXT)
libmylib $ (LIB_EXT): $ (O_FILES)
$ (AR) cr libmylib $ (LIB_EXT) $ (O_FILES)
$ (RANLIB) libmylib $ (LIB_EXT)
';
}
Asegúrese de usar una pestaña y no espacios en las líneas que comienzan con "$ (AR)" y
"$ (RANLIB)". Make no funcionará correctamente si usa espacios. También ha sido
informó que el argumento "cr" para $ (AR) es innecesario en sistemas Win32.
Ahora crearemos los archivos Mytest2 principales de nivel superior. Cambiar al directorio de arriba
Mytest2 y ejecute el siguiente comando:
% h2xs -O -n Miprueba2 ./Miprueba2/milib/milib.h
Esto imprimirá una advertencia sobre la sobrescritura de Mytest2, pero está bien. Nuestros archivos son
almacenado en Mytest2 / mylib, y no se modificará.
El Makefile.PL normal que genera h2xs no conoce el directorio mylib. Nosotros
Necesito decirle que hay un subdirectorio y que generaremos una biblioteca en
eso. Agreguemos el argumento MYEXTLIB a la llamada WriteMakefile para que se vea así:
WriteMakefile (
'NAME' => 'Mytest2',
'VERSION_FROM' => 'Mytest2.pm', # encuentra $ VERSION
'LIBS' => [''], # p. Ej., '-Lm'
'DEFINE' => '', # por ejemplo, '-DHAVE_SOMETHING'
'INC' => '', # p. Ej., '-I / usr / include / other'
'MYEXTLIB' => 'mylib / libmylib $ (LIB_EXT)',
);
y luego, al final, agregue una subrutina (que anulará la subrutina preexistente).
¡Recuerde usar un carácter de tabulación para sangrar la línea que comienza con "cd"!
sub MY :: postamble {
'
$ (MYEXTLIB): mylib / Makefile
cd mylib && $ (HACER) $ (PASSTHRU)
';
}
También arreglemos el archivo MANIFEST para que refleje con precisión el contenido de nuestro
extensión. La única línea que dice "mylib" debe reemplazarse por las siguientes tres
líneas:
mylib / Makefile.PL
mylib / mylib.c
mylib / mylib.h
Para mantener nuestro espacio de nombres agradable y sin contaminación, edite el archivo .pm y cambie la variable
@EXPORTAR a @EXPORT_OK. Finalmente, en el archivo .xs, edite la línea #include para leer:
#include "mylib / mylib.h"
Y también agregue la siguiente definición de función al final del archivo .xs:
doble
foo (a, b, c)
en un
largo b
carácter constante * c
SALIDA:
RETVALO
Ahora también necesitamos crear un mapa de tipos porque el Perl predeterminado no es compatible actualmente
el tipo "const char *". Incluya una nueva sección TYPEMAP en su código XS antes de lo anterior
función:
TYPEMAP: <
carácter constante * T_PV
FIN
Ahora ejecute perl en el Makefile.PL de nivel superior. Observe que también creó un Makefile en el
directorio mylib. Ejecute make y observe que hace cd en el directorio mylib y ejecute make
allí también.
Ahora edite el script Mytest2.t y cambie el número de pruebas a "4", y agregue lo siguiente
líneas al final del guión:
es (& Mytest2 :: foo (1, 2, "¡Hola, mundo!"), 7);
es (& Mytest2 :: foo (1, 2, "0.0"), 7);
ok (abs (& Mytest2 :: foo (0, 0, "-3.4") - 0.6) <= 0.01);
(Cuando se trata de comparaciones de punto flotante, es mejor no verificar la igualdad, pero
más bien que la diferencia entre el resultado esperado y real está por debajo de un cierto
cantidad (llamada épsilon) que es 0.01 en este caso)
Ejecute "" make test "" y todo debería estar bien. Hay algunas advertencias sobre pruebas faltantes para el
Mytest2 :: mylib extensión, pero puede ignorarlos.
Qué tiene pasó están aquí?
A diferencia de los ejemplos anteriores, ahora hemos ejecutado h2xs en un archivo de inclusión real. Esto ha causado que algunos
extras adicionales que aparecerán en los archivos .pm y .xs.
· En el archivo .xs, ahora hay una directiva #include con la ruta absoluta al
archivo de encabezado mylib.h. Cambiamos esto a una ruta relativa para poder mover el
directorio de extensión si quisiéramos.
· Ahora hay un nuevo código C que se ha agregado al archivo .xs. El propósito de
La rutina "constante" es hacer que los valores # definidos en el archivo de encabezado
accesible por el script de Perl (llamando a "TESTVAL" o & Mytest2 :: TESTVAL).
También hay código XS para permitir llamadas a la rutina "constante".
· El archivo .pm exportó originalmente el nombre "TESTVAL" en la matriz @EXPORT. Esto podría
dar lugar a conflictos de nombres. Una buena regla general es que si #define solo va a ser
utilizadas por las rutinas C mismas, y no por el usuario, deben eliminarse de
la matriz @EXPORT. Alternativamente, si no le importa usar el "nombre completo" de
una variable, puede mover la mayoría o todos los elementos de la matriz @EXPORT a la
@EXPORT_OK matriz.
· Si nuestro archivo de inclusión hubiera contenido directivas #include, estas no habrían sido
procesado por h2xs. No hay una buena solución para esto en este momento.
· También le hemos contado a Perl sobre la biblioteca que construimos en el subdirectorio mylib. Ese
solo requería la adición de la variable "MYEXTLIB" a la llamada WriteMakefile y
el reemplazo de la subrutina postámbulo a cd en el subdirectorio y ejecutar make.
El Makefile.PL para la biblioteca es un poco más complicado, pero no excesivamente.
Nuevamente reemplazamos la subrutina de postámbulo para insertar nuestro propio código. Este código simplemente
especificó que la biblioteca que se creará aquí era una biblioteca de archivos estática (a diferencia de
a una biblioteca cargable dinámicamente) y proporcionó los comandos para construirlo.
Anatomía of .xs presentar
El archivo .xs del "EJEMPLO 4" contenía algunos elementos nuevos. Para entender el significado de
estos elementos, preste atención a la línea que dice
MÓDULO = Mytest2 PAQUETE = Mytest2
Cualquier cosa antes de esta línea es código C simple que describe qué encabezados incluir, y
define algunas funciones de conveniencia. No se realizan traducciones en esta parte, aparte
de haber omitido la documentación de POD incrustada (ver perlpod) pasa al
archivo generado en C de salida tal cual.
Cualquier cosa después de esta línea es la descripción de las funciones XSUB. Estas descripciones son
traducido por xsubpp en código C que implementa estas funciones usando Perl llamando
convenciones, y que hace que estas funciones sean visibles desde el intérprete de Perl.
Preste especial atención a la función "constante". Este nombre aparece dos veces en el
archivo .xs generado: una vez en la primera parte, como una función C estática, luego otra vez en
la segunda parte, cuando se define una interfaz XSUB para esta función C estática.
Esto es bastante típico para los archivos .xs: normalmente el archivo .xs proporciona una interfaz a un
función C existente. Entonces esta función C se define en algún lugar (ya sea en un externo
biblioteca, o en la primera parte del archivo .xs), y una interfaz Perl para esta función (es decir
"Pegamento Perl") se describe en la segunda parte del archivo .xs. La situación del "EJEMPLO 1",
"EJEMPLO 2" y "EJEMPLO 3", cuando todo el trabajo se realiza dentro del "pegamento Perl", es
algo más una excepción que la regla.
Encontrar el feto out of XSUB
En el "EJEMPLO 4", la segunda parte del archivo .xs contenía la siguiente descripción de un XSUB:
doble
foo (a, b, c)
en un
largo b
carácter constante * c
SALIDA:
RETVALO
Tenga en cuenta que, a diferencia de "EJEMPLO 1", "EJEMPLO 2" y "EJEMPLO 3", esta descripción no
no contiene el real código para lo que se hace durante una llamada a la función Perl foo (). Para
Para entender lo que está sucediendo aquí, se puede agregar una sección de CÓDIGO a este XSUB:
doble
foo (a, b, c)
en un
largo b
carácter constante * c
CÓDIGO:
RETVAL = foo (a, b, c);
SALIDA:
RETVALO
Sin embargo, estos dos XSUB proporcionan un código C generado casi idéntico: xsubpp el compilador es
lo suficientemente inteligente como para descubrir la sección "CÓDIGO:" de las dos primeras líneas de la descripción
de XSUB. ¿Qué pasa con la sección "SALIDA:"? De hecho, ¡eso es absolutamente lo mismo! los
La sección "OUTPUT:" también se puede eliminar, as muchos as "CÓDIGO:" . or "PPCODE:" .
no se especifica: xsubpp puede ver que necesita generar una sección de llamada a función, y
también autogenerará la sección de SALIDA. Por lo tanto, uno puede atajar el XSUB para convertirse en:
doble
foo (a, b, c)
en un
largo b
carácter constante * c
¿Podemos hacer lo mismo con un XSUB?
int
is_even (entrada)
entrada int
CÓDIGO:
RETVAL = (entrada% 2 == 0);
SALIDA:
RETVALO
del "EJEMPLO 2"? Para hacer esto, es necesario definir una función C "int is_even (int input)".
Como vimos en "Anatomía del archivo .xs", un lugar adecuado para esta definición es el primer
parte del archivo .xs. De hecho, una función C
int
is_even (int arg)
{
retorno (arg% 2 == 0);
}
probablemente sea exagerado para esto. Algo tan simple como "#define" también servirá:
#define is_even (arg) ((arg)% 2 == 0)
Después de tener esto en la primera parte del archivo .xs, la parte "Pegamento Perl" se vuelve tan simple como
int
is_even (entrada)
entrada int
Esta técnica de separación de la parte de pegamento de la parte del caballo de batalla tiene una obvia
compensaciones: si desea cambiar una interfaz de Perl, debe cambiar dos lugares en su
código. Sin embargo, elimina mucho desorden y hace que la parte del caballo de batalla sea independiente de
idiosincrasias de la convención de llamadas de Perl. (De hecho, no hay nada específico de Perl en
la descripción anterior, una versión diferente de xsubpp podría haber traducido esto a TCL
pegamento o pegamento de Python también.)
+ Info de seguridad para el hogar XSUB argumentos
Con la finalización del Ejemplo 4, ahora tenemos una manera fácil de simular algunos
bibliotecas cuyas interfaces pueden no ser las más limpias del mundo. Ahora continuaremos
con una discusión de los argumentos pasados a la xsubpp compilador
Cuando especifica argumentos para rutinas en el archivo .xs, realmente está pasando tres
piezas de información para cada argumento enumerado. La primera pieza es el orden de esa
argumento relativo a los demás (primero, segundo, etc.). El segundo es el tipo de argumento,
y consta de la declaración de tipo del argumento (por ejemplo, int, char *, etc.). El tercero
piece es la convención de llamada para el argumento en la llamada a la función de biblioteca.
Mientras Perl pasa argumentos a funciones por referencia, C pasa argumentos por valor; para
implementar una función C que modifica los datos de uno de los "argumentos", el argumento real
de esta función C sería un puntero a los datos. Por tanto, dos funciones C con declaraciones
int string_length (char * s);
int mayúscula_carchar (char * cp);
puede tener una semántica completamente diferente: el primero puede inspeccionar una matriz de caracteres
apuntado por s, y el segundo puede desreferenciar inmediatamente "cp" y manipular * cp solamente
(usando el valor de retorno como, digamos, un indicador de éxito). De Perl uno usaría estos
funciona de una manera completamente diferente.
Uno transmite esta información a xsubpp reemplazando "*" antes del argumento por "&". "&" medio
que el argumento debe pasarse a una función de biblioteca por su dirección. Los dos anteriores
la función puede ser XSUB-ified como
int
string_length (s)
carácter * s
int
carácteres_en_ mayúsculas (cp)
char & cp
Por ejemplo, considere:
int
foo (a, b)
char & a
carácter * b
El primer argumento de Perl para esta función se trataría como un carácter y se asignaría a la
variable a, y su dirección se pasaría a la función foo. El segundo Perl
El argumento se trataría como un puntero de cadena y se asignará a la variable b. los valor of
b se pasaría a la función foo. La llamada real a la función foo that xsubpp
genera se vería así:
foo (& a, b);
xsubpp analizará las siguientes listas de argumentos de función de forma idéntica:
char & a
char & a
char & a
Sin embargo, para facilitar la comprensión, se sugiere que coloque un "&" junto al
nombre de la variable y lejos del tipo de variable), y coloque un "*" cerca del tipo de variable,
pero lejos del nombre de la variable (como en la llamada a foo anterior). Al hacerlo, es fácil
comprender exactamente lo que se pasará a la función C; será lo que sea que esté en el
"última columna".
Debería esforzarse mucho para intentar pasar a la función el tipo de variable que desee,
cuando sea posible. Le ahorrará muchos problemas a largo plazo.
La sección Argumento Apilar
Si observamos el código C generado por cualquiera de los ejemplos, excepto el ejemplo 1,
notará una serie de referencias a ST (n), donde n suele ser 0. "ST" es en realidad un
macro que apunta al n-ésimo argumento en la pila de argumentos. ST(0) es por tanto el primer
argumento en la pila y, por lo tanto, el primer argumento pasado al XSUB, ST(1) es el
segundo argumento, y así sucesivamente.
Cuando enumera los argumentos del XSUB en el archivo .xs, eso le dice xsubpp cual argumento
corresponde a cuál de la pila de argumentos (es decir, el primero en la lista es el primero
argumento, etc.). Invita al desastre si no los enumera en el mismo orden que
la función los espera.
Los valores reales en la pila de argumentos son punteros a los valores pasados. Cuando un
El argumento se enumera como un valor de SALIDA, su valor correspondiente en la pila (es decir,
ST(0) si era el primer argumento) se cambia. Puede verificar esto mirando la C
código generado para el Ejemplo 3. El código para el redondo () La rutina XSUB contiene líneas que
se parece a esto:
doble arg = (doble) SvNV (ST(0));
/ * Redondea el contenido de la variable arg * /
sv_setnv (ST(0), (doble) arg);
La variable arg se establece inicialmente tomando el valor de ST(0), luego se almacena de nuevo en
ST(0) al final de la rutina.
Los XSUB también pueden devolver listas, no solo escalares. Esto debe ser hecho por
manipular valores de pila ST(0) ST(1), etc., de una manera sutilmente diferente. Ver perlxs para
Detalles.
Los XSUB también pueden evitar la conversión automática de los argumentos de la función Perl a C
argumentos de la función. Consulte perlxs para obtener más detalles. Algunas personas prefieren la conversión manual por
inspeccionando ST (i) incluso en los casos en que la conversión automática será suficiente, argumentando que esto
aclara la lógica de una llamada XSUB. Compare con "Aprovechar los XSUB" para
una compensación similar de una separación completa de las partes de "pegamento Perl" y "caballo de batalla" de un
XSUB.
Si bien los expertos pueden discutir sobre estos modismos, un novato en Perl puede preferir una forma que
es tan poco específico de Perl como sea posible, lo que significa conversión automática y
generación de llamadas, como en "Cómo sacarle el máximo partido a los XSUB". Este enfoque tiene la
beneficio de proteger al escritor XSUB de futuros cambios en la API de Perl.
Extensión Tu Extension
A veces, es posible que desee proporcionar algunos métodos o subrutinas adicionales para ayudar a hacer
la interfaz entre Perl y su extensión es más simple o más fácil de entender. Estas
las rutinas deben vivir en el archivo .pm. Si se cargan automáticamente cuando el
la extensión misma se carga o solo se carga cuando se llama depende de en qué lugar del archivo .pm se
Se coloca la definición de subrutina. También puede consultar el Autocargador para obtener una forma alternativa de
almacenar y cargar sus subrutinas adicionales.
Documentando Tu Extension
No hay absolutamente ninguna excusa para no documentar su extensión. La documentación pertenece
en el archivo .pm. Este archivo se enviará a pod2man y la documentación incrustada será
convertido al formato de página de manual, luego colocado en el directorio blib. Será copiado a
Directorio de la página de manual de Perl cuando se instala la extensión.
Puede intercalar documentación y código Perl dentro del archivo .pm. De hecho, si quieres
para usar el método de carga automática, debe hacer esto, como explica el comentario dentro del archivo .pm.
Consulte perlpod para obtener más información sobre el formato de pod.
La instalación de Tu Extension
Una vez que su extensión esté completa y pase todas sus pruebas, instalarla es bastante simple:
simplemente ejecuta "make install". Deberá tener permiso de escritura en el
directorios donde está instalado Perl, o solicite al administrador del sistema que ejecute la marca
usted
Alternativamente, puede especificar el directorio exacto para colocar los archivos de la extensión colocando
un "PREFIX = / destination / directory" después de make install (o entre el make y el
instalar si tiene una versión de make). Esto puede resultar muy útil si
la construcción de una extensión que eventualmente se distribuirá a múltiples sistemas. Usted puede
luego simplemente archive los archivos en el directorio de destino y distribúyalos a su
sistemas de destino.
EJEMPLO 5
En este ejemplo, trabajaremos un poco más con la pila de argumentos. Los ejemplos anteriores
todos han devuelto un solo valor. Ahora crearemos una extensión que devuelva un
formación.
Esta extensión está muy orientada a Unix (struct statfs y la llamada al sistema statfs). Si tu
no se ejecutan en un sistema Unix, puede sustituir statfs por cualquier otra función que
devuelve varios valores, puede codificar valores para que se devuelvan a la persona que llama (aunque
esto será un poco más difícil de probar el caso de error), o simplemente no puede hacer este ejemplo.
Si cambia el XSUB, asegúrese de corregir los casos de prueba para que coincidan con los cambios.
Regrese al directorio Mytest y agregue el siguiente código al final de Mytest.xs:
vacío
statfs (ruta)
char * ruta
EN ESO:
int i;
estructuras de estadísticas buf;
CÓDIGOPP:
i = statfs (ruta, & buf);
si (i == 0) {
XPUSHs (sv_2mortal (newSVnv (buf.f_bavail)));
XPUSHs (sv_2mortal (newSVnv (buf.f_bfree)));
XPUSHs (sv_2mortal (newSVnv (buf.f_blocks)));
XPUSHs (sv_2mortal (newSVnv (buf.f_bsize)));
XPUSHs (sv_2mortal (newSVnv (buf.f_ffree)));
XPUSHs (sv_2mortal (newSVnv (buf.f_files)));
XPUSHs (sv_2mortal (newSVnv (buf.f_type)));
} Else {
XPUSHs (sv_2mortal (newSVnv (errno)));
}
También deberá agregar el siguiente código en la parte superior del archivo .xs, justo después de la
incluir de "XSUB.h":
#incluir
También agregue el siguiente segmento de código a Mytest.t mientras incrementa las pruebas "9" a "11":
@a = & Mytest :: statfs ("/ blech");
ok (escalar (@a) == 1 && $ a [0] == 2);
@a = & Mytest :: statfs ("/");
es (escalar (@a), 7);
New Cosas in este vídeo Ejemplo
Este ejemplo agregó bastantes conceptos nuevos. Los tomaremos uno a la vez.
· La directiva INIT: contiene código que se colocará inmediatamente después del argumento
la pila está decodificada. C no permite declaraciones de variables en ubicaciones arbitrarias
dentro de una función, por lo que esta suele ser la mejor manera de declarar las variables locales necesarias
por el XSUB. (Alternativamente, se podría poner toda la sección "PPCODE:" entre llaves,
y ponga estas declaraciones en la parte superior.)
· Esta rutina también devuelve un número diferente de argumentos dependiendo del éxito o
fallo de la llamada a statfs. Si hay un error, el número de error se devuelve como
una matriz de un solo elemento. Si la llamada es exitosa, entonces una matriz de 7 elementos es
regresó. Dado que solo se pasa un argumento a esta función, necesitamos espacio en el
pila para contener los 7 valores que se pueden devolver.
Hacemos esto usando la directiva PPCODE:, en lugar de la directiva CODE :. Esta
decirles xsubpp que gestionaremos los valores devueltos que se colocarán en el
pila de argumentos por nosotros mismos.
· Cuando queremos colocar valores que se devolverán a la persona que llama en la pila, usamos el
serie de macros que comienzan con "XPUSH". Hay cinco versiones diferentes, para
colocando enteros, enteros sin signo, dobles, cadenas y escalares de Perl en la pila.
En nuestro ejemplo, colocamos un escalar Perl en la pila. (De hecho, este es el único
macro que se puede utilizar para devolver varios valores).
Las macros XPUSH * extenderán automáticamente la pila de devoluciones para evitar que se
invadir. Empujas los valores en la pila en el orden en que quieres que los vea el
programa de llamada.
· Los valores insertados en la pila de retorno del XSUB son en realidad SV mortales. Ellos
se hacen mortales de modo que una vez que los valores son copiados por el programa de llamada, el SV
que contenían los valores devueltos se pueden desasignar. Si no fueran mortales, entonces
continuaría existiendo después de que se devolviera la rutina XSUB, pero no sería accesible.
Ésta es una pérdida de memoria.
· Si estuviéramos interesados en el rendimiento, no en la compacidad del código, en la rama del éxito
no usaríamos macros "XPUSHs", sino macros "PUSHs", y pre-extenderíamos la pila
antes de presionar los valores de retorno:
EXTENDER (SP, 7);
La compensación es que uno necesita calcular el número de valores de retorno por adelantado
(aunque extender demasiado la pila normalmente no dañará nada más que la memoria
consumo).
De manera similar, en la rama de fallas podríamos usar "PUSHs" sin extendiendo la pila: el
La referencia de función de Perl llega a un XSUB en la pila, por lo que la pila es large
suficiente para tomar un valor de retorno.
EJEMPLO 6
En este ejemplo, aceptaremos una referencia a una matriz como parámetro de entrada y devolveremos
una referencia a una matriz de hashes. Esto demostrará la manipulación del complejo Perl
tipos de datos de un XSUB.
Esta extensión es algo artificial. Se basa en el código del ejemplo anterior.
Llama a la función statfs varias veces, aceptando una referencia a una matriz de
nombres de archivo como entrada y devolviendo una referencia a una matriz de hashes que contienen los datos
para cada uno de los sistemas de archivos.
Regrese al directorio Mytest y agregue el siguiente código al final de Mytest.xs:
VS *
multi_statfs (rutas)
SV * caminos
EN ESO:
Resultados AV *;
SSize_t rutas numéricas = 0, n;
int i;
estructuras de estadísticas buf;
SvGETMAGIC (rutas);
if ((! SvROK (rutas))
|| (SvTYPE (SvRV (rutas))! = SVt_PVAV)
|| ((numpaths = av_top_index ((AV *) SvRV (rutas))) <0))
{
XSRETURN_UNDEF;
}
resultados = (AV *) sv_2mortal ((SV *) newAV ());
CÓDIGO:
para (n = 0; n <= númrutas; n ++) {
HV * rh;
ESTRENAR l;
char * fn = SvPV (* av_fetch ((AV *) SvRV (rutas), n, 0), l);
i = statfs (fn, & buf);
si (i! = 0) {
av_push (resultados, newSVnv (errno));
continuar
}
rh = (HV *) sv_2mortal ((SV *) newHV ());
hv_store (rh, "f_bavail", 8, newSVnv (buf.f_bavail), 0);
hv_store (rh, "f_bfree", 7, newSVnv (buf.f_bfree), 0);
hv_store (rh, "f_blocks", 8, newSVnv (buf.f_blocks), 0);
hv_store (rh, "f_bsize", 7, newSVnv (buf.f_bsize), 0);
hv_store (rh, "f_ffree", 7, newSVnv (buf.f_ffree), 0);
hv_store (rh, "f_files", 7, newSVnv (buf.f_files), 0);
hv_store (rh, "f_type", 6, newSVnv (buf.f_type), 0);
av_push (resultados, newRV ((SV *) rh));
}
RETVAL = newRV ((SV *) resultados);
SALIDA:
RETVALO
Y agregue el siguiente código a Mytest.t, mientras incrementa las pruebas "11" a "13":
$ resultados = Mytest :: multi_statfs (['/', '/ blech']);
ok (ref $ resultados -> [0]);
ok (! ref $ resultados -> [1]);
New Cosas in este vídeo Ejemplo
Aquí se introducen varios conceptos nuevos, que se describen a continuación:
· Esta función no utiliza un mapa de tipos. En cambio, lo declaramos aceptando un SV *
(escalar) y devolviendo un valor SV *, y nos encargamos de rellenar estos
escalares dentro del código. Debido a que solo devolvemos un valor, no necesitamos un
Directiva "PPCODE:" - en su lugar, usamos las directivas "CODE:" y "OUTPUT:".
· Al tratar con referencias, es importante manejarlas con precaución. los
El bloque "INIT:" primero llama a SvGETMAGIC (rutas), en caso de que las rutas sean una variable vinculada. Luego
comprueba que "SvROK" devuelve verdadero, lo que indica que las rutas son una referencia válida.
(El simple hecho de marcar "SvROK" no activará FETCH en una variable vinculada). Luego, verifica
que el objeto al que hacen referencia las rutas es una matriz, utilizando "SvRV" para eliminar la referencia de las rutas,
y "SvTYPE" para descubrir su tipo. Como prueba adicional, verifica que la matriz
referenciado por rutas no está vacío, utilizando la función "av_top_index" (que devuelve -1
si la matriz está vacía). La macro XSRETURN_UNDEF se usa para abortar el XSUB y regresar
el valor indefinido siempre que no se cumplan las tres condiciones.
· Manipulamos varias matrices en este XSUB. Tenga en cuenta que se representa una matriz
internamente mediante un puntero AV *. Las funciones y macros para manipular matrices son
similar a las funciones en Perl: "av_top_index" devuelve el índice más alto en un AV *,
muy parecido a $ # array; "av_fetch" obtiene un único valor escalar de una matriz, dado su
índice; "av_push" inserta un valor escalar al final de la matriz, automáticamente
extendiendo la matriz según sea necesario.
Específicamente, leemos los nombres de ruta uno a la vez de la matriz de entrada y almacenamos el
da como resultado una matriz de salida (resultados) en el mismo orden. Si statfs falla, el elemento
insertado en la matriz de retorno es el valor de errno después del error. Si statfs
tiene éxito, sin embargo, el valor introducido en la matriz de retorno es una referencia a un hash
que contiene parte de la información de la estructura statfs.
Al igual que con la pila de devoluciones, sería posible (y una pequeña ganancia de rendimiento) pre
extender la matriz de retorno antes de insertar datos en ella, ya que sabemos cuántos elementos
volveremos:
av_extend (resultados, númrutas);
· Estamos realizando solo una operación hash en esta función, que está almacenando una nueva
escalar bajo una clave usando "hv_store". Un hash está representado por un puntero HV *. Igual que
matrices, las funciones para manipular hashes de un XSUB reflejan la funcionalidad
disponible en Perl. Vea perlguts y perlapi para más detalles.
· Para crear una referencia, usamos la función "newRV". Tenga en cuenta que puede emitir un AV * o
un HV * para escribir SV * en este caso (y muchos otros). Esto le permite tomar referencias
a matrices, hashes y escalares con la misma función. Por el contrario, la función "SvRV"
siempre devuelve un SV *, que puede necesitar ser convertido al tipo apropiado si es
algo que no sea un escalar (verifique con "SvTYPE").
· En este punto, xsubpp está haciendo muy poco trabajo: las diferencias entre Mytest.xs
y Mytest.c son mínimos.
EJEMPLO 7 (Próximo Pronto)
XPUSH args Y establece RETVAL Y asigna el valor de retorno a la matriz
EJEMPLO 8 (Próximo Pronto)
Configurando $!
EJEMPLO 9 Pasando (Paso) abierto archivos a XSes
Pensarías que pasar archivos a un XS es difícil, con todos los typeglobs y esas cosas.
Bueno, no lo es.
Supongamos que, por alguna extraña razón, necesitamos un contenedor alrededor de la biblioteca C estándar
función "fputs ()". Esto es todo lo que necesitamos:
#definir PERLIO_NOT_STDIO 0
#definir PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#incluye
int
fputs (s, flujo)
carácter * s
ARCHIVO * flujo
El trabajo real se realiza en el tipo de mapa estándar.
Pero pierdes todas las cosas finas hechas por las capas de perlio. Esto llama a la función stdio
"fputs ()", que no sabe nada sobre ellos.
El mapa de tipos estándar ofrece tres variantes de PerlIO *: "InputStream" (T_IN),
"InOutStream" (T_INOUT) y "OutputStream" (T_OUT). Un simple "PerlIO *" se considera un
T_INOUT. Si es importante en su código (vea a continuación por qué podría hacerlo) #define or typedef one of
los nombres específicos y utilícelo como argumento o tipo de resultado en su archivo XS.
El mapa de tipos estándar no contiene PerlIO * antes de perl 5.7, pero tiene los tres
variantes de flujo. El uso de PerlIO * directamente no es compatible con versiones anteriores a menos que proporcione
su propio mapa de tipos.
Para las corrientes que vienen Desde perl, la principal diferencia es que "OutputStream" obtendrá el
salida PerlIO * - que puede marcar la diferencia en un socket. Como en nuestro ejemplo ...
Para los arroyos que se entregan a perl se crea un nuevo identificador de archivo (es decir, una referencia a un nuevo
glob) y asociado con el PerlIO * proporcionado. Si el estado de lectura / escritura de PerlIO *
no es correcto, entonces puede recibir errores o advertencias cuando se usa el identificador de archivo. Entonces
si abrió el PerlIO * como "w", realmente debería ser un "OutputStream" si lo abre como "r"
debe ser un "InputStream".
Ahora, suponga que desea usar capas perlio en su XS. Usaremos el perlio
La función "PerlIO_puts ()" como ejemplo.
En la parte C del archivo XS (arriba de la primera línea MODULE) tienes
#definir flujo de salida PerlIO *
or
typedef PerlIO * Flujo de salida;
Y este es el código XS:
int
perlioputs (s, corriente)
carácter * s
Flujo de salida
CÓDIGO:
RETVAL = PerlIO_puts (flujo, s);
SALIDA:
RETVALO
Tenemos que usar una sección "CÓDIGO" porque "PerlIO_puts ()" tiene los argumentos invertidos
en comparación con "fputs ()", y queremos mantener los mismos argumentos.
Queriendo explorar esto a fondo, queremos usar el stdio "fputs ()" en un PerlIO *. Esta
significa que tenemos que pedirle al sistema perlio un "ARCHIVO *" estándar:
int
perliofputs (s, flujo)
carácter * s
Flujo de salida
PREINICIO:
ARCHIVO * fp = PerlIO_findFILE (flujo);
CÓDIGO:
if (fp! = (ARCHIVO *) 0) {
RETVAL = fputs (s, fp);
} Else {
REVALOR = -1;
}
SALIDA:
RETVALO
Nota: "PerlIO_findFILE ()" buscará en las capas una capa estándar. Si no puede encontrar uno,
llamará a "PerlIO_exportFILE ()" para generar un nuevo stdio "FILE". Por favor solo llame
"PerlIO_exportFILE ()" si quieres un new "EXPEDIENTE". Generará uno en cada llamada y empujará
una nueva capa de stdio. Así que no lo llames repetidamente en el mismo archivo. "PerlIO_findFILE ()"
recupere la capa stdio una vez que haya sido generada por "PerlIO_exportFILE ()".
Esto se aplica únicamente al sistema perlio. Para versiones anteriores a 5.7, "PerlIO_exportFILE ()" es
equivalente a "PerlIO_findFILE ()".
Localización de averías these Ejemplos
Como se menciona en la parte superior de este documento, si tiene problemas con estos ejemplos
extensiones, es posible que vea si alguno de estos le ayuda.
· En versiones de 5.002 anteriores a la versión gamma, el script de prueba del Ejemplo 1 no
funcionar correctamente. Necesita cambiar la línea "use lib" para leer:
use lib './blib';
· En versiones de 5.002 anteriores a la versión 5.002b1h, el archivo test.pl no se
creado por h2xs. Esto significa que no puede decir "hacer prueba" para ejecutar el script de prueba.
Deberá agregar la siguiente línea antes de la declaración "usar extensión":
use lib './blib';
· En las versiones 5.000 y 5.001, en lugar de utilizar la línea anterior, deberá utilizar el
siguiente línea:
COMIENZO {unshift (@INC, "./blib")}
· Este documento asume que el ejecutable llamado "perl" es Perl versión 5. Algunos
Los sistemas pueden haber instalado la versión 5 de Perl como "perl5".
See tambien
Para obtener más información, consulte perlguts, perlapi, perlxs, perlmod y perlpod.
Autor
Jeff Okamoto[email protected]>
Revisado y asistido por Dean Roehrich, Ilya Zakharevich, Andreas Koenig y Tim Bunce.
Material de PerlIO aportado por Lupe Christoph, con algunas aclaraciones de Nick Ing-
Simons.
Cambios para h2xs a partir de Perl 5.8.x por Renee Baecker
Apellido cambiado
2012-01-20
Use perlxstut en línea usando los servicios de onworks.net