Download presentation
Presentation is loading. Please wait.
Published byErin Simon Modified over 8 years ago
1
Running Away to C XS – More faff than fear London Perl Workshop – Dec 04 Alex Gough alex@earth.li
2
You’re here because… You know some Perl You recognise some C –But fear it a little You’re an evil brigand You know it’s warmer in here
3
Stack
18
Stack Functions dSP; Declare stack vars PUSHMARK(SP) start of arguments EXTEND make space XPUSHstuff push stuff, making space PUSHstuff push stuff, need space PUTBACK done adding arguments... Make a call... SPAGAIN refresh our stack ret = POPstuff grab stuff from stack PUTBACK we’re done grabbing stuff
19
Scope Start and end a scope Tell Perl we’re creating temporary stuff Tell Perl when we’re done with it
20
Scope Functions ENTER Opening brace { SAVETMPS start making temps... Call function... FREETMPS done with my temps LEAVE Closing brace }
21
Scalars $thing = 12 12.3 “harry” \ @array \ %hash \ $thing bless(\$object) *FILE qr{.*} {code}
22
Scalar Functions I SV* get_sv(char* name, I32 create) SV* sv = get_sv(“bar”, TRUE) SV* newSVx sv = newSViv(12) newSVnv(12.3) newSVpv(“honk”, 0) -> “honk” newSVpv(“honk”, 2) -> “ho” IV intv = SvIV(sv) NV fltv = SvNV(sv) char* foo = SvPV(sv) sv_setpv(sv, “honk”); sv_setiv(sv, 12)
23
Scalar Functions I SV* get_sv(char* name, I32 create) SV* sv = get_sv(“bar”, TRUE) SV* newSVx sv = newSViv(12) newSVnv(12.3) newSVpv(“honk”, 0) -> “honk” newSVpv(“honk”, 2) -> “ho” IV intv = SvIV(sv) NV fltv = SvNV(sv) char* foo = SvPV(sv) sv_setpv(sv, “honk”); sv_setiv(sv, 12)
24
Scalar Functions I SV* get_sv(char* name, I32 create) SV* sv = get_sv(“bar”, TRUE) SV* newSVx sv = newSViv(12) newSVnv(12.3) newSVpv(“honk”, 0) -> “honk” newSVpv(“honk”, 2) -> “ho” IV intv = SvIV(sv) NV fltv = SvNV(sv) char* foo = SvPV(sv) sv_setpv(sv, “honk”); sv_setiv(sv, 12)
25
Scalar Functions I SV* get_sv(char* name, I32 create) SV* sv = get_sv(“bar”, TRUE) SV* newSVx sv = newSViv(12) newSVnv(12.3) newSVpv(“honk”, 0) -> “honk” newSVpv(“honk”, 2) -> “ho” IV intv = SvIV(sv) NV fltv = SvNV(sv) char* foo = SvPV(sv) sv_setpv(sv, “honk”); sv_setiv(sv, 12)
26
Scalar Functions II SV* refsv = newRV_inc(sv) “refsv = \ sv” SV* sv = SvRV(refsv) “sv = $ { refsv }” I32 cnt = REFCNT(sv) REFCNT_inc(sv) REFCNT_dec(sv) SV *sv = sv_2mortal(newSViv(12)) sv_free(sv) sv_{catpv catsv cmp dec eq inc isa len... }
27
Scalar Functions II SV* refsv = newRV_inc(sv) “refsv = \ sv” SV* sv = SvRV(refsv) “sv = $ { refsv }” I32 cnt = REFCNT(sv) REFCNT_inc(sv) REFCNT_dec(sv) SV *sv = sv_2mortal(newSViv(12)) sv_free(sv) sv_{catpv catsv cmp dec eq inc isa len... }
28
Scalar Functions II SV* refsv = newRV_inc(sv) “refsv = \ sv” SV* sv = SvRV(refsv) “sv = $ { refsv }” I32 cnt = REFCNT(sv) REFCNT_inc(sv) REFCNT_dec(sv) SV *sv = sv_2mortal(newSViv(12)) sv_free(sv) sv_{catpv catsv cmp dec eq inc isa len... }
29
Scalar Functions II SV* refsv = newRV_inc(sv) “refsv = \ sv” SV* sv = SvRV(refsv) “sv = $ { refsv }” I32 cnt = REFCNT(sv) REFCNT_inc(sv) REFCNT_dec(sv) SV *sv = sv_2mortal(newSViv(12)) sv_free(sv) sv_{catpv catsv cmp dec eq inc isa len... }
30
A Puzzle Find the longest set of three words that when listed form three letter words down all columns. pads area tend
31
Array Functions AV *av = get_av(“ARGV”, TRUE) SV** ret = av_store(av, 12, sv) SV** ret = av_fetch(av, 12, sv, lval) SV* sv = av_pop(av) av_shift(av) void av_push(av, sv) av_unshift(av, 3) [3 undefs] I32 len = av_len(av)
32
Hash Functions HV *hv = get_hv(“hash”, TRUE) BOOL hv_exists(hv, “key”, 3) SV** sv = hv_fetch(hv, “key”, 3, lval) SV** sv = hv_store(hv, “key”, 3, sv, 0) Or you can play with HE (Hash Entries)
33
Function Functions CV* cv = get_cv(“subname”, TRUE) call_pv(“subname”, context) call_sv(sv, context) Context: G_VOID } G_SCALAR } context G_ARRAY } G_NOARGS no arguments G_DISCARD “no return values” G_EVAL catch die in eval { } G_KEEPERR.. and be nice to $@
34
Objects, globs, whatever Maybe you’ll need them Maybe you won’t See perlapi, perlcall, perlguts
35
Embedding You have some C You want to add a bit of Perl –Config file dabbling –Scripting engine –Hook into Efficient / Legacy code –Prototype features
36
Config Parsing Flexible configuration framework C side factored into: void get_config(char* key, char* dst, int len); Let Perl provide the intelligence (We provide the glue)
37
Perl A big C program A really tiny main() –Constructs an intepreter –Tells it to parse your script –Tells it to run your script Jumps between C and Perl a lot –Cleans up (sort of) –Exits
38
Config Parsing use strict; my %config = (); sub init { my($file) = @_; … # fill in %config } sub get_value { my($key) = @_; return $config{$key} || “”; }
39
#include "EXTERN.h" #include "Perl.h" static PerlInterpreter *g_perl_interp; int main(int argc, char** argv, char** env) { char *config_pl[] = {“config.pl”, 0}; PERL_SYS_INIT3(&argc,&argv,&env); g_perl_interp = perl_alloc(); perl_construct(g_perl_interp); PL_exit_flags |= PERL_EXIT_DESTRUCT_END; perl_parse(g_perl_interp, NULL, 1, config_pl, env); perl_run(g_perl_interp); do_program_stuff(...); perl_destruct(g_perl_interp); perl_free(g_perl_interp); PERL_SYS_TERM() }
40
#include "EXTERN.h" #include "Perl.h" static PerlInterpreter *g_perl_interp; int main(int argc, char** argv, char** env) { char *config_pl[] = {“config.pl”, 0}; PERL_SYS_INIT3(&argc,&argv,&env); g_perl_interp = perl_alloc(); perl_construct(g_perl_interp); PL_exit_flags |= PERL_EXIT_DESTRUCT_END; perl_parse(g_perl_interp, NULL, 1, config_pl, env); perl_run(g_perl_interp); do_program_stuff(...); perl_destruct(g_perl_interp); perl_free(g_perl_interp); PERL_SYS_TERM() }
41
#include "EXTERN.h" #include "Perl.h" static PerlInterpreter *g_perl_interp; int main(int argc, char** argv, char** env) { char *config_pl[] = {“config.pl”, 0}; PERL_SYS_INIT3(&argc,&argv,&env); g_perl_interp = perl_alloc(); perl_construct(g_perl_interp); PL_exit_flags |= PERL_EXIT_DESTRUCT_END; perl_parse(g_perl_interp, NULL, 1, config_pl, env); perl_run(g_perl_interp); do_program_stuff(...); perl_destruct(g_perl_interp); perl_free(g_perl_interp); PERL_SYS_TERM() }
42
#include "EXTERN.h" #include "Perl.h" static PerlInterpreter *g_perl_interp; int main(int argc, char** argv, char** env) { char *config_pl[] = {“config.pl”, 0}; PERL_SYS_INIT3(&argc,&argv,&env); g_perl_interp = perl_alloc(); perl_construct(g_perl_interp); PL_exit_flags |= PERL_EXIT_DESTRUCT_END; perl_parse(g_perl_interp, NULL, 1, config_pl, env); perl_run(g_perl_interp); do_program_stuff(...); perl_destruct(g_perl_interp); perl_free(g_perl_interp); PERL_SYS_TERM() }
43
#include "EXTERN.h" #include "Perl.h" static PerlInterpreter *g_perl_interp; int main(int argc, char** argv, char** env) { char *config_pl[] = {“config.pl”, 0}; PERL_SYS_INIT3(&argc,&argv,&env); g_perl_interp = perl_alloc(); perl_construct(g_perl_interp); PL_exit_flags |= PERL_EXIT_DESTRUCT_END; perl_parse(g_perl_interp, NULL, 1, config_pl, env); perl_run(g_perl_interp); do_program_stuff(...); perl_destruct(g_perl_interp); perl_free(g_perl_interp); PERL_SYS_TERM() }
44
#include "EXTERN.h" #include "Perl.h" static PerlInterpreter *g_perl_interp; int main(int argc, char** argv, char** env) { char *config_pl[] = {“config.pl”, 0}; PERL_SYS_INIT3(&argc,&argv,&env); g_perl_interp = perl_alloc(); perl_construct(g_perl_interp); PL_exit_flags |= PERL_EXIT_DESTRUCT_END; perl_parse(g_perl_interp, NULL, 1, config_pl, env); perl_run(g_perl_interp); do_program_stuff(...); perl_destruct(g_perl_interp); perl_free(g_perl_interp); PERL_SYS_TERM() }
45
void get_config(char* key, char* dst) { dSP; SV *ret = NULL; ENTER; SAVETMPS; PUSHMARK(SP); XPUSHs(sv_2mortal(newSVpv(key))); PUTBACK; call_pv("get_value", G_SCALAR); SPAGAIN; ret = POPs; strcpy(dst, SvPV); PUTBACK; FREETMPS; LEAVE; }
52
Compiling Compile as normal, but add flags cc -c foo.c \ `perl -MExtUtils::Embed -e ccopts` cc -o interp perlxsi.o interp.o \ `perl -MExtUtils::Embed -e ldopts`
53
Compiling – Win32 For Visual Studio & ActivePerl include:C:\Perl\lib\CORE lib dir:C:\Perl\lib\CORE libs: Perl58.lib + have C:\Perl\bin\ in path for dll when running.
54
Using Modules Pure Perl (eg. Acme::Barf) XS extensions (eg. Audio::File, Storable) Can do, but need to set up dynaloader from C first…
55
Using Modules Dynaloader loads and initialises C modules when you say “ use Foo ” Dynaloader must be setup first Then everything should Just Work
56
Dynaloader EXTERN_C void xs_init (pTHX); EXTERN_C void boot_DynaLoader (pTHX_ CV* cv); EXTERN_C void xs_init(pTHX) { char *file = __FILE__; dXSUB_SYS; newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file); } And change your call to perl_parse to: perl_parse(g_perl_interp, xs_init, 1, config_pl, env); Generate this with: perl -MExtUtils::Embed -e xsinit -- -o perlxsi.c
57
Dynaloader EXTERN_C void xs_init (pTHX); EXTERN_C void boot_DynaLoader (pTHX_ CV* cv); EXTERN_C void xs_init(pTHX) { char *file = __FILE__; dXSUB_SYS; newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file); } And change your call to perl_parse to: perl_parse(g_perl_interp, xs_init, 1, config_pl, env); Generate this with: perl -MExtUtils::Embed -e xsinit -- -o perlxsi.c perl -MExtUtils::Embed -e xsinit -- -o perlxsi.c
58
Manual Pages perlembed perlcall perlapi ExtUtils::Embed
59
XS C from Perl libraries Meddle Speed
60
Libraries Steal work from others Compile & install separately XS provides glue to Perl Provide a Perl module to improve interface
61
Library’s Header File // green.h – Interface to green-turtle library GREEN* new_green(int turtles, char *message); int free_green(GREEN *green); int more_turtles(GREEN *green, int eggs); char** turtles(GREEN *green, char *match);
62
h2xs header 2 XS First install your library & headers (so that green.h is in the standard search path) Run: h2xs –Oxn Green::Turtle green.h Copy green.h to Green/Turtle Run: h2xs –Oxn Green::Turtle green.h
63
h2xs This just went and created Turtle.pm – Perl template Turtle.xs – XS functions typemap – maps C types to Perl types Makefile.PL Some test files and other stuff Nearly works… but we have to faff first
64
Turtle.xs Headers (#include ) MODULE = Green::Turtle PACKAGE = Green::Turtle XS “functions”
65
Turtle.xs MODULE = Green::Turtle PACKAGE = Green::Turtle double constant(name,arg) char * name int arg GREEN * new_green(turtles, message) int turtles char * message int free_green(green) GREEN * green...
66
Turtle.xs GREEN * new_green(turtles, message) int turtles char * message Becomes: Green::Turtle::new_green()
67
typemap GREEN*T_PTROBJ Perl will “cast” between scalars & GREEN* These scalars will be blessed into the GREENPtr package. When destroyed, memory will not be free’d (but see later).
68
Turtle.pm Normal perl module + some imports Good idea to wrap the XS: sub new { my($class) = shift; my($turtles, $msg) = @_; my $self = {}; $self->{_green} = new_green($turtles, $msg); return bless $self, $class; } sub add_turtles { my($self) = shift; return more_turtles($self->{green}, @_); }
69
GREEN* GREEN* blessed into GREENPtr To free, we need to add a DESTROY() MODULE Green::Turtle PACKAGE GREENPtr void DESTROY(green) GREEN* green CODE: free_green(green)
70
char ** Perl doesn’t really know what to do so is not helpful… Can typemap or marshall ourselves, as we’ll want a list of strings, we’ll need to marshall. char ** turtles(green, message) GREEN * green char * message
71
void turtles(green, message) GREEN * green char * message PPCODE: { char **ret = turtles(green, message); while (*ret != NULL) { PUSHs(sv_2mortal(newSVpv(*ret, 0))); ret++; }
72
XS blocks int count_colours(turtle) GREEN* turtle PREINIT: char *name = “george”; CODE: RETVAL = reds(turtle, name) + greens(turtle, name); OUTPUT: RETVAL
73
sub try_words { my($ar,$l,@all,$j) = $_[0]; push(@all, [split "", $_]) foreach @$ar; foreach my $a1 (@all) { foreach my $a2 (@all) { INNA: foreach my $a3 (@all) { for ($j=0;$j<$l;$j++) { my $w = $a1->[$j].$a2->[$j].$a3->[$j]; unless (exists($w3{$w})){ next INNA; } print(join("", @$_)) foreach ($a1, $a2, $a3); print "\n"; }
74
sub try_words { my($ar,$l,@all,$j) = $_[0]; push(@all, [split "", $_]) foreach @$ar; foreach my $a1 (@all) { foreach my $a2 (@all) { INNA: foreach my $a3 (@all) { for ($j=0;$j<$l;$j++) { my $w = $a1->[$j].$a2->[$j].$a3->[$j]; unless (exists($w3{$w})){ next INNA; } print(join("", @$_)) foreach ($a1, $a2, $a3); print "\n"; }
75
sub try_words { my($ar,$l,@all,$j) = $_[0]; # push(@all, [split "", $_]) foreach @$ar; foreach my $a1 (@$ar) { foreach my $a2 (@$ar) { INNA: foreach my $a3 (@$ar) { if (try_cwords($a1,$a2,$a3,$l,\%w3) ) { print “($a1, $a2, $a3)\n”; }
76
int try_cwords(one,two,thr,len,ref_w3) char* one char* two char* thr int len SV* ref_w3 PREINIT: int i; char three[] = {0,0,0}; HV* w3;
77
char three[3]; char *one, *two, *thr; SV* ref_w3; HV* w3; int len; CODE: if (! SvROK(ref_w3)) croak("ref_w3 is not a reference"); w3 = (HV*)SvRV(ref_w3); for (i=0;i<len; i++) { three[0] = one[i]; three[1] = two[i]; three[2] = thr[i]; /* Check if it's in the hash */ if (!hv_exists(w3, three, 3)) XSRETURN_UNDEF; } RETVAL = 1;
78
sub try_words { my($ar,$l,@all,$j) = $_[0]; # push(@all, [split "", $_]) foreach @$ar; foreach my $a1 (@$ar) { foreach my $a2 (@$ar) { INNA: foreach my $a3 (@$ar) { if (try_cwords($a1,$a2,$a3,$l,\%w3) ) { print “($a1, $a2, $a3)\n”; }
79
C speed hotness anticoagulative neuroanatomical determinateness aeromechanical aminoguanidine heterophylesis
80
General XS info Lovely man pages –perlxs –perlxstut –perlcall, perlapi, perlwhatever Bother someone you know Inline::C!
81
Lear on Hybrids Our mother was the Pussy-cat, our father was the Owl, And so we're partly little beasts and partly little fowl, The brothers of our family have feathers and they hoot, While all the sisters dress in fur and have long tails to boot.
Similar presentations
© 2024 SlidePlayer.com Inc.
All rights reserved.