Mailing List Archive

new perlembed
3c3
< perlembed - how to embed perl in your C or C++ app
---
> perlembed - how to embed perl in your C program
5c5,297
< =head1 DESCRIPTION
---
> =head1 PREAMBLE
>
> Do you want to:
>
> =over 5
>
> =item B<Use C from Perl?>
>
> Read L<perlcall> and L<perlxs>.
>
> =item B<Use a UNIX program from Perl?>
>
> Read about backquotes and L<perlfunc/system> and L<perlfunc/exec>.
>
> =item B<Use Perl from Perl?>
>
> Read about L<perlfunc/do> and L<perlfunc/eval> and L<perlmod/use>
> and L<perlmod/require>.
>
> =item B<Use C from C?>
>
> Rethink your design.
>
> =item B<Use Perl from C?>
>
> Read on...
>
> =back
>
> =head1 ROADMAP
>
> There's one example in each of the three sections:
>
> L<Adding a Perl interpreter to your C program>
>
> L<Calling a Perl subroutine from your C program>
>
> L<Fiddling with the Perl stack from your C program>
>
> This documentation is UNIX specific.
>
> =head1 EXPLANATION
>
> Every C program that uses Perl must link in the I<perl library>.
>
> 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</usr/bin/perl> or equivalent).
> (Corollary: you can't use Perl from C unless Perl has been compiled
> on your machine, or installed properly---that's why you shouldn't
> blithely copy Perl executables from machine to machine without also
> copying the I<lib> directory.)
>
> Your C program will---usually---allocate, "run", and deallocate a
> I<PerlInterpreter> object, which is defined in the perl library.
>
> =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<miniperlmain.c>,
> from the source distribution. Here's a bastardized version of
> I<miniperlmain.c> containing the essentials of embedding:
>
> #include <stdio.h>
> #include <EXTERN.h> /* from the Perl distribution */
> #include <perl.h> /* from the Perl distribution */
>
> static void xs_init _((void));
> static PerlInterpreter *my_perl; /*** The Perl interpreter ***/
>
> int main(int argc, char **argv, char **env)
> {
> int status;
>
> my_perl = perl_alloc();
> perl_construct(my_perl);
>
> status = perl_parse(my_perl, xs_init, argc, argv, env);
> if (status) exit(status);
>
> status = perl_run(my_perl);
> perl_destruct(my_perl);
> perl_free(my_perl);
>
> exit(status);
> }
>
> static void xs_init() {}
>
> If your copy of Perl is recent enough to contain this documentation
> (5.002 or later), then the perl library (and EXTERN.h and perl.h) will
> reside in a directory resembling this:
>
> /usr/local/lib/perl5/your_architecture_here/CORE
>
>
> Here's how you might compile the above program (say it's called I<interp.c>)
> on a DEC Alpha running the OSF operating system:
>
> % 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
>
> You'll have to choose the appropriate compiler (I<cc>, I<gcc>, et al.) and
> library directory (I</usr/local/lib/...>) 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 EXTERN.h or perl.h, you need
> to change the path following the -I.
>
> After a successful compilation, you'll be able to use I<interp> just
> like perl itself:
>
> % interp
> print "Pretty Good Perl \n";
> print "10890 - 9801 is ", 10890 - 9801;
> <CTRL-D>
> Pretty Good Perl
> 10890 - 9801 is 1089
>
> or
>
> % interp -e 'printf("%x", 3735928559)'
> deadbeef
>
> 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<argv[1]> before
> calling I<perl_run()>.
>
> =head2 Calling a Perl subroutine from your C program
>
> To call individual Perl subroutines, you'll need to remove the call to
> I<perl_run()> and replace it with a new function: I<perl_call_argv()>.
>
> That's shown below, in a program I'll call I<showtime.c>.
>
> #include <stdio.h>
> #include <EXTERN.h>
> #include <perl.h>
>
> static void xs_init _((void));
> static PerlInterpreter *my_perl;
>
> int main(int argc, char **argv, char **env)
> {
> int status;
>
> my_perl = perl_alloc();
> perl_construct(my_perl);
>
> status = perl_parse(my_perl, xs_init, argc, argv, env);
> if (status) exit(status);
>
> /*** This replaces perl_run() ***/
> perl_call_argv("showtime", G_DISCARD | G_NOARGS, argv);
> perl_destruct(my_perl);
> perl_free(my_perl);
>
> exit(status);
> }
>
> static void xs_init() {}
>
> where I<showtime> is a Perl subroutine that takes no arguments (that's the
> I<G_NOARGS>) and for which I'll ignore the return value (that's the
> I<G_DISCARD>). Those flags, and others, are discussed in L<perlcall>.
>
> I'll define the I<showtime> subroutine in a file called I<showtime.pl>:
>
> print "I shan't be printed.";
>
> sub showtime {
> print time;
> }
>
> Simple enough. Now compile and run:
>
> % cc -o showtime showtime.c -L/usr/local/lib/perl5/alpha-dec_osf/CORE
> -I/usr/local/lib/perl5/alpha-dec_osf/CORE -lperl -lm
>
> % showtime showtime.pl
> 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
> sentence.
>
> If you want to pass some arguments to the Perl subroutine, or
> you want to access the return value, you'll need to manipulate the
> Perl stack.
>
> =head2 Fiddling with the Perl stack from your C program
>
> When trying to explain stacks, most computer science textbooks 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.
>
> 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<perlguts>.
>
> Then you'll need to know how to manipulate the Perl stack. That's
> described in L<perlcall>.
>
> Once you've understood those, embedding Perl in C is easy.
>
> Since C has no built-in function for integer exponentiation, let's
> make Perl's ** operator available to it (although most Perl arithmetic
> is computed with double-precision floats anyway). First I'll create a
> stub exponentiation function in I<power.pl>:
>
> sub expo {
> my ($a, $b) = @_;
> return $a ** $b;
> }
>
> Now I'll create a C program, I<power.c>, with a function
> I<PerlPower()> that contains all the perlguts necessary to push the
> two arguments into I<expo()> and to pop the return value out. Take a
> deep breath...
>
> #include <stdio.h>
> #include <EXTERN.h>
> #include <perl.h>
>
> static void xs_init _((void));
> static PerlInterpreter *my_perl;
>
> 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 */
> perl_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[2];
>
> my_perl = perl_alloc();
> perl_construct( my_perl );
>
> my_argv[1] = (char *) malloc(10);
> sprintf(my_argv[1], "power.pl");
>
> perl_parse(my_perl, xs_init, argc, my_argv, env);
>
> PerlPower(3, 4); /*** Compute 3 ** 4 ***/
>
> perl_destruct(my_perl);
> perl_free(my_perl);
> }
>
> static void xs_init() {}
>
> Compile and run:
>
> % cc -o power power.c -L/usr/local/lib/perl5/alpha-dec_osf/CORE
> -I/usr/local/lib/perl5/alpha-dec_osf/CORE -lperl -lm
>
> % power power.pl
> 3 to the 4th power is 81.
>
>
> MORAL: you can sometimes L<write faster code> in C, but
> you can always L<write code faster> in Perl. Since you can use
> each from the other, combine them as you wish.
>
>
> =head1 AUTHOR
>
> Jon Orwant
>
> L<orwant@media.mit.edu>
>
> December 12, 1995
>
> Some of this material is excerpted from my book: I<Perl 5 Interactive>, Waite
> Group Press, 1996. ISBN 1-57169-064-6.
7d298
< Look at perlmain.c, and do something like that.
Re: new perlembed [ In reply to ]
Jon Orwant writes:
> > from the source distribution. Here's a bastardized version of
> > I<miniperlmain.c> containing the essentials of embedding:
> >
> > #include <stdio.h>

