Presentation is loading. Please wait.

Presentation is loading. Please wait.

Running Away to C XS – More faff than fear London Perl Workshop – Dec 04 Alex Gough

Similar presentations


Presentation on theme: "Running Away to C XS – More faff than fear London Perl Workshop – Dec 04 Alex Gough"— Presentation transcript:

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

4

5

6

7

8

9

10

11

12

13

14

15

16

17

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; }

46

47

48

49

50

51

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.


Download ppt "Running Away to C XS – More faff than fear London Perl Workshop – Dec 04 Alex Gough"

Similar presentations


Ads by Google