X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=pod%2Fperlembed.pod;h=9523e1f5ab771dda6ab18fa13030ce5d0c6a3fea;hb=561b68a973f8a5d10c61d6a02c02f3002a0a63ba;hp=e55ee633c90044e609d540cab32625ec0266ae93;hpb=8ebc5c0145d2e3559bce3073437e6d027dcdffcc;p=p5sagit%2Fp5-mst-13.2.git diff --git a/pod/perlembed.pod b/pod/perlembed.pod index e55ee63..9523e1f 100644 --- a/pod/perlembed.pod +++ b/pod/perlembed.pod @@ -12,16 +12,16 @@ Do you want to: =item B -Read L and L. +Read L, L, L, L, and L. -=item B +=item B Read about back-quotes and about C and C in L. =item B -Read about C and C in L and L and C -and C in L and L, L. +Read about L and L and L +and L. =item B @@ -35,32 +35,57 @@ Read on... =head2 ROADMAP -L +=over 5 + +=item * + +Compiling your C program + +=item * + +Adding a Perl interpreter to your C program + +=item * + +Calling a Perl subroutine from your C program + +=item * + +Evaluating a Perl statement from your C program + +=item * -There's one example in each of the eight sections: +Performing Perl pattern matches and substitutions from your C program -L +=item * -L +Fiddling with the Perl stack from your C program -L +=item * -L +Maintaining a persistent interpreter -L +=item * -L +Maintaining multiple interpreter instances -L +=item * -L +Using Perl modules, which themselves use C libraries, from your C program -This documentation is UNIX specific. +=item * + +Embedding Perl under Win32 + +=back =head2 Compiling your C program -Every C program that uses Perl must link in the I. +If you have trouble compiling the scripts in this documentation, +you're not alone. The cardinal rule: COMPILE THE PROGRAMS IN EXACTLY +THE SAME WAY THAT YOUR PERL WAS COMPILED. (Sorry for yelling.) +Also, every C program that uses Perl must link in the I. What's that, you ask? Perl is itself written in C; the perl library is the collection of compiled C programs that were used to create your perl executable (I or equivalent). (Corollary: you @@ -69,13 +94,14 @@ your machine, or installed properly--that's why you shouldn't blithely copy Perl executables from machine to machine without also copying the I directory.) -Your C program will--usually--allocate, "run", and deallocate a -I object, which is defined in the perl library. +When you use Perl from C, your C program will--usually--allocate, +"run", and deallocate a I object, which is defined by +the perl library. If your copy of Perl is recent enough to contain this documentation (version 5.002 or later), then the perl library (and I and -I, which you'll also need) will -reside in a directory resembling this: +I, which you'll also need) will reside in a directory +that looks like this: /usr/local/lib/perl5/your_architecture_here/CORE @@ -91,42 +117,64 @@ Execute this statement for a hint about where to find CORE: perl -MConfig -e 'print $Config{archlib}' -Here's how you might compile the example in the next section, -L, -on a DEC Alpha running the OSF operating system: +Here's how you'd compile the example in the next section, +L, on my Linux box: + + % 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 + +(That's all one line.) On my DEC Alpha running old 5.003_05, the +incantation is a bit different: + + % 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 - % cc -o interp interp.c -L/usr/local/lib/perl5/alpha-dec_osf/CORE - -I/usr/local/lib/perl5/alpha-dec_osf/CORE -lperl -lm +How can you figure out what to add? Assuming your Perl is post-5.001, +execute a C command and pay special attention to the "cc" and +"ccflags" information. -You'll have to choose the appropriate compiler (I, I, et al.) and -library directory (I) for your machine. If your -compiler complains that certain functions are undefined, or that it -can't locate I<-lperl>, then you need to change the path following the --L. If it complains that it can't find I or I, you need -to change the path following the -I. +You'll have to choose the appropriate compiler (I, I, et al.) for +your machine: C will tell you what +to use. + +You'll also have to choose the appropriate library directory +(I) for your machine. If your compiler complains +that certain functions are undefined, or that it can't locate +I<-lperl>, then you need to change the path following the C<-L>. If it +complains that it can't find I and I, you need to +change the path following the C<-I>. You may have to add extra libraries as well. Which ones? Perhaps those printed by perl -MConfig -e 'print $Config{libs}' -We strongly recommend you use the B module to determine -all of this information for you: +Provided your perl binary was properly configured and installed the +B module will determine all of this information for +you: % cc -o interp interp.c `perl -MExtUtils::Embed -e ccopts -e ldopts` +If the B module isn't part of your Perl distribution, +you can retrieve it from +http://www.perl.com/perl/CPAN/modules/by-module/ExtUtils/ +(If this documentation came from your Perl distribution, then you're +running 5.004 or better and you already have it.) -If the B module is not part of your perl kit's -distribution you can retrieve it from: -http://www.perl.com/cgi-bin/cpan_mod?module=ExtUtils::Embed. - +The B kit on CPAN also contains all source code for +the examples in this document, tests, additional examples and other +information you may find useful. =head2 Adding a Perl interpreter to your C program In a sense, perl (the C program) is a good example of embedding Perl (the language), so I'll demonstrate embedding with I, -from the source distribution. Here's a bastardized, non-portable version of -I containing the essentials of embedding: +included in the source distribution. Here's a bastardized, nonportable +version of I containing the essentials of embedding: #include /* from the Perl distribution */ #include /* from the Perl distribution */ @@ -135,19 +183,24 @@ I containing the essentials of embedding: int main(int argc, char **argv, char **env) { + PERL_SYS_INIT3(&argc,&argv,&env); my_perl = perl_alloc(); perl_construct(my_perl); + PL_exit_flags |= PERL_EXIT_DESTRUCT_END; perl_parse(my_perl, NULL, argc, argv, (char **)NULL); perl_run(my_perl); perl_destruct(my_perl); perl_free(my_perl); + PERL_SYS_TERM(); } -Note that we do not use the C pointer here or in any of the -following examples. -Normally handed to C as its final argument, -we hand it a B instead, in which case the current environment -is used. +Notice that we don't use the C pointer. Normally handed to +C as its final argument, C here is replaced by +C, which means that the current environment will be used. The macros +PERL_SYS_INIT3() and PERL_SYS_TERM() provide system-specific tune up +of the C runtime environment necessary to run Perl interpreters; since +PERL_SYS_INIT3() may change C, it may be more appropriate to provide +C as an argument to perl_parse(). Now compile this program (I'll call it I) into an executable: @@ -170,13 +223,13 @@ or You can also read and execute Perl statements from a file while in the midst of your C program, by placing the filename in I before -calling I. +calling I. =head2 Calling a Perl subroutine from your C program -To call individual Perl subroutines, you can use any of the B -functions documented in the L man page. -In this example we'll use I. +To call individual Perl subroutines, you can use any of the B +functions documented in L. +In this example we'll use C. That's shown below, in a program I'll call I. @@ -188,17 +241,20 @@ That's shown below, in a program I'll call I. int main(int argc, char **argv, char **env) { char *args[] = { NULL }; + PERL_SYS_INIT3(&argc,&argv,&env); my_perl = perl_alloc(); perl_construct(my_perl); perl_parse(my_perl, NULL, argc, argv, NULL); + PL_exit_flags |= PERL_EXIT_DESTRUCT_END; /*** skipping perl_run() ***/ - perl_call_argv("showtime", G_DISCARD | G_NOARGS, args); + call_argv("showtime", G_DISCARD | G_NOARGS, args); perl_destruct(my_perl); perl_free(my_perl); + PERL_SYS_TERM(); } where I is a Perl subroutine that takes no arguments (that's the @@ -221,35 +277,31 @@ Simple enough. Now compile and run: 818284590 yielding the number of seconds that elapsed between January 1, 1970 -(the beginning of the UNIX epoch), and the moment I began writing this +(the beginning of the Unix epoch), and the moment I began writing this sentence. -Note that in this particular case we are not required to call I, -however, in general it's considered good practice to ensure proper -initialization of library code including execution of all object C -methods and package C blocks. +In this particular case we don't have to call I, as we set +the PL_exit_flag PERL_EXIT_DESTRUCT_END which executes END blocks in +perl_destruct. -If you want to pass some arguments to the Perl subroutine, you may add -strings to the C terminated C list passed to I. -In order to pass arguments of another data type and/or examine return values -of the subroutine you'll need to manipulate the -Perl stack, demonstrated in the last section of this document: -L +If you want to pass arguments to the Perl subroutine, you can add +strings to the C-terminated C list passed to +I. For other data types, or to examine return values, +you'll need to manipulate the Perl stack. That's demonstrated in +L. =head2 Evaluating a Perl statement from your C program -One way to evaluate pieces of Perl code is to use L. -We have wrapped this function with our own I function, which -converts a command string to an SV, passing this and the L -flag to L. +Perl provides two API functions to evaluate pieces of Perl code. +These are L and L. -Arguably, this is the only routine you'll ever need to execute -snippets of Perl code from within your C program. Your string can be -as long as you wish; it can contain multiple statements; it can -include L, L and L to +Arguably, these are the only routines you'll ever need to execute +snippets of Perl code from within your C program. Your code can be as +long as you wish; it can contain multiple statements; it can employ +L, L, and L to include external Perl files. -Our I lets us evaluate individual Perl strings, and then +I lets us evaluate individual Perl strings, and then extract variables for coercion into C types. The following program, I, executes three Perl strings, extracting an C from the first, a C from the second, and a C from the third. @@ -259,38 +311,37 @@ the first, a C from the second, and a C from the third. static PerlInterpreter *my_perl; - I32 perl_eval(char *string) - { - return perl_eval_sv(newSVpv(string,0), G_DISCARD); - } - main (int argc, char **argv, char **env) { - char *embedding[] = { "", "-e", "0" }; - STRLEN length; + STRLEN n_a; + char *embedding[] = { "", "-e", "0" }; - my_perl = perl_alloc(); - perl_construct( my_perl ); + PERL_SYS_INIT3(&argc,&argv,&env); + 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 **/ - perl_eval("$a = 3; $a **= 2"); - printf("a = %d\n", SvIV(perl_get_sv("a", FALSE))); + perl_parse(my_perl, NULL, 3, embedding, NULL); + PL_exit_flags |= PERL_EXIT_DESTRUCT_END; + perl_run(my_perl); - /** Treat $a as a float **/ - perl_eval("$a = 3.14; $a **= 2"); - printf("a = %f\n", SvNV(perl_get_sv("a", FALSE))); + /** 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 string **/ - perl_eval("$a = 'rekcaH lreP rehtonA tsuJ'; $a = reverse($a); "); - printf("a = %s\n", SvPV(perl_get_sv("a", FALSE), length)); + /** Treat $a as a float **/ + eval_pv("$a = 3.14; $a **= 2", TRUE); + printf("a = %f\n", SvNV(get_sv("a", FALSE))); - perl_destruct(my_perl); - perl_free(my_perl); + /** Treat $a as a string **/ + eval_pv("$a = 'rekcaH lreP 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); + PERL_SYS_TERM(); } -All of those strange functions with I in their names help convert Perl scalars to C types. They're described in L. +All of those strange functions with I in their names help convert Perl scalars to C types. They're described in L and L. If you compile and run I, you'll see the results of using I to create an C, I to create a C, and @@ -300,179 +351,228 @@ I to create a string: a = 9.859600 a = Just Another Perl Hacker +In the example above, we've created a global variable to temporarily +store the computed value of our eval'd expression. It is also +possible and in most cases a better strategy to fetch the return value +from I instead. Example: + + ... + STRLEN n_a; + SV *val = eval_pv("reverse 'rekcaH lreP rehtonA tsuJ'", TRUE); + printf("%s\n", SvPV(val,n_a)); + ... + +This way, we avoid namespace pollution by not creating global +variables and we've simplified our code as well. =head2 Performing Perl pattern matches and substitutions from your C program -Our I lets us evaluate strings of Perl code, so we can +The I function lets us evaluate strings of Perl code, so we can define some functions that use it to "specialize" in matches and substitutions: I, I, and I. - char match(char *string, char *pattern); + I32 match(SV *string, char *pattern); -Given a string and a pattern (e.g., "m/clasp/" or "/\b\w*\b/", which in -your program might be represented as C<"/\\b\\w*\\b/">), +Given a string and a pattern (e.g., C or C, which +in your C program might appear as "/\\b\\w*\\b/"), match() returns 1 if the string matches the pattern and 0 otherwise. + int substitute(SV **string, char *pattern); - int substitute(char *string[], char *pattern); +Given a pointer to an C and an C<=~> operation (e.g., +C or C), substitute() modifies the string +within the C as according to the operation, returning the number of substitutions +made. -Given a pointer to a string and an "=~" operation (e.g., "s/bob/robert/g" or -"tr[A-Z][a-z]"), modifies the string according to the operation, -returning the number of substitutions made. + int matches(SV *string, char *pattern, AV **matches); - int matches(char *string, char *pattern, char **matches[]); - -Given a string, a pattern, and a pointer to an empty array of strings, -evaluates C<$string =~ $pattern> in an array context, and fills in -I with the array elements (allocating memory as it does so), -returning the number of matches found. +Given an C, a pattern, and a pointer to an empty C, +matches() evaluates C<$string =~ $pattern> in a list context, and +fills in I with the array elements, returning the number of matches found. Here's a sample program, I, that uses all three (long lines have been wrapped here): - #include - #include - static PerlInterpreter *my_perl; - I32 perl_eval(char *string) - { - return perl_eval_sv(newSVpv(string,0), G_DISCARD); - } - /** match(string, pattern) - ** - ** Used for matches in a scalar context. - ** - ** Returns 1 if the match was successful; 0 otherwise. - **/ - char match(char *string, char *pattern) - { - char *command; - command = malloc(sizeof(char) * strlen(string) + strlen(pattern) + 37); - sprintf(command, "$string = '%s'; $return = $string =~ %s", - string, pattern); - perl_eval(command); - free(command); - return SvIV(perl_get_sv("return", FALSE)); - } - /** substitute(string, pattern) - ** - ** Used for =~ operations that modify their left-hand side (s/// and tr///) - ** - ** Returns the number of successful matches, and - ** modifies the input string if there were any. - **/ - int substitute(char *string[], char *pattern) - { - char *command; - STRLEN length; - command = malloc(sizeof(char) * strlen(*string) + strlen(pattern) + 35); - sprintf(command, "$string = '%s'; $ret = ($string =~ %s)", - *string, pattern); - perl_eval(command); - free(command); - *string = SvPV(perl_get_sv("string", FALSE), length); - return SvIV(perl_get_sv("ret", FALSE)); - } - /** matches(string, pattern, matches) - ** - ** Used for matches in an array context. - ** - ** Returns the number of matches, - ** and fills in **matches with the matching substrings (allocates memory!) - **/ - int matches(char *string, char *pattern, char **match_list[]) - { - char *command; - SV *current_match; - AV *array; + #include + #include + + static PerlInterpreter *my_perl; + + /** my_eval_sv(code, error_check) + ** kinda like eval_sv(), + ** but we pop the return value off the stack + **/ + SV* my_eval_sv(SV *sv, I32 croak_on_error) + { + dSP; + SV* retval; + STRLEN n_a; + + PUSHMARK(SP); + eval_sv(sv, G_SCALAR); + + SPAGAIN; + retval = POPs; + PUTBACK; + + if (croak_on_error && SvTRUE(ERRSV)) + croak(SvPVx(ERRSV, n_a)); + + return retval; + } + + /** match(string, pattern) + ** + ** Used for matches in a scalar context. + ** + ** Returns 1 if the match was successful; 0 otherwise. + **/ + + I32 match(SV *string, char *pattern) + { + SV *command = newSV(0), *retval; + STRLEN n_a; + + sv_setpvf(command, "my $string = '%s'; $string =~ %s", + SvPV(string,n_a), pattern); + + retval = my_eval_sv(command, TRUE); + SvREFCNT_dec(command); + + return SvIV(retval); + } + + /** substitute(string, pattern) + ** + ** Used for =~ operations that modify their left-hand side (s/// and tr///) + ** + ** Returns the number of successful matches, and + ** modifies the input string if there were any. + **/ + + I32 substitute(SV **string, char *pattern) + { + SV *command = newSV(0), *retval; + STRLEN n_a; + + sv_setpvf(command, "$string = '%s'; ($string =~ %s)", + SvPV(*string,n_a), pattern); + + retval = my_eval_sv(command, TRUE); + SvREFCNT_dec(command); + + *string = get_sv("string", FALSE); + return SvIV(retval); + } + + /** matches(string, pattern, matches) + ** + ** Used for matches in a list context. + ** + ** Returns the number of matches, + ** and fills in **matches with the matching substrings + **/ + + I32 matches(SV *string, char *pattern, AV **match_list) + { + SV *command = newSV(0); I32 num_matches; - STRLEN length; - int i; - command = malloc(sizeof(char) * strlen(string) + strlen(pattern) + 38); - sprintf(command, "$string = '%s'; @array = ($string =~ %s)", - string, pattern); - perl_eval(command); - free(command); - array = perl_get_av("array", FALSE); - num_matches = av_len(array) + 1; /** assume $[ is 0 **/ - *match_list = (char **) malloc(sizeof(char *) * num_matches); - for (i = 0; i <= num_matches; i++) { - current_match = av_shift(array); - (*match_list)[i] = SvPV(current_match, length); - } + STRLEN n_a; + + sv_setpvf(command, "my $string = '%s'; @array = ($string =~ %s)", + SvPV(string,n_a), pattern); + + my_eval_sv(command, TRUE); + SvREFCNT_dec(command); + + *match_list = get_av("array", FALSE); + num_matches = av_len(*match_list) + 1; /** assume $[ is 0 **/ + return num_matches; - } - main (int argc, char **argv, char **env) - { + } + + main (int argc, char **argv, char **env) + { char *embedding[] = { "", "-e", "0" }; - char *text, **match_list; - int num_matches, i; - int j; + AV *match_list; + I32 num_matches, i; + SV *text; + STRLEN n_a; + + PERL_SYS_INIT3(&argc,&argv,&env); my_perl = perl_alloc(); - perl_construct( my_perl ); + perl_construct(my_perl); perl_parse(my_perl, NULL, 3, embedding, NULL); - perl_run(my_perl); - - text = (char *) malloc(sizeof(char) * 486); /** A long string follows! **/ - sprintf(text, "%s", "When he is at a convenience store and the bill \ - comes to some amount like 76 cents, Maynard is aware that there is \ - something he *should* do, something that will enable him to get back \ - a quarter, but he has no idea *what*. He fumbles through his red \ - squeezey changepurse and gives the boy three extra pennies with his \ - dollar, hoping that he might luck into the correct amount. The boy \ - gives him back two of his own pennies and then the big shiny quarter \ - that is his prize. -RICHH"); + PL_exit_flags |= PERL_EXIT_DESTRUCT_END; + + text = newSV(0); + sv_setpv(text, "When he is at a convenience store and the " + "bill comes to some amount like 76 cents, Maynard is " + "aware that there is something he *should* do, something " + "that will enable him to get back a quarter, but he has " + "no idea *what*. He fumbles through his red squeezey " + "changepurse and gives the boy three extra pennies with " + "his dollar, hoping that he might luck into the correct " + "amount. The boy gives him back two of his own pennies " + "and then the big shiny quarter that is his prize. " + "-RICHH"); + if (match(text, "m/quarter/")) /** Does text contain 'quarter'? **/ - printf("match: Text contains the word 'quarter'.\n\n"); + printf("match: Text contains the word 'quarter'.\n\n"); else - printf("match: Text doesn't contain the word 'quarter'.\n\n"); + printf("match: Text doesn't contain the word 'quarter'.\n\n"); + if (match(text, "m/eighth/")) /** Does text contain 'eighth'? **/ - printf("match: Text contains the word 'eighth'.\n\n"); + printf("match: Text contains the word 'eighth'.\n\n"); else - printf("match: Text doesn't contain the word 'eighth'.\n\n"); + printf("match: Text doesn't contain the word 'eighth'.\n\n"); + /** Match all occurrences of /wi../ **/ num_matches = matches(text, "m/(wi..)/g", &match_list); printf("matches: m/(wi..)/g found %d matches...\n", num_matches); + for (i = 0; i < num_matches; i++) - printf("match: %s\n", match_list[i]); + printf("match: %s\n", SvPV(*av_fetch(match_list, i, FALSE),n_a)); printf("\n"); - for (i = 0; i < num_matches; i++) { - free(match_list[i]); - } - free(match_list); + /** Remove all vowels from text **/ num_matches = substitute(&text, "s/[aeiou]//gi"); if (num_matches) { - printf("substitute: s/[aeiou]//gi...%d substitutions made.\n", - num_matches); - printf("Now text is: %s\n\n", text); + printf("substitute: s/[aeiou]//gi...%d substitutions made.\n", + num_matches); + printf("Now text is: %s\n\n", SvPV(text,n_a)); } + /** Attempt a substitution **/ if (!substitute(&text, "s/Perl/C/")) { - printf("substitute: s/Perl/C...No substitution made.\n\n"); + printf("substitute: s/Perl/C...No substitution made.\n\n"); } - free(text); + + SvREFCNT_dec(text); + PL_perl_destruct_level = 1; perl_destruct(my_perl); perl_free(my_perl); - } + PERL_SYS_TERM(); + } which produces the output (again, long lines have been wrapped here) - perl_match: Text contains the word 'quarter'. + match: Text contains the word 'quarter'. - perl_match: Text doesn't contain the word 'eighth'. + match: Text doesn't contain the word 'eighth'. - perl_matches: m/(wi..)/g found 2 matches... + matches: m/(wi..)/g found 2 matches... match: will match: with - perl_substitute: s/[aeiou]//gi...139 substitutions made. - Now text is: Whn h s t cnvnnc str nd th bll cms t sm mnt lk 76 cnts, + substitute: s/[aeiou]//gi...139 substitutions made. + Now text is: Whn h s t 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 n d *wht*. H fmbls thrgh hs rd sqzy chngprs nd gvs th by thr xtr pnns wth hs dllr, hpng tht h mght lck nt th crrct mnt. Th by gvs hm bck tw f hs wn pnns nd thn th bg shny qrtr tht s hs prz. -RCHH - perl_substitute: s/Perl/C...No substitution made. + substitute: s/Perl/C...No substitution made. =head2 Fiddling with the Perl stack from your C program @@ -485,14 +585,14 @@ results--the return value of your Perl subroutine--off the stack. First 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. They're described in L. +friends. They're described in L and L. Then you'll need to know how to manipulate the Perl stack. That's described in L. Once you've understood those, embedding Perl in C is easy. -Because C has no built-in function for integer exponentiation, let's +Because C has no builtin function for integer exponentiation, let's make Perl's ** operator available to it (this is less useful than it sounds, because Perl implements ** with C's I function). First I'll create a stub exponentiation function in I: @@ -518,11 +618,11 @@ deep breath... dSP; /* initialize stack pointer */ ENTER; /* everything created after here */ SAVETMPS; /* ...is a temporary variable. */ - PUSHMARK(sp); /* remember the stack pointer */ + 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 */ - perl_call_pv("expo", G_SCALAR); /* call the function */ + 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); @@ -533,21 +633,21 @@ deep breath... int main (int argc, char **argv, char **env) { - char *my_argv[2]; + char *my_argv[] = { "", "power.pl" }; + PERL_SYS_INIT3(&argc,&argv,&env); my_perl = perl_alloc(); perl_construct( my_perl ); - my_argv[1] = (char *) malloc(10); - sprintf(my_argv[1], "power.pl"); - - perl_parse(my_perl, NULL, argc, my_argv, NULL); + perl_parse(my_perl, NULL, 2, my_argv, (char **)NULL); + PL_exit_flags |= PERL_EXIT_DESTRUCT_END; perl_run(my_perl); PerlPower(3, 4); /*** Compute 3 ** 4 ***/ perl_destruct(my_perl); perl_free(my_perl); + PERL_SYS_TERM(); } @@ -561,86 +661,73 @@ Compile and run: =head2 Maintaining a persistent interpreter -When developing interactive, potentially long-running applications, it's -a good idea to maintain a persistent interpreter rather than allocating -and constructing a new interpreter multiple times. The major gain here is -speed, avoiding the penalty of Perl start-up time. However, a persistent -interpreter will require you to be more cautious in your use of namespace -and variable scoping. In previous examples we've been using global variables -in the default package B
. We knew exactly what code would be run, -making it safe to assume we'd avoid any variable collision or outrageous -symbol table growth. - -Let's say your application is a server, which must run perl code from an -arbitrary file during each transaction. Your server has no way of knowing -what code is inside anyone of these files. -If the file was pulled in by B, compiled into a newly -constructed interpreter, then cleaned out with B after the -the transaction, you'd be shielded from most namespace troubles. - -One way to avoid namespace collisions in this scenerio, is to translate the -file name into a valid Perl package name, which is most likely to be unique, -then compile the code into that package using L. -In the example below, each file will only be compiled once, unless it is -updated on disk. -Optionally, the application may choose to clean out the symbol table -associated with the file after we are done with it. We'll call the subroutine -B which lives in the file B, with -L, passing the filename and boolean cleanup/cache +When developing interactive and/or potentially long-running +applications, it's a good idea to maintain a persistent interpreter +rather than allocating and constructing a new interpreter multiple +times. The major reason is speed: since Perl will only be loaded into +memory once. + +However, you have to be more cautious with namespace and variable +scoping when using a persistent interpreter. In previous examples +we've been using global variables in the default package C
. We +knew exactly what code would be run, and assumed we could avoid +variable collisions and outrageous symbol table growth. + +Let's say your application is a server that will occasionally run Perl +code from some arbitrary file. Your server has no way of knowing what +code it's going to run. Very dangerous. + +If the file is pulled in by C, compiled into a newly +constructed interpreter, and subsequently cleaned out with +C afterwards, you're shielded from most namespace +troubles. + +One way to avoid namespace collisions in this scenario is to translate +the filename into a guaranteed-unique package name, and then compile +the code into that package using L. In the example +below, each file will only be compiled once. Or, the application +might choose to clean out the symbol table associated with the file +after it's no longer needed. Using L, We'll +call the subroutine C which lives in the +file C and pass the filename and boolean cleanup/cache flag as arguments. -Note that the process will continue to grow for each file that is compiled, -and each file it pulls in via L, L or -L. In addition, there maybe Bed subroutines and -other conditions that cause Perl's symbol table to grow. You may wish to -add logic which keeps track of process size or restarts itself after n number -of requests to ensure memory consumption is kept to a minimum. You also need -to consider the importance of variable scoping with L to futher -reduce symbol table growth. +Note that the process will continue to grow for each file that it +uses. In addition, there might be Ced subroutines and other +conditions that cause Perl's symbol table to grow. You might want to +add some logic that keeps track of the process size, or restarts +itself after a certain number of requests, to ensure that memory +consumption is minimized. You'll also want to scope your variables +with L whenever possible. + - package Embed::Persistent; #persistent.pl - + use strict; - use vars '%Cache'; - - #use Devel::Symdump (); - + our %Cache; + use Symbol qw(delete_package); + sub valid_package_name { my($string) = @_; $string =~ s/([^A-Za-z0-9\/])/sprintf("_%2x",unpack("C",$1))/eg; # second pass only for words starting with a digit $string =~ s|/(\d)|sprintf("/_%2x",unpack("C",$1))|eg; - + # Dress it up as a real package name $string =~ s|/|::|g; return "Embed" . $string; } - - #borrowed from Safe.pm - sub delete_package { - my $pkg = shift; - my ($stem, $leaf); - - no strict 'refs'; - $pkg = "main::$pkg\::"; # expand to full symbol table name - ($stem, $leaf) = $pkg =~ m/(.*::)(\w+::)$/; - - my $stem_symtab = *{$stem}{HASH}; - - delete $stem_symtab->{$leaf}; - } - + sub eval_file { my($filename, $delete) = @_; my $package = valid_package_name($filename); my $mtime = -M $filename; if(defined $Cache{$package}{mtime} && - $Cache{$package}{mtime} <= $mtime) + $Cache{$package}{mtime} <= $mtime) { - # we have compiled this subroutine already, + # we have compiled this subroutine already, # it has not been updated on disk, nothing left to do print STDERR "already compiled $package->handler\n"; } @@ -650,7 +737,7 @@ reduce symbol table growth. local($/) = undef; my $sub = ; close FH; - + #wrap the code into a subroutine inside our unique package my $eval = qq{package $package; sub handler { $sub; }}; { @@ -659,79 +746,86 @@ reduce symbol table growth. eval $eval; } die $@ if $@; - + #cache it unless we're cleaning out each time $Cache{$package}{mtime} = $mtime unless $delete; } - + eval {$package->handler;}; die $@ if $@; - + delete_package($package) if $delete; - + #take a look if you want #print Devel::Symdump->rnew($package)->as_string, $/; } - + 1; - + __END__ /* persistent.c */ - #include - #include - + #include + #include + /* 1 = clean out filename's symbol table after each request, 0 = don't */ #ifndef DO_CLEAN #define DO_CLEAN 0 #endif - - static PerlInterpreter *perl = NULL; - + + #define BUFFER_SIZE 1024 + + static PerlInterpreter *my_perl = NULL; + int main(int argc, char **argv, char **env) { char *embedding[] = { "", "persistent.pl" }; char *args[] = { "", DO_CLEAN, NULL }; - char filename [1024]; + char filename[BUFFER_SIZE]; int exitstatus = 0; - - if((perl = perl_alloc()) == NULL) { + STRLEN n_a; + + PERL_SYS_INIT3(&argc,&argv,&env); + if((my_perl = perl_alloc()) == NULL) { fprintf(stderr, "no memory!"); exit(1); } - perl_construct(perl); - - exitstatus = perl_parse(perl, NULL, 2, embedding, NULL); - - if(!exitstatus) { - exitstatus = perl_run(perl); - - while(printf("Enter file name: ") && gets(filename)) { - + perl_construct(my_perl); + + PL_origalen = 1; /* don't let $0 assignment update the proctitle or embedding[0] */ + exitstatus = perl_parse(my_perl, NULL, 2, embedding, NULL); + PL_exit_flags |= PERL_EXIT_DESTRUCT_END; + if(!exitstatus) { + exitstatus = perl_run(my_perl); + + while(printf("Enter file name: ") && + fgets(filename, BUFFER_SIZE, stdin)) { + + filename[strlen(filename)-1] = '\0'; /* strip \n */ /* call the subroutine, passing it the filename as an argument */ args[0] = filename; - perl_call_argv("Embed::Persistent::eval_file", + call_argv("Embed::Persistent::eval_file", G_DISCARD | G_EVAL, args); - + /* check $@ */ - if(SvTRUE(GvSV(errgv))) - fprintf(stderr, "eval error: %s\n", SvPV(GvSV(errgv),na)); + if(SvTRUE(ERRSV)) + fprintf(stderr, "eval error: %s\n", SvPV(ERRSV,n_a)); } } - - perl_destruct_level = 0; - perl_destruct(perl); - perl_free(perl); + + PL_perl_destruct_level = 0; + perl_destruct(my_perl); + perl_free(my_perl); + PERL_SYS_TERM(); exit(exitstatus); } - Now compile: - % cc -o persistent persistent.c `perl -MExtUtils::Embed -e ldopts` + % cc -o persistent persistent.c `perl -MExtUtils::Embed -e ccopts -e ldopts` -Here's a example script file: +Here's an example script file: #test.pl my $string = "hello"; @@ -751,93 +845,138 @@ Now run: foo says: hello Enter file name: ^C +=head2 Execution of END blocks + +Traditionally END blocks have been executed at the end of the perl_run. +This causes problems for applications that never call perl_run. Since +perl 5.7.2 you can specify C +to get the new behaviour. This also enables the running of END blocks if +the perl_parse fails and C will return the exit value. + +=head2 $0 assignments + +When a perl script assigns a value to $0 then the perl runtime will +try to make this value show up as the program name reported by "ps" by +updating the memory pointed to by the argv passed to perl_parse() and +also calling API functions like setproctitle() where available. This +behaviour might not be appropriate when embedding perl and can be +disabled by assigning the value C<1> to the variable C +before perl_parse() is called. + +The F example above is for instance likely to segfault +when $0 is assigned to if the C assignment is +removed. This because perl will try to write to the read only memory +of the C strings. + =head2 Maintaining multiple interpreter instances -The previous examples have gone through several steps to startup, use and -shutdown an embedded Perl interpreter. Certain applications may require -more than one instance of an interpreter to be created during the lifespan -of a single process. Such an application may take different approaches in -it's use of interpreter objects. For example, a particular transaction may -want to create an interpreter instance, then release any resources associated -with the object once the transaction is completed. When a single process -does this once, resources are released upon exit of the program and the next -time it starts, the interpreter's global state is fresh. - -In the same process, the program must take care to ensure that these -actions take place before constructing a new interpreter. By default, the -global variable C is set to C<0> since extra cleaning -is not needed when a program constructs a single interpreter, such as the -perl executable itself in C or some such. - -You can tell Perl to make everything squeeky clean by setting -C to C<1>. - - perl_destruct_level = 1; /* perl global variable */ +Some rare applications will need to create more than one interpreter +during a session. Such an application might sporadically decide to +release any resources associated with the interpreter. + +The program must take care to ensure that this takes place I +the next interpreter is constructed. By default, when perl is not +built with any special options, the global variable +C is set to C<0>, since extra cleaning isn't +usually needed when a program only ever creates a single interpreter +in its entire lifetime. + +Setting C to C<1> makes everything squeaky clean: + while(1) { ... - /* reset global variables here with perl_destruct_level = 1 */ - perl_contruct(my_perl); + /* reset global variables here with PL_perl_destruct_level = 1 */ + PL_perl_destruct_level = 1; + perl_construct(my_perl); ... /* clean and reset _everything_ during perl_destruct */ - perl_destruct(my_perl); /* ah, nice and fresh */ - perl_free(my_perl); + PL_perl_destruct_level = 1; + perl_destruct(my_perl); + perl_free(my_perl); ... /* let's go do it again! */ } -Now, when I is called, the interpreter's syntax parsetree -and symbol tables are cleaned out, along with reseting global variables. - -So, we've seen how to startup and shutdown an interpreter more than once -in the same process, but there was only one instance in existance at any -one time. Hmm, wonder if we can have more than one interpreter instance -running at the _same_ time? -Indeed this is possible, however when you build Perl, you must compile with -C<-DMULTIPLICITY>. - -It's a little tricky for the Perl runtime to handle multiple interpreters, -introducing some overhead that most programs with a single interpreter don't -get burdened with. When you compile with C<-DMULTIPLICITY>, by default, -C is set to C<1> for each interpreter. +When I is called, the interpreter's syntax parse tree +and symbol tables are cleaned up, and global variables are reset. The +second assignment to C is needed because +perl_construct resets it to C<0>. + +Now suppose we have more than one interpreter instance running at the +same time. This is feasible, but only if you used the Configure option +C<-Dusemultiplicity> or the options C<-Dusethreads -Duseithreads> when +building perl. By default, enabling one of these Configure options +sets the per-interpreter global variable C to +C<1>, so that thorough cleaning is automatic and interpreter variables +are initialized correctly. Even if you don't intend to run two or +more interpreters at the same time, but to run them sequentially, like +in the above example, it is recommended to build perl with the +C<-Dusemultiplicity> option otherwise some interpreter variables may +not be initialized correctly between consecutive runs and your +application may crash. + +Using C<-Dusethreads -Duseithreads> rather than C<-Dusemultiplicity> +is more appropriate if you intend to run multiple interpreters +concurrently in different threads, because it enables support for +linking in the thread libraries of your system with the interpreter. Let's give it a try: #include - #include - + #include /* we're going to embed two interpreters */ /* we're going to embed two interpreters */ - #define SAY_HELLO "-e", "print qq(Hi, I'm $^X\n)" - int main(int argc, char **argv, char **env) { - PerlInterpreter - *one_perl = perl_alloc(), - *two_perl = perl_alloc(); + 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(); + two_perl = perl_alloc(); + + PERL_SET_CONTEXT(one_perl); perl_construct(one_perl); + PERL_SET_CONTEXT(two_perl); perl_construct(two_perl); + PERL_SET_CONTEXT(one_perl); perl_parse(one_perl, NULL, 3, one_args, (char **)NULL); + PERL_SET_CONTEXT(two_perl); perl_parse(two_perl, NULL, 3, two_args, (char **)NULL); + PERL_SET_CONTEXT(one_perl); perl_run(one_perl); + PERL_SET_CONTEXT(two_perl); perl_run(two_perl); + PERL_SET_CONTEXT(one_perl); perl_destruct(one_perl); + PERL_SET_CONTEXT(two_perl); perl_destruct(two_perl); + PERL_SET_CONTEXT(one_perl); perl_free(one_perl); + PERL_SET_CONTEXT(two_perl); perl_free(two_perl); + PERL_SYS_TERM(); } +Note the calls to PERL_SET_CONTEXT(). These are necessary to initialize +the global state that tracks which interpreter is the "current" one on +the particular process or thread that may be running it. It should +always be used if you have more than one interpreter and are making +perl API calls on both interpreters in an interleaved fashion. + +PERL_SET_CONTEXT(interp) should also be called whenever C is +used by a thread that did not create it (using either perl_alloc(), or +the more esoteric perl_clone()). Compile as usual: @@ -873,21 +1012,14 @@ That's where the glue code can be inserted to create the initial contact between Perl and linked C/C++ routines. Let's take a look some pieces of I to see how Perl does this: + static void xs_init (pTHX); - #ifdef __cplusplus - # define EXTERN_C extern "C" - #else - # define EXTERN_C extern - #endif - - static void xs_init _((void)); - - EXTERN_C void boot_DynaLoader _((CV* cv)); - EXTERN_C void boot_Socket _((CV* cv)); + EXTERN_C void boot_DynaLoader (pTHX_ CV* cv); + EXTERN_C void boot_Socket (pTHX_ CV* cv); EXTERN_C void - xs_init() + xs_init(pTHX) { char *file = __FILE__; /* DynaLoader is a special case */ @@ -917,7 +1049,7 @@ Once you have this code, slap it into the second argument of I: Then compile: - % cc -o interp interp.c `perl -MExtUtils::Embed -e ldopts` + % cc -o interp interp.c `perl -MExtUtils::Embed -e ccopts -e ldopts` % interp use Socket; @@ -927,13 +1059,58 @@ Then compile: B can also automate writing the I glue code. - % perl -MExtUtils::Embed -e xsinit -o perlxsi.c + % perl -MExtUtils::Embed -e xsinit -- -o perlxsi.c % cc -c perlxsi.c `perl -MExtUtils::Embed -e ccopts` % cc -c interp.c `perl -MExtUtils::Embed -e ccopts` % cc -o interp perlxsi.o interp.o `perl -MExtUtils::Embed -e ldopts` -Consult L and L for more details. +Consult L, L, and L for more details. + +=head1 Embedding Perl under Win32 + +In general, all of the source code shown here should work unmodified under +Windows. + +However, there are some caveats about the command-line examples shown. +For starters, backticks won't work under the Win32 native command shell. +The ExtUtils::Embed kit on CPAN ships with a script called +B, which generates a simple makefile to build a program from +a single C source file. It can be used like this: + + C:\ExtUtils-Embed\eg> perl genmake interp.c + C:\ExtUtils-Embed\eg> nmake + C:\ExtUtils-Embed\eg> interp -e "print qq{I'm embedded in Win32!\n}" +You may wish to use a more robust environment such as the Microsoft +Developer Studio. In this case, run this to generate perlxsi.c: + + perl -MExtUtils::Embed -e xsinit + +Create a new project and Insert -> Files into Project: perlxsi.c, +perl.lib, and your own source files, e.g. interp.c. Typically you'll +find perl.lib in B, if not, you should see the +B directory relative to C. The studio will +also need this path so it knows where to find Perl include files. +This path can be added via the Tools -> Options -> Directories menu. +Finally, select Build -> Build interp.exe and you're ready to go. + +=head1 Hiding Perl_ + +If you completely hide the short forms forms of the Perl public API, +add -DPERL_NO_SHORT_NAMES to the compilation flags. This means that +for example instead of writing + + warn("%d bottles of beer on the wall", bottlecount); + +you will have to write the explicit full form + + Perl_warn(aTHX_ "%d bottles of beer on the wall", bottlecount); + +(See L.> ) Hiding the short forms is very useful for avoiding +all sorts of nasty (C preprocessor or otherwise) conflicts with other +software packages (Perl defines about 2400 APIs with these short names, +take or leave few hundred, so there certainly is room for conflict.) =head1 MORAL @@ -944,14 +1121,36 @@ each from the other, combine them as you wish. =head1 AUTHOR -Jon Orwant Forwant@media.mit.eduE>, -co-authored by Doug MacEachern Fdougm@osf.orgE>, -with contributions from -Tim Bunce, Tom Christiansen, Dov Grobgeld, and Ilya +Jon Orwant > and Doug MacEachern +>, with small contributions from Tim Bunce, Tom +Christiansen, Guy Decoux, Hallvard Furuseth, Dov Grobgeld, and Ilya Zakharevich. -June 17, 1996 - -Some of this material is excerpted from my book: I, -Waite Group Press, 1996 (ISBN 1-57169-064-6) and appears -courtesy of Waite Group Press. +Doug MacEachern has an article on embedding in Volume 1, Issue 4 of +The Perl Journal ( http://www.tpj.com/ ). Doug is also the developer of the +most widely-used Perl embedding: the mod_perl system +(perl.apache.org), which embeds Perl in the Apache web server. +Oracle, Binary Evolution, ActiveState, and Ben Sugars's nsapi_perl +have used this model for Oracle, Netscape and Internet Information +Server Perl plugins. + +=head1 COPYRIGHT + +Copyright (C) 1995, 1996, 1997, 1998 Doug MacEachern and Jon Orwant. All +Rights Reserved. + +Permission is granted to make and distribute verbatim copies of this +documentation provided the copyright notice and this permission notice are +preserved on all copies. + +Permission is granted to copy and distribute modified versions of this +documentation under the conditions for verbatim copying, provided also +that they are marked clearly as modified versions, that the authors' +names and title are unchanged (though subtitles and additional +authors' names may be added), and that the entire resulting derived +work is distributed under the terms of a permission notice identical +to this one. + +Permission is granted to copy and distribute translations of this +documentation into another language, under the above conditions for +modified versions.