Hmm, not here!

Ilya
new perlembed [ In reply to ]
Very nice job with the perlembed pod. Indeed it has been needed.
May I suggest that you also add a paragraph describing how you
do "perl-eval" of a string from C. It was one of the first questions
that hit me when I looked at embedding Perl some time ago.

Here's a suggestion of such a paragraph. Feel free to mangle it and
change it any way you want. English isn't my native language after all.

=head2 How do I evaluate a string from C?

There is no direct intrinsic call to evaluate a Perl string from
within C. One way of doing this is by declaring a perl function C<c_eval>,
which takes it's first parameter and evaluates it; basically a
wrapper for eval.

This is really the only routine you need inside an application
embedding Perl, since additional libraries may then be included
with a C<require> statement. Therefore C<c_eval> may declared as
parameters to C<perl_parse>. This may be done by declaring the
static array:

char *embedding[] = { "", "-e", "sub _eval_ { eval $_[0] }" };

and the following C routine C<perl_eval> in the C program:

int perl_eval(char *s)
{
char *argv[2];
argv[0]=s;
argv[1]=NULL;
perl_call_argv("_eval_", 0,argv);
}

When C<perl_parse> is called it includes the is passed the static
array C<embedding>:

perl_parse( my_perl, NULL, 3, embedding, env );

