📄 perlembed.pod
字号:
#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[BUFFER_SIZE]; int exitstatus = 0; STRLEN n_a; PERL_SYS_INIT3(&argc,&argv,&env); if((my_perl = perl_alloc()) == NULL) { fprintf(stderr, "no memory!"); exit(1); } 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; call_argv("Embed::Persistent::eval_file", G_DISCARD | G_EVAL, args); /* check $@ */ if(SvTRUE(ERRSV)) fprintf(stderr, "eval error: %s\n", SvPV(ERRSV,n_a)); } } 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 ccopts -e ldopts`Here's an example script file: #test.pl my $string = "hello"; foo($string); sub foo { print "foo says: @_\n"; }Now run: % persistent Enter file name: test.pl foo says: hello Enter file name: test.pl already compiled Embed::test_2epl->handler foo says: hello Enter file name: ^C=head2 Execution of END blocksTraditionally END blocks have been executed at the end of the perl_run.This causes problems for applications that never call perl_run. Sinceperl 5.7.2 you can specify C<PL_exit_flags |= PERL_EXIT_DESTRUCT_END>to get the new behaviour. This also enables the running of END blocks ifthe perl_parse fails and C<perl_destruct> will return the exit value.=head2 $0 assignmentsWhen a perl script assigns a value to $0 then the perl runtime willtry to make this value show up as the program name reported by "ps" byupdating the memory pointed to by the argv passed to perl_parse() andalso calling API functions like setproctitle() where available. Thisbehaviour might not be appropriate when embedding perl and can bedisabled by assigning the value C<1> to the variable C<PL_origalen>before perl_parse() is called.The F<persistent.c> example above is for instance likely to segfaultwhen $0 is assigned to if the C<PL_origalen = 1;> assignment isremoved. This because perl will try to write to the read only memoryof the C<embedding[]> strings.=head2 Maintaining multiple interpreter instancesSome rare applications will need to create more than one interpreterduring a session. Such an application might sporadically decide torelease any resources associated with the interpreter.The program must take care to ensure that this takes place I<before>the next interpreter is constructed. By default, when perl is notbuilt with any special options, the global variableC<PL_perl_destruct_level> is set to C<0>, since extra cleaning isn'tusually needed when a program only ever creates a single interpreterin its entire lifetime.Setting C<PL_perl_destruct_level> to C<1> makes everything squeaky clean: while(1) { ... /* 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 */ PL_perl_destruct_level = 1; perl_destruct(my_perl); perl_free(my_perl); ... /* let's go do it again! */ }When I<perl_destruct()> is called, the interpreter's syntax parse treeand symbol tables are cleaned up, and global variables are reset. Thesecond assignment to C<PL_perl_destruct_level> is needed becauseperl_construct resets it to C<0>.Now suppose we have more than one interpreter instance running at thesame time. This is feasible, but only if you used the Configure optionC<-Dusemultiplicity> or the options C<-Dusethreads -Duseithreads> whenbuilding perl. By default, enabling one of these Configure optionssets the per-interpreter global variable C<PL_perl_destruct_level> toC<1>, so that thorough cleaning is automatic and interpreter variablesare initialized correctly. Even if you don't intend to run two ormore interpreters at the same time, but to run them sequentially, likein the above example, it is recommended to build perl with theC<-Dusemultiplicity> option otherwise some interpreter variables maynot be initialized correctly between consecutive runs and yourapplication may crash.See also L<perlxs/Thread-aware system interfaces>.Using C<-Dusethreads -Duseithreads> rather than C<-Dusemultiplicity>is more appropriate if you intend to run multiple interpretersconcurrently in different threads, because it enables support forlinking in the thread libraries of your system with the interpreter.Let's give it a try: #include <EXTERN.h> #include <perl.h> /* 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, *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 initializethe global state that tracks which interpreter is the "current" one onthe particular process or thread that may be running it. It shouldalways be used if you have more than one interpreter and are makingperl API calls on both interpreters in an interleaved fashion.PERL_SET_CONTEXT(interp) should also be called whenever C<interp> isused by a thread that did not create it (using either perl_alloc(), orthe more esoteric perl_clone()).Compile as usual: % cc -o multiplicity multiplicity.c `perl -MExtUtils::Embed -e ccopts -e ldopts`Run it, Run it: % multiplicity Hi, I'm one_perl Hi, I'm two_perl=head2 Using Perl modules, which themselves use C libraries, from your C programIf you've played with the examples above and tried to embed a scriptthat I<use()>s a Perl module (such as I<Socket>) which itself uses a C or C++ library,this probably happened: Can't load module Socket, dynamic loading not available in this perl. (You may need to build a new perl executable which either supports dynamic loading or has the Socket module statically linked into it.)What's wrong?Your interpreter doesn't know how to communicate with these extensionson its own. A little glue will help. Up until now you've beencalling I<perl_parse()>, handing it NULL for the second argument: perl_parse(my_perl, NULL, argc, my_argv, NULL);That's where the glue code can be inserted to create the initial contact betweenPerl and linked C/C++ routines. Let's take a look some pieces of I<perlmain.c>to see how Perl does this: static void xs_init (pTHX); EXTERN_C void boot_DynaLoader (pTHX_ CV* cv); EXTERN_C void boot_Socket (pTHX_ CV* cv); EXTERN_C void xs_init(pTHX) { char *file = __FILE__; /* DynaLoader is a special case */ newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file); newXS("Socket::bootstrap", boot_Socket, file); }Simply put: for each extension linked with your Perl executable(determined during its initial configuration on yourcomputer or when adding a new extension),a Perl subroutine is created to incorporate the extension'sroutines. Normally, that subroutine is namedI<Module::bootstrap()> and is invoked when you say I<use Module>. Inturn, this hooks into an XSUB, I<boot_Module>, which creates a Perlcounterpart for each of the extension's XSUBs. Don't worry about thispart; leave that to the I<xsubpp> and extension authors. If yourextension is dynamically loaded, DynaLoader creates I<Module::bootstrap()>for you on the fly. In fact, if you have a working DynaLoader then thereis rarely any need to link in any other extensions statically.Once you have this code, slap it into the second argument of I<perl_parse()>: perl_parse(my_perl, xs_init, argc, my_argv, NULL);Then compile: % cc -o interp interp.c `perl -MExtUtils::Embed -e ccopts -e ldopts` % interp use Socket; use SomeDynamicallyLoadedModule; print "Now I can use extensions!\n"'B<ExtUtils::Embed> can also automate writing the I<xs_init> glue code. % 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<perlxs>, L<perlguts>, and L<perlapi> for more details.=head1 Embedding Perl under Win32In general, all of the source code shown here should work unmodified underWindows.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 calledB<genmake>, which generates a simple makefile to build a program froma 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 MicrosoftDeveloper Studio. In this case, run this to generate perlxsi.c: perl -MExtUtils::Embed -e xsinitCreate a new project and Insert -> Files into Project: perlxsi.c,perl.lib, and your own source files, e.g. interp.c. Typically you'llfind perl.lib in B<C:\perl\lib\CORE>, if not, you should see theB<CORE> directory relative to C<perl -V:archlib>. The studio willalso 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 thatfor 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<perlguts/Background and PERL_IMPLICIT_CONTEXT for the explanationof the C<aTHX_>.> ) Hiding the short forms is very useful for avoidingall sorts of nasty (C preprocessor or otherwise) conflicts with othersoftware packages (Perl defines about 2400 APIs with these short names,take or leave few hundred, so there certainly is room for conflict.)=head1 MORALYou can sometimes I<write faster code> in C, butyou can always I<write code faster> in Perl. Because you can useeach from the other, combine them as you wish.=head1 AUTHORJon Orwant <F<orwant@media.mit.edu>> and Doug MacEachern<F<dougm@covalent.net>>, with small contributions from Tim Bunce, TomChristiansen, Guy Decoux, Hallvard Furuseth, Dov Grobgeld, and IlyaZakharevich.Doug MacEachern has an article on embedding in Volume 1, Issue 4 ofThe Perl Journal ( http://www.tpj.com/ ). Doug is also the developer of themost 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_perlhave used this model for Oracle, Netscape and Internet InformationServer Perl plugins.=head1 COPYRIGHTCopyright (C) 1995, 1996, 1997, 1998 Doug MacEachern and Jon Orwant. AllRights Reserved.Permission is granted to make and distribute verbatim copies of thisdocumentation provided the copyright notice and this permission notice arepreserved on all copies.Permission is granted to copy and distribute modified versions of thisdocumentation under the conditions for verbatim copying, provided alsothat they are marked clearly as modified versions, that the authors'names and title are unchanged (though subtitles and additionalauthors' names may be added), and that the entire resulting derivedwork is distributed under the terms of a permission notice identicalto this one.Permission is granted to copy and distribute translations of thisdocumentation into another language, under the above conditions formodified versions.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -