Este es el comando perlembed 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
perlembed - cómo incrustar perl en su programa C
DESCRIPCIÓN
PREÁMBULO
Quieres:
Use C del Perl?
Lea perlxstut, perlxs, h2xs, perlguts y perlapi.
Use a Unix programa del Perl?
Lea sobre comillas inversas y sobre "system" y "exec" en perlfunc.
Use Perl del Perl?
Lea acerca de "do" en perlfunc y "eval" en perlfunc y "require" en perlfunc y
"use" en perlfunc.
Use C del C?
Reconsidere su diseño.
Use Perl del C?
Sigue leyendo ...
HOJA DE RUTA
· Compilar su programa C
· Adición de un intérprete de Perl a su programa C
· Llamar a una subrutina Perl desde su programa C
· Evaluación de una declaración de Perl de su programa C
· Realización de coincidencias y sustituciones de patrones Perl desde su programa C
· Jugando con la pila de Perl de su programa C
· Mantener un intérprete persistente
· Mantener múltiples instancias de intérpretes
· Uso de módulos Perl, que a su vez utilizan bibliotecas C, desde su programa C
· Incrustación de Perl en Win32
Compilación Tu C programa
Si tiene problemas para compilar los scripts de esta documentación, no está solo. El
Regla fundamental: COMPILAR LOS PROGRAMAS EXACTAMENTE DE LA MISMA FORMA EN QUE SE COMPILÓ SU PERL.
(Perdón por gritar.)
Además, todos los programas en C que utilizan Perl deben vincularse en el perl bibliotecas. ¿Qué es eso, preguntas?
Perl está escrito en C; la biblioteca perl es la colección de programas C compilados
que se utilizaron para crear su ejecutable perl (/ usr / bin / perl o equivalente). (Corolario:
no puede usar Perl desde su programa C a menos que Perl haya sido compilado en su máquina, o
instalado correctamente, por eso no debe copiar alegremente los ejecutables de Perl de la máquina
a la máquina sin copiar también el lib directorio.)
Cuando utiliza Perl desde C, su programa en C - normalmente - asignará, "ejecutará" y desasignará un
Intérprete de Perl objeto, que está definido por la biblioteca de perl.
Si su copia de Perl es lo suficientemente reciente para contener esta documentación (versión 5.002 o
más tarde), luego la biblioteca de perl (y EXTERNO.h y perl.h, que también necesitarás)
residir en un directorio que se parece a esto:
/ usr / local / lib / perl5 / your_architecture_here / CORE
o tal vez solo
/ usr / local / lib / perl5 / CORE
o tal vez algo como
/ usr / opt / perl5 / CORE
Ejecute esta declaración para obtener una pista sobre dónde encontrar CORE:
perl -MConfig -e 'imprimir $ Config {archlib}'
Así es como compilaría el ejemplo en la siguiente sección, "Agregar un intérprete de Perl a
su programa C ", en mi caja de Linux:
% gcc -O2 -Dbool = char -DHAS_BOOL -I / usr / local / include
-I / usr / local / lib / perl5 / i586-linux / 5.003 / CORE
-L / usr / local / lib / perl5 / i586-linux / 5.003 / CORE
-o interp interp.c -lperl -lm
(Eso es todo una línea). En mi DEC Alpha con el antiguo 5.003_05, el encantamiento es un poco
diferente:
% cc -O2 -Olimit 2900 -DSTANDARD_C -I / usr / local / include
-I / usr / local / lib / perl5 / alpha-dec_osf / 5.00305 / CORE
-L / usr / local / lib / perl5 / alpha-dec_osf / 5.00305 / CORE -L / usr / local / lib
-D__LANGUAGE_C__ -D_NO_PROTO -o interp interp.c -lperl -lm
¿Cómo puedes averiguar qué agregar? Suponiendo que su Perl es posterior a 5.001, ejecute "perl -V"
comando y preste especial atención a la información "cc" y "ccflags".
Tendrás que elegir el compilador apropiado (cc, gcc, et al.) para su máquina: "perl
-MConfig -e 'print $ Config {cc}' "le dirá qué usar.
También tendrá que elegir el directorio de biblioteca apropiado (/ usr / local / lib / ...) para tu
máquina. Si su compilador se queja de que ciertas funciones no están definidas o que
no puedo localizar -lperl, entonces necesita cambiar la ruta siguiendo la "-L". Si se queja
que no puede encontrar EXTERNO.h y perl.h, debe cambiar la ruta siguiendo la "-I".
Es posible que también deba agregar bibliotecas adicionales. ¿Cuáles? Quizás los impresos por
perl -MConfig -e 'imprimir $ Config {libs}'
Siempre que su binario de perl esté correctamente configurado e instalado el ExtUtils :: Insertar módulo
determinará toda esta información por usted:
% cc -o interp interp.c `perl -MExtUtils :: Insertar -e ccopts -e ldopts`
Si ExtUtils :: Insertar módulo no es parte de su distribución de Perl, puede recuperarlo
del http://www.perl.com/perl/CPAN/modules/by-module/ExtUtils/ (Si esta documentación vino
de su distribución de Perl, entonces está ejecutando 5.004 o mejor y ya lo tiene).
La pestaña ExtUtils :: Insertar kit en CPAN también contiene todo el código fuente para los ejemplos en este
documento, pruebas, ejemplos adicionales y otra información que pueda resultarle útil.
Adición a Perl Interprete a Tu C programa
En cierto sentido, perl (el programa C) es un buen ejemplo de incrustación de Perl (el lenguaje), por lo que
Voy a demostrar cómo incrustar con miniperlmain.c, incluido en la distribución de la fuente.
Aquí hay una versión bastarda y no portátil de miniperlmain.c que contiene lo esencial de
incrustación:
#incluir / * de la distribución Perl * /
#incluir / * de la distribución Perl * /
PerlInterpreter estático * my_perl; / *** El intérprete de Perl *** /
int main (int argc, char ** argv, char ** env)
{
PERL_SYS_INIT3 (& argc, & argv, & env);
my_perl = perl_alloc ();
construcción_perl(mi_perl);
PL_exit_flags | = PERL_EXIT_DESTRUCT_END;
perl_parse (my_perl, NULL, argc, argv, (char **) NULL);
perl_run(mi_perl);
perl_destruct(mi_perl);
perl_gratis(mi_perl);
PERL_SYS_TERM ();
}
Tenga en cuenta que no usamos el puntero "env". Normalmente entregado a "perl_parse" como su final
argumento, "env" aquí se reemplaza por "NULL", lo que significa que el entorno actual
ser usado.
Las macros PERL_SYS_INIT3 () y PERL_SYS_TERM () proporcionar un ajuste específico del sistema de la C
entorno de ejecución necesario para ejecutar intérpretes de Perl; solo deben ser llamados una vez
independientemente de cuántos intérpretes cree o destruya. Llamar PERL_SYS_INIT3 () antes
crea su primer intérprete, y PERL_SYS_TERM () después de que liberes tu último
Interprete.
Since PERL_SYS_INIT3 () puede cambiar "env", puede ser más apropiado proporcionar "env" como un
argumento para perl_parse ().
También tenga en cuenta que no importa a qué argumentos le pase perl_parse (), PERL_SYS_INIT3 () deben
ser invocado en la C principal() argc, argv y env y solo una vez.
Ahora compile este programa (lo llamaré interp.c) en un ejecutable:
% cc -o interp interp.c `perl -MExtUtils :: Insertar -e ccopts -e ldopts`
Después de una compilación exitosa, podrá usar interpretar al igual que el propio perl:
% interpretación
imprimir "Perl bastante bueno \ n";
imprimir "10890 - 9801 es", 10890 - 9801;
Perl bastante bueno
10890 - 9801 es 1089
or
% interp -e 'printf ("% x", 3735928559)'
carne de res muerta
También puede leer y ejecutar declaraciones de Perl desde un archivo mientras se encuentra en medio de su C
programa, colocando el nombre del archivo en argv [1] antes de llamar perl_run.
llamar a Perl subrutina del Tu C programa
Para llamar a subrutinas individuales de Perl, puede utilizar cualquiera de los llamar_* funciones documentadas en
perlcall. En este ejemplo usaremos "call_argv".
Eso se muestra a continuación, en un programa al que llamaré showtime.c.
#incluir
#incluir
PerlInterpreter estático * my_perl;
int main (int argc, char ** argv, char ** env)
{
char * args [] = {NULL};
PERL_SYS_INIT3 (& argc, & argv, & env);
my_perl = perl_alloc ();
construcción_perl(mi_perl);
perl_parse (my_perl, NULL, argc, argv, NULL);
PL_exit_flags | = PERL_EXIT_DESTRUCT_END;
/ *** omitiendo perl_run () *** /
call_argv ("tiempo de presentación", G_DISCARD | G_NOARGS, args);
perl_destruct(mi_perl);
perl_gratis(mi_perl);
PERL_SYS_TERM ();
}
dónde showtime es una subrutina de Perl que no toma argumentos (esa es la G_NOARGS) y para
que ignoraré el valor de retorno (ese es el G_DESCARTAR). Esas banderas, y otras, son
discutido en perlcall.
Definiré el showtime subrutina en un archivo llamado showtime.pl:
imprimir "No me imprimirán";
tiempo de presentación secundario {
tiempo de impresión;
}
Suficientemente simple. Ahora compila y ejecuta:
% cc -o tiempo del espectáculo tiempo del espectáculo.c \
`perl -MExtUtils :: Insertar -e ccopts -e ldopts`
% tiempo del espectáculo showtime.pl
818284590
dando el número de segundos que transcurrieron entre el 1 de enero de 1970 (el comienzo de la
Época Unix), y en el momento en que comencé a escribir esta oración.
En este caso particular, no tenemos que llamar perl_run, ya que configuramos el PL_exit_flag
PERL_EXIT_DESTRUCT_END que ejecuta bloques END en perl_destruct.
Si desea pasar argumentos a la subrutina Perl, puede agregar cadenas al
La lista de "argumentos" terminados en "NULL" se ha pasado a llamada_argv. Para otros tipos de datos o para examinar
valores devueltos, necesitará manipular la pila de Perl. Eso se demuestra en "Fiddling
con la pila de Perl de su programa C ".
Evaluación a Perl ambiental del Tu C programa
Perl proporciona dos funciones API para evaluar fragmentos de código Perl. Estos son "eval_sv" en
perlapi y "eval_pv" en perlapi.
Podría decirse que estas son las únicas rutinas que necesitará para ejecutar fragmentos de código Perl
desde dentro de su programa C. Su código puede ser tan largo como desee; puede contener múltiples
declaraciones; puede emplear "use" en perlfunc, "require" en perlfunc y "do" en perlfunc
para incluir archivos externos de Perl.
evaluación_pv nos permite evaluar cadenas de Perl individuales y luego extraer variables para coerción
en tipos C. El siguiente programa, cadena.c, ejecuta tres cadenas de Perl, extrayendo un
"int" del primero, un "float" del segundo y un "char *" del tercero.
#incluir
#incluir
PerlInterpreter estático * my_perl;
principal (int argc, char ** argv, char ** env)
{
char * incrustación [] = {"", "-e", "0"};
PERL_SYS_INIT3 (& argc, & argv, & env);
my_perl = perl_alloc ();
perl_construct (mi_perl);
perl_parse (my_perl, NULL, 3, incrustación, NULL);
PL_exit_flags | = PERL_EXIT_DESTRUCT_END;
perl_run(mi_perl);
/ ** Trate $ a como un número entero ** /
eval_pv ("$ a = 3; $ a ** = 2", VERDADERO);
printf ("a =% d \ n", SvIV (get_sv ("a", 0)));
/ ** Trate $ a como un flotador ** /
eval_pv ("$ a = 3.14; $ a ** = 2", VERDADERO);
printf ("a =% f \ n", SvNV (get_sv ("a", 0)));
/ ** Trate $ a como una cadena ** /
eval_pv (
"$ a = 'rekcaH lreP rehtonA tsuJ'; $ a = reverso ($ a);", VERDADERO);
printf ("a =% s \ n", SvPV_nolen (get_sv ("a", 0)));
perl_destruct(mi_perl);
perl_gratis(mi_perl);
PERL_SYS_TERM ();
}
Todas esas funciones extrañas con sv en sus nombres ayudan a convertir los escalares de Perl a C
tipos. Están descritos en perlguts y perlapi.
Si compila y ejecuta cadena.c, verá los resultados de usar SvIV () para crear una
"En t", SvNV () para crear un "flotador", y SvPV () para crear una cadena:
a = 9
a = 9.859600
a = Solo otro Hacker de Perl
En el ejemplo anterior, hemos creado una variable global para almacenar temporalmente los datos calculados.
valor de nuestra expresión evaluada. También es posible y en la mayoría de los casos una mejor estrategia
para recuperar el valor de retorno de eval_pv () en lugar de. Ejemplo:
...
SV * val = eval_pv ("reverso 'rekcaH lreP rehtonA tsuJ'", VERDADERO);
printf ("% s \ n", SvPV_nolen (val));
...
De esta forma, evitamos la contaminación del espacio de nombres al no crear variables globales y hemos
simplificó nuestro código también.
Realización Perl patrón cerillas y sustituciones del Tu C programa
La pestaña eval_sv () La función nos permite evaluar cadenas de código Perl, por lo que podemos definir algunas
funciones que lo utilizan para "especializarse" en coincidencias y sustituciones: partido(), sustituir(),
y partidos().
Coincidencia I32 (SV * cadena, char * patrón);
Dada una cadena y un patrón (por ejemplo, "m / cierre /" o "/ \ b \ w * \ b /", que en su programa C
podría aparecer como "/ \\ b \\ w * \\ b /"), partido() devuelve 1 si la cadena coincide con el patrón y 0
de otra manera.
int sustituto (SV ** cadena, char * patrón);
Dado un puntero a un "SV" y una operación "= ~" (por ejemplo, "s / bob / robert / g" o
"tr [AZ] [az]"), sustituir() modifica la cadena dentro del "SV" según el
operación, devolviendo el número de sustituciones realizadas.
Coincidencias SSize_t (SV * cadena, char * patrón, AV ** coincidencias);
Dado un "SV", un patrón y un puntero a un "AV" vacío, partidos() evalúa "$ string = ~
$ patrón "en un contexto de lista y rellena cerillas con los elementos de la matriz, devolviendo el
número de coincidencias encontradas.
Aquí hay un programa de muestra, partido.c, que usa los tres (aquí se han envuelto las líneas largas):
#incluir
#incluir
PerlInterpreter estático * my_perl;
/ ** my_eval_sv (código, error_check)
** algo así como eval_sv (),
** pero sacamos el valor de retorno de la pila
** /
SV * my_eval_sv (SV * sv, I32 croak_on_error)
{
dSP;
SV * retval;
PUSHMARK (SP);
eval_sv (sv, G_SCALAR);
ESPAÑA;
retval = COP;
VOLVER;
si (croak_on_error && SvTRUE (ERRSV))
croar (SvPVx_nolen (ERRSV));
recuperación de retorno;
}
/ ** coincidencia (cadena, patrón)
**
** Se utiliza para coincidencias en un contexto escalar.
**
** Devuelve 1 si la coincidencia fue exitosa; 0 de lo contrario.
** /
Coincidencia I32 (SV * cadena, char * patrón)
{
SV * comando = nuevoSV(0), * retval;
sv_setpvf (comando, "mi $ cadena = '% s'; $ cadena = ~% s",
SvPV_nolen (cadena), patrón);
retval = my_eval_sv (comando, VERDADERO);
SvREFCNT_dec (comando);
return SvIV (retval);
}
/ ** sustituto (cadena, patrón)
**
** Usado para = ~ operaciones que
** modificar su lado izquierdo (s /// y tr ///)
**
** Devuelve el número de coincidencias exitosas y
** modifica la cadena de entrada si la hubiera.
** /
Sustituto I32 (SV ** cadena, char * patrón)
{
SV * comando = nuevoSV(0), * retval;
sv_setpvf (comando, "$ cadena = '% s'; ($ cadena = ~% s)",
SvPV_nolen (* cadena), patrón);
retval = my_eval_sv (comando, VERDADERO);
SvREFCNT_dec (comando);
* cadena = get_sv ("cadena", 0);
return SvIV (retval);
}
/ ** coincidencias (cadena, patrón, coincidencias)
**
** Se utiliza para coincidencias en un contexto de lista.
**
** Devuelve el número de coincidencias,
** y rellena ** coincide con las subcadenas correspondientes
** /
Coincidencias de SSize_t (SV * string, char * pattern, AV ** match_list)
{
SV * comando = nuevoSV(0);
SSize_t num_coincidencias;
sv_setpvf (comando, "mi $ cadena = '% s'; @array = ($ cadena = ~% s)",
SvPV_nolen (cadena), patrón);
my_eval_sv (comando, VERDADERO);
SvREFCNT_dec (comando);
* match_list = get_av ("matriz", 0);
num_matches = av_top_index (* lista_de_coincidencias) + 1;
devuelve num_coincidencias;
}
principal (int argc, char ** argv, char ** env)
{
char * incrustación [] = {"", "-e", "0"};
AV * lista_compatibilidad;
I32 num_coincidencias, i;
SV * texto;
PERL_SYS_INIT3 (& argc, & argv, & env);
my_perl = perl_alloc ();
construcción_perl(mi_perl);
perl_parse (my_perl, NULL, 3, incrustación, NULL);
PL_exit_flags | = PERL_EXIT_DESTRUCT_END;
texto = nuevoSV(0);
sv_setpv (texto, "Cuando está en una tienda de conveniencia y el"
"factura llega a una cantidad como 76 centavos, Maynard es"
"consciente de que hay algo que él * debería * hacer, algo"
"Eso le permitirá recuperar una moneda de veinticinco centavos, pero lo ha hecho"
"No tengo idea * de qué *. Busca a tientas su exprimidor rojo"
"cambia de bolso y le da al chico tres centavos extra con"
"su dólar, con la esperanza de que tenga suerte en lo correcto"
"cantidad. El chico le devuelve dos de sus propios centavos"
"y luego el gran cuarto brillante que es su premio".
"-RICHH");
if (match (text, "m / quarter /")) / ** ¿El texto contiene 'quarter'? ** /
printf ("coincidencia: el texto contiene la palabra 'trimestre'. \ n \ n");
más
printf ("coincidencia: el texto no contiene la palabra 'trimestre'. \ n \ n");
if (match (text, "m / octavo /")) / ** ¿El texto contiene 'octavo'? ** /
printf ("coincidencia: el texto contiene la palabra 'octavo'. \ n \ n");
más
printf ("coincidencia: el texto no contiene la palabra 'octavo'. \ n \ n");
/ ** Coincide con todas las apariciones de /wi../ ** /
num_matches = coincidencias (texto, "m / (wi ..) / g", & lista_compatibilidad);
printf ("coincide con: m / (wi ..) / g encontró% d coincidencias ... \ n", num_matches);
para (i = 0; i <num_matches; i ++)
printf ("coincidencia:% s \ n",
SvPV_nolen (* av_fetch (lista_compatibilidad, i, FALSO)));
printf ("\ n");
/ ** Eliminar todas las vocales del texto ** /
num_matches = substitute (& text, "s / [aeiou] // gi");
si (num_coincidencias) {
printf ("sustituto: s / [aeiou] // gi ...% lu sustituciones hechas. \ n",
(largo sin firmar) num_matches);
printf ("Ahora el texto es:% s \ n \ n", SvPV_nolen (texto));
}
/ ** Intentar una sustitución ** /
if (! substitute (& text, "s / Perl / C /")) {
printf ("sustituto: s / Perl / C ... No se ha realizado ninguna sustitución. \ n \ n");
}
SvREFCNT_dec (texto);
PL_perl_destruct_level = 1;
perl_destruct(mi_perl);
perl_gratis(mi_perl);
PERL_SYS_TERM ();
}
que produce la salida (de nuevo, las líneas largas se han envuelto aquí)
coincidencia: el texto contiene la palabra "trimestre".
coincidencia: el texto no contiene la palabra "octavo".
coincidencias: m / (wi ..) / g encontró 2 coincidencias ...
partido: voluntad
juntar con
sustituto: s / [aeiou] // gi ... 139 sustituciones realizadas.
Ahora el texto es: Whn hst cnvnnc str nd th bll cms t sm mnt lk 76 cnts,
Mynrd s wr tht thr s smthng h * shld * d, smthng tht wll nbl hm t gt
bck qrtr, bt h hs nd * wht *. H fmbls a través de hs rd sqzy chngprs nd
gvs th por thr xtr pnns wth hs dllr, hpng tht h mght lck nt th crrct
mnt. Th por gvs hm bck tw f hs wn pnns nd thn th bg shny qrtr tht s
hs prz. -RCHH
sustituto: s / Perl / C ... No se ha realizado ninguna sustitución.
Trivial con la Perl montón del Tu C programa
Al tratar de explicar las pilas, la mayoría de los libros de texto de informática murmuran algo sobre
columnas cargadas por resorte de platos de cafetería: lo último que empujaste en la pila es el
lo primero que salgas. Eso servirá para nuestros propósitos: su programa C impulsará algunos
argumentos en "la pila de Perl", cierra los ojos mientras ocurre algo de magia, y luego abre el
resultados - el valor de retorno de su subrutina Perl - fuera de la pila.
Primero necesitará saber cómo convertir entre tipos C y tipos Perl, con newSViv ()
y sv_setnv () y newAV () y todos sus amigos. Están descritos en perlguts y
perlapi.
Entonces necesitará saber cómo manipular la pila de Perl. Eso se describe en perlcall.
Una vez que los haya entendido, incrustar Perl en C es fácil.
Debido a que C no tiene una función incorporada para la exponenciación de números enteros, hagamos de Perl **
operador disponible para él (esto es menos útil de lo que parece, porque Perl implementa **
con C's pow () función). Primero, crearé una función de exponenciación de stub en poder.pl:
exposición secundaria {
mi ($ a, $ b) = @_;
devuelve $ a ** $ b;
}
Ahora crearé un programa en C, poder.c, con una función PerlPower () que contiene todo el
perlguts necesarios para empujar los dos argumentos en expo () y sacar el valor de retorno.
Tomar una respiración profunda...
#incluir
#incluir
PerlInterpreter estático * my_perl;
hoyo estatico
PerlPower (int a, int b)
{
dSP; / * inicializar el puntero de pila * /
INGRESAR; / * todo lo creado después de aquí * /
SAVETMPS; / * ... es una variable temporal. * /
PUSHMARK (SP); / * recuerda el puntero de la pila * /
XPUSHs (sv_2mortal (newSViv (a))); / * empujar la base sobre la pila * /
XPUSHs (sv_2mortal (newSViv (b))); / * empujar el exponente a la pila * /
VOLVER; / * hace que el puntero de pila local sea global * /
call_pv ("expo", G_SCALAR); / * llamar a la función * /
SPAGAIN; / * actualizar el puntero de la pila * /
/ * saca el valor de retorno de la pila * /
printf ("% d a la% d-ésima potencia es% d. \ n", a, b, POPi);
VOLVER;
FREETMPS; / * libera ese valor de retorno * /
SALIR; / * ... y los argumentos "mortales" XPUSHed. * /
}
int main (int argc, char ** argv, char ** env)
{
char * my_argv [] = {"", "power.pl"};
PERL_SYS_INIT3 (& argc, & argv, & env);
my_perl = perl_alloc ();
perl_construct (mi_perl);
perl_parse (my_perl, NULL, 2, my_argv, (char **) NULL);
PL_exit_flags | = PERL_EXIT_DESTRUCT_END;
perl_run(mi_perl);
PerlPower (3, 4); / *** Calcular 3 ** 4 *** /
perl_destruct(mi_perl);
perl_gratis(mi_perl);
PERL_SYS_TERM ();
}
Compila y ejecuta:
% cc -o power power.c `perl -MExtUtils :: Embed -e ccopts -e ldopts`
% energía
3 elevado a 4 es 81.
Mantener los a persistente Interprete
Al desarrollar aplicaciones interactivas y / o potencialmente de larga duración, es una buena idea
mantener un intérprete persistente en lugar de asignar y construir un nuevo
intérprete varias veces. La razón principal es la velocidad: dado que Perl solo se cargará
en la memoria una vez.
Sin embargo, debe tener más cuidado con el espacio de nombres y el alcance de las variables al usar un
intérprete persistente. En ejemplos anteriores hemos estado usando variables globales en el
paquete predeterminado "principal". Sabíamos exactamente qué código se ejecutaría y asumimos que podríamos
Evite colisiones variables y un crecimiento exorbitante de la tabla de símbolos.
Digamos que su aplicación es un servidor que ocasionalmente ejecutará código Perl desde algunos
archivo arbitrario. Su servidor no tiene forma de saber qué código va a ejecutar. Muy
peligroso.
Si el archivo es extraído por "perl_parse ()", compilado en un intérprete recién construido,
y posteriormente limpiado con "perl_destruct ()", estás protegido de la mayoría
problemas de espacio de nombres.
Una forma de evitar colisiones de espacios de nombres en este escenario es traducir el nombre del archivo a un
nombre de paquete único garantizado, y luego compile el código en ese paquete usando "eval"
en perlfunc. En el siguiente ejemplo, cada archivo solo se compilará una vez. O la
La aplicación puede optar por limpiar la tabla de símbolos asociada con el archivo después de su
ya no es necesario. Usando "call_argv" en perlapi, llamaremos a la subrutina
"Embed :: Persistent :: eval_file" que vive en el archivo "persistent.pl" y pasa el
nombre de archivo y marca booleana de limpieza / caché como argumentos.
Tenga en cuenta que el proceso seguirá creciendo para cada archivo que utilice. Además,
puede haber subrutinas ed "AUTOLOAD" y otras condiciones que hacen que el símbolo de Perl
mesa para crecer. Es posible que desee agregar alguna lógica que realice un seguimiento del tamaño del proceso, o
se reinicia después de un cierto número de solicitudes, para garantizar que el consumo de memoria sea
minimizado. También querrá establecer el alcance de sus variables con "my" en perlfunc siempre que
posible.
paquete Embed :: Persistent;
# persistent.pl
uso estricto
nuestro% Cache;
use el símbolo qw (delete_package);
sub nombre_paquete_valido {
mi ($ cadena) = @_;
$ cadena = ~ s / ([^ A-Za-z0-9 \ /]) / sprintf ("_% 2x", desempaquetar ("C", $ 1)) / eg;
# segundo pase solo para palabras que comienzan con un dígito
$ cadena = ~ s | / (\ d) | sprintf ("/ _% 2x", desempaquetar ("C", $ 1)) | p. ej.
# Vístelo como un nombre de paquete real
$ cadena = ~ s | / | :: | g;
volver "Insertar". $ cadena;
}
sub archivo_de_evaluación {
my ($ nombre de archivo, $ eliminar) = @_;
mi $ paquete = nombre_paquete_valido ($ nombre_archivo);
my $ mtime = -M $ nombre de archivo;
if (definido $ Cache {$ paquete} {mtime}
&&
$ Cache {$ paquete} {mtime} <= $ mtime)
{
# ya hemos compilado esta subrutina,
# no se ha actualizado en el disco, no queda nada por hacer
print STDERR "ya compilado $ paquete-> manejador \ n";
}
else {
local * FH;
abra FH, $ nombre de archivo o muera "abra '$ nombre de archivo' $!";
local ($ /) = indef;
my $ sub = ;
cerrar FH;
# envuelve el código en una subrutina dentro de nuestro paquete único
my $ eval = qq {paquete $ paquete; sub controlador {$ sub; }};
{
# ocultar nuestras variables dentro de este bloque
my ($ nombre de archivo, $ mtime, $ paquete, $ sub);
eval $ eval;
}
muere $ @ si $ @;
#cachéelo a menos que estemos limpiando cada vez
$ Cache {$ paquete} {mtime} = $ mtime a menos que $ delete;
}
eval {$ paquete-> manejador;};
muere $ @ si $ @;
delete_package ($ paquete) si $ eliminar;
# echa un vistazo si quieres
#print Devel :: Symdump-> rnew ($ paquete) -> as_string, $ /;
}
1;
__FIN__
/ * persistente.c * /
#incluir
#incluir
/ * 1 = limpiar la tabla de símbolos del nombre de archivo después de cada solicitud,
0 = no
*/
#ifndef HACER_LIMPIAR
#definir DO_CLEAN 0
#terminara si
#definir BUFFER_SIZE 1024
PerlInterpreter estático * my_perl = NULL;
int
principal (int argc, char ** argv, char ** env)
{
char * incrustación [] = {"", "persistent.pl"};
char * args [] = {"", DO_CLEAN, NULL};
char nombre de archivo [BUFFER_SIZE];
int estado de salida = 0;
PERL_SYS_INIT3 (& argc, & argv, & env);
if ((my_perl = perl_alloc ()) == NULL) {
fprintf (stderr, "¡sin memoria!");
salida(1);
}
construcción_perl(mi_perl);
PL_origalen = 1; / * no permita que la asignación de $ 0 actualice el
proctitle o incrustación [0] * /
exitstatus = perl_parse (my_perl, NULL, 2, incrustación, NULL);
PL_exit_flags | = PERL_EXIT_DESTRUCT_END;
if (! exitstatus) {
estado de salida = perl_run(mi_perl);
while (printf ("Introduzca el nombre del archivo:") &&
fgets (nombre de archivo, BUFFER_SIZE, stdin)) {
nombre de archivo [strlen (nombre de archivo) -1] = '\ 0'; / * tira \ n * /
/ * llamar a la subrutina,
pasándole el nombre del archivo como argumento * /
args [0] = nombre de archivo;
call_argv ("Insertar :: Persistente :: eval_file",
G_DESCARTAR | G_EVAL, argumentos);
/ * comprobar $ @ * /
si (SvTRUE (ERRSV))
fprintf (stderr, "error de evaluación:% s \ n", SvPV_nolen (ERRSV));
}
}
PL_perl_destruct_level = 0;
perl_destruct(mi_perl);
perl_gratis(mi_perl);
PERL_SYS_TERM ();
salida (exitstatus);
}
Ahora compila:
% cc -o persistente persistente.c \
`perl -MExtUtils :: Insertar -e ccopts -e ldopts`
Aquí hay un archivo de script de ejemplo:
# test.pl
my $ string = "hola";
foo ($ cadena);
subfoo {
print "foo dice: @_ \ n";
}
Ahora ejecuta:
% persistente
Ingrese el nombre del archivo: test.pl
foo dice: hola
Ingrese el nombre del archivo: test.pl
ya compilado Embed :: test_2epl-> handler
foo dice: hola
Ingrese el nombre del archivo: ^ C
Ejecución of FIN bloques
Tradicionalmente, los bloques END se han ejecutado al final de perl_run. Esto causa
problemas para aplicaciones que nunca llaman a perl_run. Desde perl 5.7.2 puede especificar
"PL_exit_flags | = PERL_EXIT_DESTRUCT_END" para obtener el nuevo comportamiento. Esto también permite
ejecución de bloques END si perl_parse falla y "perl_destruct" devolverá la salida
.
$0 asignaciones
Cuando un script de Perl asigna un valor a $ 0, el tiempo de ejecución de Perl intentará hacer este valor.
aparece como el nombre del programa informado por "ps" al actualizar la memoria apuntada por el argv
pasó a perl_parse () y también llamar a funciones API como setproctitle () donde esté disponible.
Es posible que este comportamiento no sea apropiado al incrustar perl y puede desactivarse mediante
asignando el valor 1 a la variable "PL_origalen" antes perl_parse () se llama.
La pestaña persistente.c ejemplo anterior, por ejemplo, es probable que se produzca un error de segmentación cuando se asigna $ 0 a
si el "PL_origalen = 1;" se elimina la asignación. Esto se debe a que perl intentará escribir en
la memoria de sólo lectura de las cadenas de "incrustación []".
Mantener los una variedad Interprete instancias
Algunas aplicaciones raras necesitarán crear más de un intérprete durante una sesión.
Una aplicación de este tipo podría decidir esporádicamente liberar cualquier recurso asociado con el
Interprete.
El programa debe asegurarse de que esto se lleve a cabo antes el próximo intérprete es
construido. De forma predeterminada, cuando perl no se construye con opciones especiales, el
la variable "PL_perl_destruct_level" se establece en 0, ya que generalmente no se necesita una limpieza adicional
cuando un programa solo crea un intérprete durante toda su vida.
Establecer "PL_perl_destruct_level" en 1 hace que todo esté absolutamente limpio:
mientras(1) {
...
/ * restablecer las variables globales aquí con PL_perl_destruct_level = 1 * /
PL_perl_destruct_level = 1;
construcción_perl(mi_perl);
...
/ * limpiar y restablecer _todo_ durante perl_destruct * /
PL_perl_destruct_level = 1;
perl_destruct(mi_perl);
perl_gratis(mi_perl);
...
/ * ¡Vamos a hacerlo de nuevo! * /
}
¿Cuándo? perl_destruct () se llama, el árbol de análisis sintáctico del intérprete y las tablas de símbolos son
se limpian y se restablecen las variables globales. La segunda asignación a
"PL_perl_destruct_level" es necesario porque perl_construct lo restablece a 0.
Ahora suponga que tenemos más de una instancia de intérprete ejecutándose al mismo tiempo. Esto es
factible, pero solo si usó la opción Configurar "-Dusemultiplicity" o las opciones
"-Dusethreads -Duseithreads" al compilar perl. De forma predeterminada, habilitar uno de estos
Configurar opciones establece la variable global por intérprete "PL_perl_destruct_level" en 1,
para que la limpieza a fondo sea automática y las variables del intérprete se inicialicen
correctamente. Incluso si no tiene la intención de ejecutar dos o más intérpretes al mismo tiempo, pero
para ejecutarlos secuencialmente, como en el ejemplo anterior, se recomienda compilar perl con
la opción "-Dusemultiplicity"; de lo contrario, es posible que algunas variables del intérprete no se inicialicen
correctamente entre ejecuciones consecutivas y su aplicación puede fallar.
Consulte también "Interfaces del sistema con reconocimiento de subprocesos" en perlxs.
Usar "-Dusethreads -Duseithreads" en lugar de "-Dusemultiplicity" es más apropiado si
tiene la intención de ejecutar varios intérpretes al mismo tiempo en diferentes subprocesos, porque
habilita el soporte para vincular las bibliotecas de subprocesos de su sistema con el intérprete.
Hagamos un intento:
#incluir
#incluir
/ * vamos a incrustar dos intérpretes * /
#define SAY_HELLO "-e", "print qq (Hola, soy $ ^ X \ n)"
int main (int argc, char ** argv, char ** env)
{
PerlInterpreter * one_perl, * two_perl;
char * one_args [] = {"one_perl", SAY_HELLO};
char * two_args [] = {"two_perl", SAY_HELLO};
PERL_SYS_INIT3 (& argc, & argv, & env);
one_perl = perl_alloc ();
dos_perl = perl_alloc ();
PERL_SET_CONTEXT (uno_perl);
perl_construct (uno_perl);
PERL_SET_CONTEXT (dos_perl);
perl_construct (dos_perl);
PERL_SET_CONTEXT (uno_perl);
perl_parse (one_perl, NULL, 3, one_args, (char **) NULL);
PERL_SET_CONTEXT (dos_perl);
perl_parse (two_perl, NULL, 3, two_args, (char **) NULL);
PERL_SET_CONTEXT (uno_perl);
perl_run (uno_perl);
PERL_SET_CONTEXT (dos_perl);
perl_run (dos_perl);
PERL_SET_CONTEXT (uno_perl);
perl_destruct (uno_perl);
PERL_SET_CONTEXT (dos_perl);
perl_destruct (dos_perl);
PERL_SET_CONTEXT (uno_perl);
perl_free (uno_perl);
PERL_SET_CONTEXT (dos_perl);
perl_free (dos_perl);
PERL_SYS_TERM ();
}
Tenga en cuenta las llamadas a PERL_SET_CONTEXT (). Estos son necesarios para inicializar el estado global.
que rastrea qué intérprete es el "actual" en el proceso o hilo en particular
que puede estar ejecutándolo. Siempre debe usarse si tiene más de un intérprete
y están haciendo llamadas a la API de Perl en ambos intérpretes de forma intercalada.
PERL_SET_CONTEXT (interp) también debe llamarse siempre que un hilo que utilice "interp"
no lo creó (usando tampoco perl_alloc (), o lo más esotérico perl_clone ()).
Compile como de costumbre:
% cc -o multiplicidad multiplicidad.c \
`perl -MExtUtils :: Insertar -e ccopts -e ldopts`
Ejecútelo, ejecútelo:
% multiplicidad
Hola, soy one_perl
Hola soy two_perl
Usando Perl módulos, lo cual sí mismos use C bibliotecas del Tu C programa
Si ha jugado con los ejemplos anteriores y ha intentado incrustar un script que usar()sa Perl
módulo (como Enchufe) que usa una biblioteca C o C ++, esto probablemente sucedió:
No se puede cargar el módulo Socket, la carga dinámica no está disponible en este perl.
(Es posible que deba crear un nuevo ejecutable de Perl que admita
carga dinámica o tiene el módulo Socket vinculado estáticamente a él).
¿Qué tiene de malo?
Su intérprete no sabe cómo comunicarse con estas extensiones por sí solo. A
un poco de pegamento ayudará. Hasta ahora has estado llamando perl_parse (), entregándolo NULL por
el segundo argumento:
perl_parse (my_perl, NULL, argc, my_argv, NULL);
Ahí es donde se puede insertar el código de pegamento para crear el contacto inicial entre Perl y
rutinas vinculadas de C / C ++. Echemos un vistazo a algunas piezas de perlmain.c para ver como lo hace Perl
modo:
vacío estático xs_init (pTHX);
EXTERN_C void boot_DynaLoader (pTHX_ CV * cv);
EXTERN_C void boot_Socket (pTHX_ CV * cv);
EXTERN_C vacío
xs_init (pTHX)
{
char * file = __FILE__;
/ * DynaLoader es un caso especial * /
newXS ("DynaLoader :: boot_DynaLoader", boot_DynaLoader, archivo);
newXS ("Socket :: bootstrap", boot_Socket, archivo);
}
En pocas palabras: para cada extensión vinculada con su ejecutable de Perl (determinada durante su
configuración inicial en su computadora o al agregar una nueva extensión), una subrutina Perl
se crea para incorporar las rutinas de la extensión. Normalmente, esa subrutina se llama
Módulo :: bootstrap () y se invoca cuando dices use Módulo . A su vez, esto se engancha en un
XSUB, módulo_arranque, que crea una contraparte de Perl para cada uno de los XSUB de la extensión.
No se preocupe por esta parte; déjale eso al xsubpp y autores de extensión. Si tu
la extensión se carga dinámicamente, DynaLoader crea Módulo :: bootstrap () para ti en el
volar. De hecho, si tiene un DynaLoader en funcionamiento, rara vez es necesario vincularlo
cualquier otra extensión estáticamente.
Una vez que tenga este código, péguelo en el segundo argumento de perl_parse ():
perl_parse (my_perl, xs_init, argc, my_argv, NULL);
Luego compila:
% cc -o interp interp.c `perl -MExtUtils :: Insertar -e ccopts -e ldopts`
% interpretación
utilizar Socket;
utilice SomeDynamicallyLoadedModule;
print "¡Ahora puedo usar extensiones! \ n" '
ExtUtils :: Insertar también puede automatizar la escritura del xs_init código de pegamento.
% perl -MExtUtils :: Insertar -e xsinit - -o perlxsi.c
% cc -c perlxsi.c `perl -MExtUtils :: Insertar -e ccopts`
% cc -c interp.c `perl -MExtUtils :: Insertar -e ccopts`
% cc -o interp perlxsi.o interp.o `perl -MExtUtils :: Embed -e ldopts`
Consulte perlxs, perlguts y perlapi para obtener más detalles.
Usando integrado Perl con POSIX locales
(Consulte perllocale para obtener información sobre estos.) Cuando normalmente se inicia un intérprete de Perl,
le dice al sistema que quiere usar la configuración regional predeterminada del sistema. Esto es a menudo, pero no
necesariamente, la configuración regional "C" o "POSIX". En ausencia de "use locale" dentro del código perl, este
la mayoría de las veces no tiene ningún efecto (pero consulte "No dentro del alcance de" use locale "" en perllocale).
Además, no hay problema si la configuración regional que desea utilizar en su Perl incrustado es el
igual que el sistema predeterminado. Sin embargo, esto no funciona si ha configurado y desea utilizar
una configuración regional que no es la predeterminada del sistema. A partir de Perl v5.20, puede decirle al
intérprete de Perl incrustado que la configuración regional ya está configurada correctamente, y para omitir
su propia inicialización normal. Omite si la variable de entorno
Se establece "PERL_SKIP_LOCALE_INIT" (incluso si se establece en 0 o ""). Un Perl que tiene esta capacidad
definirá el símbolo del preprocesador C "HAS_SKIP_LOCALE_INIT". Esto permite código que tiene
trabajar con múltiples versiones de Perl para hacer algún tipo de solución cuando se enfrenta a un
anterior Perl.
Ocultación Perl_
Si oculta completamente las formas cortas de la API pública de Perl, agregue -DPERL_NO_SHORT_NAMES
a las banderas de compilación. Esto significa que, por ejemplo, en lugar de escribir
advertir ("% d botellas de cerveza en la pared", recuento de botellas);
tendrás que escribir la forma completa explícita
Perl_warn (aTHX_ "% d botellas de cerveza en la pared", recuento de botellas);
(Ver "Antecedentes y PERL_IMPLICIT_CONTEXT" en perlguts para la explicación de la
"aTHX_". ) Ocultar las formas cortas es muy útil para evitar todo tipo de desagradables (C
preprocesador o de otro tipo) entra en conflicto con otros paquetes de software (Perl define alrededor de 2400
Las API con estos nombres cortos, toman o dejan algunos cientos, por lo que ciertamente hay espacio para
conflicto.)
MORAL
A veces puedes escribir faster código en C, pero siempre puedes escribir código faster en Perl.
Debido a que puede usar uno del otro, combínelos como desee.
Utilice perlembed en línea utilizando los servicios de onworks.net