It is now simple to evaluate individual strings from within C. Just
send the string to perl_eval:

perl_eval("$a = 3.14; $a**= 2;");
printf("a = %f\n", SvNV( perl_get_sv("a", FALSE) );


s
Re: new perlembed [ In reply to ]
Very nice job with the perlembed pod. Indeed it has been needed.
May I suggest that you also add a paragraph describing how you
do "perl-eval" of a string from C. It was one of the first questions
that hit me when I looked at embedding Perl some time ago.

Here's a suggestion of such a paragraph. Feel free to mangle it and
change it any way you want. English isn't my native language after all.

=head2 How do I evaluate a string from C?

There is no direct intrinsic call to evaluate a Perl string from
within C. One way of doing this is by declaring a perl function C<c_eval>,
which takes it's first parameter and evaluates it; basically a
wrapper for eval.

This is really the only routine you need inside an application
embedding Perl, since additional libraries may then be included
with a C<require> statement. Therefore C<c_eval> may declared as
parameters to C<perl_parse>. This may be done by declaring the
static array:

char *embedding[] = { "", "-e", "sub _eval_ { eval $_[0] }" };

and the following C routine C<perl_eval> in the C program:

int perl_eval(char *s)
{
char *argv[2];
argv[0]=s;
argv[1]=NULL;
perl_call_argv("_eval_", 0,argv);
}

When C<perl_parse> is called it includes the is passed the static
array C<embedding>:

perl_parse( my_perl, NULL, 3, embedding, env );

It is now simple to evaluate individual strings from within C. Just
send the string to perl_eval:

perl_eval("$a = 3.14; $a**= 2;");
printf("a = %f\n", SvNV( perl_get_sv("a", FALSE) );

--
___
Dov Grobgeld | Email: dov@orbotech.co.il /+ \ PCB
Algorithms Department, Orbotech | Phone: +972-8-9423566 \ +/ AOI
Yavne, Israel | __| |
Disclaimer: All views above are mine alone. ____|


s
Re: new perlembed [ In reply to ]
GREAT STUFF!

Coupla suggestions: first, do a 1,$s/---/--/g to make the pod xlators
happy. Second is to include an example of a perl_match and a
perl_substitute function.

Kinda like

char **perl_match(char *old_string, char *pattern);
char **matches;
if (matches = perl_match(s, "foo(.*?)bar") {
printf("match of %s\n", matches[0]);
}


Unless you want matches[0] to be the count or something so $1
would be in matches[1].

Similarly for a perl_substitute. Hm.. I wonder whether you
should always pass in strings or compiled regexps?

--tom
Re: new perlembed [ In reply to ]
> From: dov.grobgeld@Orbotech.Co.IL (Dov Grobgeld)
>
> Very nice job with the perlembed pod. Indeed it has been needed.
> May I suggest that you also add a paragraph describing how you
> do "perl-eval" of a string from C. It was one of the first questions
> that hit me when I looked at embedding Perl some time ago.

> =head2 How do I evaluate a string from C?
>
> There is no direct intrinsic call to evaluate a Perl string from
> within C. One way of doing this is by declaring a perl function C<c_eval>,
> which takes it's first parameter and evaluates it; basically a
> wrapper for eval.

Larry has snuck this into 5.002 perl.c:

/* Eval a string. */

I32
perl_eval_sv(sv, flags)

Thanks Larry!

Does anyone have time to document it? Probably belongs in perlapi with
a reference in perlembed.

Tim.
Re: new perlembed [ In reply to ]
>Larry has snuck this into 5.002 perl.c:

> /* Eval a string. */

> I32
> perl_eval_sv(sv, flags)

>Thanks Larry!

>Does anyone have time to document it? Probably belongs in perlapi with
>a reference in perlembed.


Very cool. But it wold be even neater if LArry could doc is prototype
stuff. Or maybe I'll just make a mail-from-larry-2-pod translator. :-)

--tom

ps: did you guys see the suggestion that a perl compiler (to native, to byte
code, or to java vm byte code) should have as its first mission to utter the
phrase "Hello, Larry!"? seemed amusing.)
Re: new perlembed [ In reply to ]
> From: Jon Orwant <orwant@fahrenheit-451.media.mit.edu>
>
> > =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<miniperlmain.c>,
> > from the source distribution. Here's a bastardized version of
> > I<miniperlmain.c> containing the essentials of embedding:

> > int main(int argc, char **argv, char **env)
> > {
> > int status;
> >
> > my_perl = perl_alloc();
> > perl_construct(my_perl);
> >
> > status = perl_parse(my_perl, xs_init, argc, argv, env);

Take out the 'env's from all the examples:

> > int main(int argc, char **argv)

> > status = perl_parse(my_perl, xs_init, argc, argv, NULL);

as per the current 5.002. (It's a subtle issue but without that -d:Foo
could core dump).

> > Here's how you might compile the above program (say it's called I<interp.c>)
> > on a DEC Alpha running the OSF operating system:
> >
> > % 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

Umm, I think various libs recorded in config.sh need to be added here
depending on the platform.

Mine says libs='-lsocket -lnsl -ldb -ldl -lm -lc -lcrypt' so I'd guess
that the cc line sould be

% cc -o interp interp.c -L/usr/local/lib/perl5/alpha-dec_osf/CORE
-I/usr/local/lib/perl5/alpha-dec_osf/CORE -lperl
-lsocket -lnsl -ldb -ldl -lm -lc -lcrypt

(We should think about providing some support for this somehow.)

I'll just mention that Config.pm now supports an easier way to do this:

$ eval `perl -e 'use Config; print Config::config_sh'`
$ $cc -o interp interp.c -L$archlib/CORE -I$archlib/CORE -lperl $libs

Note the use of the bourne shell. Note also the fact that you have to
load the entire config.

Here's a small patch which I commend to the porters:

$ diff -c1 ./configpm.* ./configpm
*** ./configpm.b1f Wed Dec 13 14:31:24 1995
--- ./configpm Wed Dec 13 15:55:02 1995
***************
*** 178,180 ****

! sub config_sh { $config_sh }

--- 178,182 ----

! sub config_sh { $config_sh }
! sub config_csh { "set ".join("\nset ",split(/\n/,$config_sh))."\n" }
! sub config_vars { my $prefix=shift; foreach(@_){ print "$prefix$_='$Config{$_}';\n" } }

config_vars lets you say thinsg like:

$ eval `perl -e 'use Config; Config::config_vars("", qw(libs, libpth))'`

The prefix variable lets you add a "set " for csh users.

Tim.
Re: new perlembed [ In reply to ]
Tim Bunce writes:
> % cc -o interp interp.c -L/usr/local/lib/perl5/alpha-dec_osf/CORE
> -I/usr/local/lib/perl5/alpha-dec_osf/CORE -lperl
> -lsocket -lnsl -ldb -ldl -lm -lc -lcrypt
>
> (We should think about providing some support for this somehow.)
>

Easy,
$self->embed if defined $self->{EMBED};
Here
sub embed {
<<EOE;

EMBEDDED = \\?\\?\\?

embed: $(EMBEDDED)$exe_ext

$(EMBEDDED)$exe_ext: and so on

EOE
}

So you call it like
make embed EMBEDDED=mymain

Or, in fact,
make embed
may call
make perl PERLMAIN=mymain MAINFLAGS= MAINLIBS=-lmylib

with minimal mods to perl-ish targets. If prototypes are in 5.002, the
working version will follow soon.

Ilya