21.4. Embedding Perl (Using Perl from C)You can access a Perl interpreter from C by embedding Perl inside your C program. Since Perl is itself a C program, embedding consists of taking the important chunks of Perl and integrating them into yours. Note that embedding isn't necessary if your only goal is to use a standalone Perl program and you don't mind launching a separate process to do so. You can use a function like C's popen(3) to exchange data between your C program and any external Perl program, just like you can use Perl's open(PIPE, "| program") or the IPC::Open2 and IPC::Open3 modules to exchange data between your Perl program and any other program. But if you want to avoid the overhead of launching a separate process, you can embed an interpreter into your C program. When developing long-running applications (say, for embedding in a web server), it's a good idea to maintain a single persistent interpreter rather than creating and destroying interpreters over and over again. The major reason is speed, since Perl will only be loaded into memory once. By using a persistent Perl interpreter, Apache's mod_perl module avoids loading Perl into memory anew every time someone hits an Apache web page. The perlembed manpage provides an example of a persistent interpreter, as well as an example of how a Perl program can manage multiple simultaneous interpreters (another big plus for web servers). 21.4.1. Compiling Embedded ProgramsWhen you embed Perl in C, your C program will usually allocate, "run", and deallocate a PerlInterpreter object, which is a C struct defined in the libperl library that was built in the process of configuring Perl for your system. The libperl library (along with EXTERN.h and perl.h, which you'll also need) resides in a directory that will vary from system to system. You should be able to find out the name of that directory with: You should compile your program in exactly the same way that your perl executable was compiled. First, you'll need to know what C compiler was used to build Perl on your machine. You can learn that from:% perl -MConfig -e "print $Config{archlib}" You can figure out what to put on the rest of the command line with the standard ExtUtils::Embed module. If you had a C program named interp.c and your C compiler was cc, you could compile it for embedding as follows:% perl -MConfig -e "print $Config{cc}" % cc -o interp interp.c `perl -MExtUtils::Embed -e ccopts -e ldopts` 21.4.2. Adding a Perl Interpreter to Your C ProgramAs it turns out, perl (the C program) is a good example of embedding Perl (the language), so a simple demonstration of embedding can be found in the file miniperlmain.c, included with the Perl source code. Here's a nonportable version of miniperlmain.c containing the essentials of embedding: When this is compiled with the command line above, you'll be able to use interp just like a regular Perl interpreter:#include <EXTERN.h> /* from the Perl distribution */ #include <perl.h> /* from the Perl distribution */ static PerlInterpreter *my_perl; /*** The Perl interpreter ***/ int main(int argc, char **argv, char **env) { my_perl = perl_alloc(); perl_construct(my_perl); perl_parse(my_perl, NULL, argc, argv, (char **)NULL); perl_run(my_perl); perl_destruct(my_perl); perl_free(my_perl); } You can also execute Perl statements stored in a file by placing the filename in argv[1] before calling perl_run.% interp -e "printf('%x', 3735928559)" deadbeef 21.4.3. Calling a Perl Subroutine from CIf a Perl program contains a subroutine that you want to call from a C program, you can create a Perl interpreter and then use one of the functions beginning with call_ documented in the perlcall manpage to invoke the subroutine. Let's assume this is our Perl program, called showtime.pl: In this example, we'll use call_argv to invoke the showtime subroutine from this C program, called showtime.c:print "I shan't be printed."; sub showtime { print time; } Here, we assume showtime is a Perl subroutine that takes no arguments (that's the G_NOARGS) and for which we can ignore the return value (that's the G_DISCARD). Those flags, and others, are discussed in perlcall. We compile and run showtime as follows:#include <EXTERN.h> #include <perl.h> static PerlInterpreter *my_perl; int main(int argc, char **argv, char **env) { char *args[] = { NULL }; my_perl = perl_alloc(); perl_construct(my_perl); perl_parse(my_perl, NULL, argc, argv, NULL); /*** skipping perl_run() ***/ call_argv("showtime", G_DISCARD | G_NOARGS, args); perl_destruct(my_perl); perl_free(my_perl); } In this particular case, we don't call perl_run, but in general it's considered good form so that DESTROY methods and END blocks are executed at the right time.% cc -o showtime showtime.c `perl -MExtUtils::Embed -e ccopts -e ldopts` % showtime showtime.pl 963852741 If you want to pass arguments to the Perl subroutine, you can add strings to the NULL-terminated args list passed to call_argv. For other data types, or to examine return values, you'll need to manipulate the Perl stack. That's touched on lightly later; for the down and dirty, read the perlcall manpage bundled with Perl. 21.4.4. Evaluating a Perl Statement from CPerl provides two functions for evaluating snippets of Perl code: eval_sv and eval_pv, described in the perlapi manpage. Arguably, these are the only routines you'll ever need to execute Perl code from within your C program. The code executed can be as long as you wish, contain multiple statements, and employ use, require, or do to include other Perl files. eval_pv lets you evaluate individual Perl strings and then extract variables for coercion into C types. The following program, string.c, executes three Perl strings, extracting an int from the first, a float from the second, and a char * from the third: #include <EXTERN.h> #include <perl.h> static PerlInterpreter *my_perl; main (int argc, char **argv, char **env) { STRLEN n_a; char *embedding[] = { "", "-e", "0" }; my_perl = perl_alloc(); perl_construct( my_perl ); perl_parse(my_perl, NULL, 3, embedding, NULL); perl_run(my_perl); /** Treat $a as an integer **/ eval_pv("$a = 3; $a **= 2", TRUE); printf("a = %d\n", SvIV(get_sv("a", FALSE))); /** Treat $a as a float **/ eval_pv("$a = 3.14; $a **= 2", TRUE); printf("a = %f\n", SvNV(get_sv("a", FALSE))); /** Treat $a as a string **/ eval_pv("$a = 'relreP kcaH rehtonA tsuJ'; $a = reverse($a);", TRUE); printf("a = %s\n", SvPV(get_sv("a", FALSE), n_a)); perl_destruct(my_perl); perl_free(my_perl); } All of the functions with Sv in their names convert Perl scalars to C types. They're described in the perlguts and perlapi manpages. If you compile and run this program, you'll see the results of using SvIV to create an int, SvNV to create a float, and SvPV to create a C string: In the previous example, we've created a global variable to temporarily store the computed value of our evaluated expression. It is also possible (and in most cases better form) to use the return value of eval_pv instead of throwing it away:a = 9 a = 9.859600 a = Just Another Hack Perler The perlembed manpage bundled with Perl includes a demonstration of eval_sv that lets you make use of Perl's regular expression capabilities from your C program.SV *val = eval_pv("reverse 'relreP kcaH rehtonA tsuJ'", TRUE); printf("%s\n", SvPV(val,n_a)); 21.4.5. Fiddling with the Perl Stack from CWhen trying to explain stacks, most computer science textbooks[2] mumble something about spring-loaded columns of cafeteria plates: the last thing you pushed on the stack is the first thing you pop off. That'll do for our purposes: your C program will push some arguments onto "the Perl stack", shut its eyes while some magic happens, and then pop the results--the return value of your Perl subroutine--off the stack.
We'll present an example here without much explanation. To really understand what's going on, you'll need to know how to convert between C types and Perl types, with newSViv and sv_setnv and newAV and all their friends described in the perlguts and perlapi manpages. Then you'll need to read perlcall to learn how to manipulate the Perl stack. Because C has no built-in function for integer exponentiation, let's make Perl's ** operator available to it. (This is less useful than it sounds, since Perl implements ** with C's pow(3) function.) First we'll create an exponentiation function in a library file called power.pl: Now we'll create a C program, power.c, with a function called PerlPower that pushes the two arguments onto the stack, invokes expo, and pops the return value out:sub expo { my ($a, $b) = @_; return $a ** $b; } You can compile power.c into power like so:#include <EXTERN.h> #include <perl.h> static PerlInterpreter *my_perl; /* "Real programmers can write assembly code in any language." */ static void PerlPower(int a, int b) { dSP; /* initialize stack pointer */ ENTER; /* everything created after here */ SAVETMPS; /* ...is a temporary variable. */ PUSHMARK(SP); /* remember the stack pointer */ XPUSHs(sv_2mortal(newSViv(a))); /* push the base onto the stack */ XPUSHs(sv_2mortal(newSViv(b))); /* push the exponent onto stack */ PUTBACK; /* make local stack pointer global */ call_pv("expo", G_SCALAR); /* call the function */ SPAGAIN; /* refresh stack pointer */ /* pop the return value from stack */ printf ("%d to the %dth power is %d.\n", a, b, POPi); PUTBACK; FREETMPS; /* free that return value */ LEAVE; /* ...and the XPUSHed "mortal" args */ } int main (int argc, char **argv, char **env) { char *my_argv[] = { "", "power.pl" }; my_perl = perl_alloc(); perl_construct( my_perl ); perl_parse(my_perl, NULL, 2, my_argv, (char **)NULL); perl_run(my_perl); PerlPower(3, 4); /*** Compute 3 ** 4 ***/ perl_destruct(my_perl); perl_free(my_perl); } Now your power program can sit around being different too.% cc -o power power.c `perl -MExtUtils::Embed -e ccopts -e ldopts` % power 3 to the 4th power is 81. Copyright © 2001 O'Reilly & Associates. All rights reserved. |
|