Embedding Perl in C and
 the other way around




      Marian Marinov(mm@1h.com
                  
            Co-Founder and CIO of 1H Ltd.
Embedding C in Perl




              
The XS way...

       It cannot be seen, cannot be felt,
     Cannot be heard, cannot be smelt.
    It lies behind stars and under hills,
             And empty holes it fills.
                  - J.R.R. Tolkien, The Hobbit


    Answer: dark.

                         
XS Docs

● perlman:perlxstut
● man perlxs

● man perlguts

● man perlapi

● man h2xs




                       
XS Basics
● SV – Scalar Value                 SV*   newSVsv(SV*);
● AV  – Array Value
● HV  – Hash Value
● IV  – Integer Value               SV*   newSViv(IV);
● UV  – Unsigned Integer Value      SV*   newSVuv(UV);
● NV  – Double Value                SV*   newSVnv(double);
● PV  – String Value
●SV* newSVpv(const char*, STRLEN);

●SV* newSVpvn(const char*, STRLEN);

●SV* newSVpvf(const char*, ...);




    SvIV(SV*)
    SvUV(SV*)
    SvNV(SV*)
    SvPV(SV*, STRLEN len)
    SvPV_nolen(SV*)
                                
Inline::C
$ cat inline.pl
#!/usr/bin/perl
use Inline C=>'
void some_func() {
        printf("Hello Worldn");
}';
&some_func

$ ./inline.pl
Hello World

Examples from Inline::C-Cookbook
                     
fun way of using Inline::C

$ cat perl­sign.pl 
#!/usr/bin/perl 
use Inline C=>'
void C() {
    int m,u,e=0;float l,_,I;
    for(;1840­e;putchar((++e>907&&942>e?61­m:u)
["n)moc.isc@rezneumb(rezneuM drahnreB"]))
        for(u=_=l=0;79­(m=e%80)&&I*l+_*_<6&&26­+
+u;_=2*l*_+e/80*.09­1,l=I)
            I=l*l­_*_­2+m/27.;
    }';
&C
                             
mmmmmmmmooooooooooooooooooooooooocccccccccc....is@zrre i.cccccccoooooooooommmmm
mmmmmmoooooooooooooooooooooooccccccccccc.....iiscrr n@csi...ccccccoooooooooommm
mmmmooooooooooooooooooooooccccccccccc....iiiss@n     zMesii....cccccoooooooooom
mmooooooooooooooooooooocccccccccc....iisssssc@rn      erccsiiiii..ccccooooooooo
moooooooooooooooooocccccccc.......iis@e uMeu r          e r@@@ezs..cccoooooooo
oooooooooooooooccccccc.........iiiisc@z                     e   eci..cccooooooo
ooooooooooccccccc..iiiiiiiiiiiiisscz z                         z@sii.ccccoooooo
oooooccccccccc...iicz@ccccz@ccccccrrr                              s..cccoooooo
ooocccccccc.....iisc@eb     bnneree                              eci..ccccooooo
occcccccc.....iisccrnb           m                               nci..ccccooooo
ccc....iiiiisss@emee(                                            cii..cccccoooo
iscc@@beremeene(           Bernhard Muenzer(bmuenzer@csi.com) ercsi...cccccoooo
c....iiiiiisssc@e rnz                                           esi...cccccoooo
occccccc....iiiscc@rb            (                               esi..ccccooooo
oocccccccc......iisc@z        bneze                              z@i..ccccooooo
ooooocccccccc....ii@er@@@@nr@cccc@e                               es..cccoooooo
oooooooooccccccc...@siiiiiiiiisssscnM                          urcsi..cccoooooo
ooooooooooooooccccccc..........iiiisc@e                         zsi..cccooooooo
mooooooooooooooooocccccccc.......iiis@    nu               er eznri.cccoooooooo
mmoooooooooooooooooooocccccccccc....issc@ccc@@rn      er@cssiiiss..cccooooooooo
mmmmoooooooooooooooooooooccccccccccc....iiiisc@z      rrsii.....ccccoooooooooom
mmmmmooooooooooooooooooooooocccccccccccc....iis@rz rrcsi....ccccccoooooooooomm
mmmmmmmmoooooooooooooooooooooooocccccccccc....iisceeeusi..cccccccooooooooommmmm

                                         
Multiple Return Values

print map {"$_n"} get_localtime(time);

use Inline C => <<'END_OF_C_CODE';

#include <time.h>
void get_localtime(int utc) {
   struct tm *ltime = localtime(&utc);
   Inline_Stack_Vars;
   Inline_Stack_Reset;

        Inline_Stack_Push(sv_2mortal(newSViv(ltime->tm_year)));
        Inline_Stack_Push(sv_2mortal(newSViv(ltime->tm_mon)));
        Inline_Stack_Push(sv_2mortal(newSViv(ltime->tm_mday)));
        Inline_Stack_Push(sv_2mortal(newSViv(ltime->tm_hour)));
        Inline_Stack_Push(sv_2mortal(newSViv(ltime->tm_min)));
        Inline_Stack_Push(sv_2mortal(newSViv(ltime->tm_sec)));
        Inline_Stack_Push(sv_2mortal(newSViv(ltime->tm_isdst)));
        Inline_Stack_Done;
}
                                       
END_OF_C_CODE
Variable Argument Lists


greet(qw(Sarathy Jan Sparky Murray Mike));

use Inline C => <<'END_OF_C_CODE';
void greet(SV* name1, ...) {
  Inline_Stack_Vars;
  int i;

  for (i = 0; i < Inline_Stack_Items; i++)
    printf("Hello %s!n",
       SvPV(Inline_Stack_Item(i), PL_na));

  Inline_Stack_Void;
}
END_OF_C_CODE
                         
Another way of using Inline::C


use Inline C;

$vp = string_scan($text);      # call our function

__END__
__C__
/*
 * Our C code goes here
 */
int string_scan(char* str) {

}
                         
Embedding Perl in C




              
How you can do it?


● ExtUtils::Embed
      perl -MExtUtils::Embed -e ccopts -e ldopts
● B::C

● The only way... XS




                          
Docs


man   perlembed
man   perlcall
man   perlguts
man   perlapi
man   perlxs



                    
B::C/perlcc
●   Works with Perl 5.6.0
●   Works with Perl 5.13.x

#!/usr/bin/perl
use strict;
use warnings;
use lib '.';
use parse_config;

my $a = 'some text';
my $b = 13;
my %config = parse_config('/etc/guardian.conf');
#my %config = ( df => 13, hj => 18);
printf "%s %dn", $a, $b;
while (my ($k,$v) = each %config) {
        print "$k :: $vn";
}
                                 
$ perlcc -o em em.pl
$ ./em
Segmentation fault

$ perlcc -o em em.pl
$ ./em
some text 13
df :: 13
hj :: 18




                        
#include "embed.h"

int main (int argc, char **argv, char **env) {
        char *embedding[] = { "", "-e", "0" };
        unsigned char *perlPlain;
        size_t len = 0;
        int err = 0;

        PERL_SYS_INIT3(&argc,&argv,&env);
        my_perl = perl_alloc();
        perl_construct( my_perl );

        perl_parse(my_perl, xs_init, 3, embedding, NULL);
        PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
        perl_run(my_perl);

        perlPlain=spc_base64_decode(&perl64,&len,0,&err);
        eval_pv(perlPlain, TRUE);

        perl_destruct(my_perl);
        perl_free(my_perl);
        PERL_SYS_TERM();
        return 0;
                                   
}
#ifndef _EMBED_H
#define _EMBED_H
#include <EXTERN.h>
#include <perl.h>
#include "base64.h"
#include "code_64.h"

static PerlInterpreter *my_perl;
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);
}

#endif

                                    
$ ./embed --version

This is perl, v5.10.1 (*) built for i386-linux-thread-multi

Copyright 1987-2009, Larry Wall

Perl may be copied only under the terms of either the Artistic
License or the
GNU General Public License, which may be found in the Perl 5
source kit.

Complete documentation for Perl, including FAQ lists, should be
found on
this system using "man perl" or "perldoc perl". If you have
access to the
Internet, point your browser at http://www.perl.org/, the Perl
Home Page.



                                   
# perl -MExtUtils::Embed -e ccopts -e ldopts
-Wl,-E -Wl,-rpath,/usr/lib/perl5/5.8.8/i386-linux-thread-
multi/CORE -L/usr/local/lib /usr/lib/perl5/5.8.8/i386-linux-
thread-multi/auto/DynaLoader/DynaLoader.a
-L/usr/lib/perl5/5.8.8/i386-linux-thread-multi/CORE -lperl
-lresolv -lnsl -ldl -lm -lcrypt -lutil -lpthread -lc
 -D_REENTRANT -D_GNU_SOURCE -fno-strict-aliasing -pipe
-Wdeclaration-after-statement -I/usr/local/include
-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/include/gdbm
-I/usr/lib/perl5/5.8.8/i386-linux-thread-multi/CORE

# gcc -o embed embed.c $(perl -MExtUtils::Embed -e ccopts -e
ldopts)




                                 
call_argv("showtime", G_DISCARD | G_NOARGS, args);

                             vs.

      eval_pv(perlPlain, TRUE);


    /** Treat $a as an integer **/
      eval_pv("$a = 3; $a **= 2", TRUE);
      printf("a = %dn", SvIV(get_sv("a", 0)));

    /** Treat $a as a float **/
      eval_pv("$a = 3.14; $a **= 2", TRUE);
      printf("a = %fn", SvNV(get_sv("a", 0)));

 /** Treat $a as a string **/
   eval_pv("$a = 'rekcaH lreP rehtonA tsuJ'; $a = reverse($a);",
TRUE);
   printf("a = %sn", SvPV_nolen(get_sv("a", 0)));

                                    

Embedding perl

  • 1.
    Embedding Perl inC and the other way around   Marian Marinov(mm@1h.com   Co-Founder and CIO of 1H Ltd.
  • 2.
  • 3.
    The XS way... It cannot be seen, cannot be felt, Cannot be heard, cannot be smelt. It lies behind stars and under hills, And empty holes it fills. - J.R.R. Tolkien, The Hobbit Answer: dark.    
  • 4.
    XS Docs ● perlman:perlxstut ●man perlxs ● man perlguts ● man perlapi ● man h2xs    
  • 5.
    XS Basics ● SV– Scalar Value SV* newSVsv(SV*); ● AV – Array Value ● HV – Hash Value ● IV – Integer Value SV* newSViv(IV); ● UV – Unsigned Integer Value SV* newSVuv(UV); ● NV – Double Value SV* newSVnv(double); ● PV – String Value ●SV* newSVpv(const char*, STRLEN); ●SV* newSVpvn(const char*, STRLEN); ●SV* newSVpvf(const char*, ...); SvIV(SV*) SvUV(SV*) SvNV(SV*) SvPV(SV*, STRLEN len) SvPV_nolen(SV*)    
  • 6.
    Inline::C $ cat inline.pl #!/usr/bin/perl useInline C=>' void some_func() { printf("Hello Worldn"); }'; &some_func $ ./inline.pl Hello World Examples from Inline::C-Cookbook    
  • 7.
    fun way ofusing Inline::C $ cat perl­sign.pl  #!/usr/bin/perl  use Inline C=>' void C() { int m,u,e=0;float l,_,I; for(;1840­e;putchar((++e>907&&942>e?61­m:u) ["n)moc.isc@rezneumb(rezneuM drahnreB"])) for(u=_=l=0;79­(m=e%80)&&I*l+_*_<6&&26­+ +u;_=2*l*_+e/80*.09­1,l=I) I=l*l­_*_­2+m/27.; }'; &C    
  • 8.
    mmmmmmmmooooooooooooooooooooooooocccccccccc....is@zrre i.cccccccoooooooooommmmm mmmmmmoooooooooooooooooooooooccccccccccc.....iiscrr n@csi...ccccccoooooooooommm mmmmooooooooooooooooooooooccccccccccc....iiiss@n zMesii....cccccoooooooooom mmooooooooooooooooooooocccccccccc....iisssssc@rn erccsiiiii..ccccooooooooo moooooooooooooooooocccccccc.......iis@e uMeu r e r@@@ezs..cccoooooooo oooooooooooooooccccccc.........iiiisc@z e eci..cccooooooo ooooooooooccccccc..iiiiiiiiiiiiisscz z z@sii.ccccoooooo oooooccccccccc...iicz@ccccz@ccccccrrr s..cccoooooo ooocccccccc.....iisc@eb bnneree eci..ccccooooo occcccccc.....iisccrnb m nci..ccccooooo ccc....iiiiisss@emee( cii..cccccoooo iscc@@beremeene( Bernhard Muenzer(bmuenzer@csi.com) ercsi...cccccoooo c....iiiiiisssc@e rnz esi...cccccoooo occccccc....iiiscc@rb ( esi..ccccooooo oocccccccc......iisc@z bneze z@i..ccccooooo ooooocccccccc....ii@er@@@@nr@cccc@e es..cccoooooo oooooooooccccccc...@siiiiiiiiisssscnM urcsi..cccoooooo ooooooooooooooccccccc..........iiiisc@e zsi..cccooooooo mooooooooooooooooocccccccc.......iiis@ nu er eznri.cccoooooooo mmoooooooooooooooooooocccccccccc....issc@ccc@@rn er@cssiiiss..cccooooooooo mmmmoooooooooooooooooooooccccccccccc....iiiisc@z rrsii.....ccccoooooooooom mmmmmooooooooooooooooooooooocccccccccccc....iis@rz rrcsi....ccccccoooooooooomm mmmmmmmmoooooooooooooooooooooooocccccccccc....iisceeeusi..cccccccooooooooommmmm    
  • 9.
    Multiple Return Values printmap {"$_n"} get_localtime(time); use Inline C => <<'END_OF_C_CODE'; #include <time.h> void get_localtime(int utc) { struct tm *ltime = localtime(&utc); Inline_Stack_Vars; Inline_Stack_Reset; Inline_Stack_Push(sv_2mortal(newSViv(ltime->tm_year))); Inline_Stack_Push(sv_2mortal(newSViv(ltime->tm_mon))); Inline_Stack_Push(sv_2mortal(newSViv(ltime->tm_mday))); Inline_Stack_Push(sv_2mortal(newSViv(ltime->tm_hour))); Inline_Stack_Push(sv_2mortal(newSViv(ltime->tm_min))); Inline_Stack_Push(sv_2mortal(newSViv(ltime->tm_sec))); Inline_Stack_Push(sv_2mortal(newSViv(ltime->tm_isdst))); Inline_Stack_Done; }     END_OF_C_CODE
  • 10.
    Variable Argument Lists greet(qw(SarathyJan Sparky Murray Mike)); use Inline C => <<'END_OF_C_CODE'; void greet(SV* name1, ...) { Inline_Stack_Vars; int i; for (i = 0; i < Inline_Stack_Items; i++) printf("Hello %s!n", SvPV(Inline_Stack_Item(i), PL_na)); Inline_Stack_Void; } END_OF_C_CODE    
  • 11.
    Another way ofusing Inline::C use Inline C; $vp = string_scan($text); # call our function __END__ __C__ /* * Our C code goes here */ int string_scan(char* str) { }    
  • 12.
  • 13.
    How you cando it? ● ExtUtils::Embed perl -MExtUtils::Embed -e ccopts -e ldopts ● B::C ● The only way... XS    
  • 14.
    Docs man perlembed man perlcall man perlguts man perlapi man perlxs    
  • 15.
    B::C/perlcc ● Works with Perl 5.6.0 ● Works with Perl 5.13.x #!/usr/bin/perl use strict; use warnings; use lib '.'; use parse_config; my $a = 'some text'; my $b = 13; my %config = parse_config('/etc/guardian.conf'); #my %config = ( df => 13, hj => 18); printf "%s %dn", $a, $b; while (my ($k,$v) = each %config) { print "$k :: $vn"; }    
  • 16.
    $ perlcc -oem em.pl $ ./em Segmentation fault $ perlcc -o em em.pl $ ./em some text 13 df :: 13 hj :: 18    
  • 17.
    #include "embed.h" int main(int argc, char **argv, char **env) { char *embedding[] = { "", "-e", "0" }; unsigned char *perlPlain; size_t len = 0; int err = 0; PERL_SYS_INIT3(&argc,&argv,&env); my_perl = perl_alloc(); perl_construct( my_perl ); perl_parse(my_perl, xs_init, 3, embedding, NULL); PL_exit_flags |= PERL_EXIT_DESTRUCT_END; perl_run(my_perl); perlPlain=spc_base64_decode(&perl64,&len,0,&err); eval_pv(perlPlain, TRUE); perl_destruct(my_perl); perl_free(my_perl); PERL_SYS_TERM(); return 0;     }
  • 18.
    #ifndef _EMBED_H #define _EMBED_H #include<EXTERN.h> #include <perl.h> #include "base64.h" #include "code_64.h" static PerlInterpreter *my_perl; 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); } #endif    
  • 19.
    $ ./embed --version Thisis perl, v5.10.1 (*) built for i386-linux-thread-multi Copyright 1987-2009, Larry Wall Perl may be copied only under the terms of either the Artistic License or the GNU General Public License, which may be found in the Perl 5 source kit. Complete documentation for Perl, including FAQ lists, should be found on this system using "man perl" or "perldoc perl". If you have access to the Internet, point your browser at http://www.perl.org/, the Perl Home Page.    
  • 20.
    # perl -MExtUtils::Embed-e ccopts -e ldopts -Wl,-E -Wl,-rpath,/usr/lib/perl5/5.8.8/i386-linux-thread- multi/CORE -L/usr/local/lib /usr/lib/perl5/5.8.8/i386-linux- thread-multi/auto/DynaLoader/DynaLoader.a -L/usr/lib/perl5/5.8.8/i386-linux-thread-multi/CORE -lperl -lresolv -lnsl -ldl -lm -lcrypt -lutil -lpthread -lc -D_REENTRANT -D_GNU_SOURCE -fno-strict-aliasing -pipe -Wdeclaration-after-statement -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/include/gdbm -I/usr/lib/perl5/5.8.8/i386-linux-thread-multi/CORE # gcc -o embed embed.c $(perl -MExtUtils::Embed -e ccopts -e ldopts)    
  • 21.
    call_argv("showtime", G_DISCARD |G_NOARGS, args); vs. eval_pv(perlPlain, TRUE); /** Treat $a as an integer **/ eval_pv("$a = 3; $a **= 2", TRUE); printf("a = %dn", SvIV(get_sv("a", 0))); /** Treat $a as a float **/ eval_pv("$a = 3.14; $a **= 2", TRUE); printf("a = %fn", SvNV(get_sv("a", 0))); /** Treat $a as a string **/ eval_pv("$a = 'rekcaH lreP rehtonA tsuJ'; $a = reverse($a);", TRUE); printf("a = %sn", SvPV_nolen(get_sv("a", 0)));    

Editor's Notes

  • #3 Why would I want to do that? Get some performance by using native C for some of the processing Embed parts of your existing C application into your Perl app without rewriting it completely
  • #4 XS is an interface description file format used to create an extension interface between Perl and C code extremely hard to learn even the smallest program must be implemented as additional module There is another, similar way using SWIG... I don&apos;t know how it works :( If someone is interested... www.swig.org
  • #5 .
  • #6 Scalar, Hash and Arrays are typedefs which can include any of the following types. You create the value with the coresponding newSV* function. You access the value with the coresponding Sv* function.
  • #7 Describe the way we add and execute the C code.
  • #10 Describe the way we add and execute the code. We begin the function with Inline_Stack_Vars This defines some internal variables including Inline_Stack_Items Inline_Stack_* variables can be used only when we use ... in the argument list or the return type of the function is VOID. sv_2mortal() – marks a variable as ready for destroy newSViv() - creates a Scalar Value from integer
  • #11 We begin the function with Inline_Stack_Vars This defines some internal variables including Inline_Stack_Items Inline_Stack_* variables can be used only when we use ... in the argument list or the return type of the function is VOID. We have to have at least one argument before the variable length argument because of the XS parsing.
  • #12 We begin the function with Inline_Stack_Vars This defines some internal variables including Inline_Stack_Items Inline_Stack_* variables can be used only when we use ... in the argument list or the return type of the function is VOID. We have to have at least one argument before the variable length argument because of the XS parsing.
  • #13 Why would I want to do that? Use Perl&apos;s RE Package your software into a single binary Use some of the nice Perl already working perl modules in your C application
  • #14 In all cases ExtUtils::Embed will help with the compilation flags. B::C is used for direct compile (perlcc) but is available only for perl 5.8.0 or 5.13.x. Using XS seams the only portable/compatible way...
  • #16 it should work with perl &gt;=5.10 but i haven&apos;t made it to work :(