running away to c

81
Running Away to C XS – More faff than fear London Perl Workshop – Dec 04 Alex Gough [email protected]

Upload: najila

Post on 23-Mar-2016

18 views

Category:

Documents


0 download

DESCRIPTION

Running Away to C. XS – More faff than fear London Perl Workshop – Dec 04 Alex Gough [email protected]. 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. Stack. Stack. Stack. Stack. Stack. Stack. Stack. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Running Away to C

Running Away to C

XS – More faff than fearLondon Perl Workshop – Dec 04

Alex [email protected]

Page 2: Running Away to C

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

Page 3: Running Away to C

Stack

Page 4: Running Away to C

Stack

Page 5: Running Away to C

Stack

Page 6: Running Away to C

Stack

Page 7: Running Away to C

Stack

Page 8: Running Away to C

Stack

Page 9: Running Away to C

Stack

Page 10: Running Away to C

Stack

Page 11: Running Away to C

Stack

Page 12: Running Away to C

Stack

Page 13: Running Away to C

Stack

Page 14: Running Away to C

Stack

Page 15: Running Away to C

Stack

Page 16: Running Away to C

Stack

Page 17: Running Away to C

Stack

Page 18: Running Away to C

Stack FunctionsdSP; Declare stack varsPUSHMARK(SP) start of argumentsEXTEND make spaceXPUSHstuff push stuff, making spacePUSHstuff push stuff, need spacePUTBACK done adding arguments . . . Make a call . . .SPAGAIN refresh our stackret = POPstuff grab stuff from stackPUTBACK we’re done grabbing stuff

Page 19: Running Away to C

Scope•Start and end a scope

•Tell Perl we’re creating temporary stuff

•Tell Perl when we’re done with it

Page 20: Running Away to C

Scope FunctionsENTER Opening brace {SAVETMPS start making temps . . . Call function . . .FREETMPS done with my tempsLEAVE Closing brace }

Page 21: Running Away to C

Scalars

$thing = 12 12.3 “harry” \ @array \ %hash \ $thing bless(\$object) *FILE qr{.*} {code}

Page 22: Running Away to C

Scalar Functions ISV* 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)

Page 23: Running Away to C

Scalar Functions ISV* 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)

Page 24: Running Away to C

Scalar Functions ISV* 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)

Page 25: Running Away to C

Scalar Functions ISV* 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)

Page 26: Running Away to C

Scalar Functions IISV* 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 . . . }

Page 27: Running Away to C

Scalar Functions IISV* 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 . . . }

Page 28: Running Away to C

Scalar Functions IISV* 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 . . . }

Page 29: Running Away to C

Scalar Functions IISV* 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 . . . }

Page 30: Running Away to C

A Puzzle

• Find the longest set of three words that when listed form three letter words down all columns.

padsareatend

Page 31: Running Away to C

Array FunctionsAV *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)

Page 32: Running Away to C

Hash FunctionsHV *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)

Page 33: Running Away to C

Function FunctionsCV* 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 $@

Page 34: Running Away to C

Objects, globs, whatever

• Maybe you’ll need them• Maybe you won’t• See perlapi, perlcall, perlguts

Page 35: Running Away to C

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

Page 36: Running Away to C

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)

Page 37: Running Away to C

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

Page 38: Running Away to C

Config Parsinguse strict;

my %config = ();

sub init {my($file) = @_;… # fill in %config

}

sub get_value {my($key) = @_;return $config{$key} || “”;

}

Page 39: Running Away to C

#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()

}

Page 40: Running Away to C

#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()

}

Page 41: Running Away to C

#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()

}

Page 42: Running Away to C

#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()

}

Page 43: Running Away to C

#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()

}

Page 44: Running Away to C

#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()

}

Page 45: Running Away to C

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;

}

Page 46: Running Away to C

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;

}

Page 47: Running Away to C

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;

}

Page 48: Running Away to C

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;

}

Page 49: Running Away to C

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;

}

Page 50: Running Away to C

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;

}

Page 51: Running Away to C

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;

}

Page 52: Running Away to C

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`

Page 53: Running Away to C

Compiling – Win32

• For Visual Studio & ActivePerlinclude: C:\Perl\lib\CORElib dir: C:\Perl\lib\CORElibs: Perl58.lib+ have C:\Perl\bin\ in path for dll when running.

Page 54: Running Away to C

Using Modules

• Pure Perl(eg. Acme::Barf)

• XS extensions(eg. Audio::File, Storable)

• Can do, but need to set up dynaloader from C first…

Page 55: Running Away to C

Using Modules

• Dynaloader loads and initialises C modules when you say“use Foo”

• Dynaloader must be setup first

• Then everything should Just Work

Page 56: Running Away to C

DynaloaderEXTERN_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

Page 57: Running Away to C

DynaloaderEXTERN_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

Page 58: Running Away to C

Manual Pages

• perlembed• perlcall• perlapi• ExtUtils::Embed

Page 59: Running Away to C

XS

• C from Perl• libraries• Meddle• Speed

Page 60: Running Away to C

Libraries• Steal work from others• Compile & install separately• XS provides glue to Perl• Provide a Perl module to improve interface

Page 61: Running Away to C

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

Page 62: Running Away to C

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

Page 63: Running Away to C

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

Page 64: Running Away to C

Turtle.xs

• Headers (#include <green.h>)MODULE = Green::Turtle

PACKAGE = Green::Turtle• XS “functions”

Page 65: Running Away to C

Turtle.xsMODULE = Green::Turtle PACKAGE = Green::Turtle

doubleconstant(name,arg) char * name int arg

GREEN *new_green(turtles, message) int turtles char * message

intfree_green(green) GREEN * green

. . .

Page 66: Running Away to C

Turtle.xsGREEN *new_green(turtles, message) int turtles char * message

Becomes:

Green::Turtle::new_green()

Page 67: Running Away to C

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).

Page 68: Running Away to C

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}, @_);}

Page 69: Running Away to C

GREEN*

• GREEN* blessed into GREENPtr• To free, we need to add a DESTROY()MODULE Green::Turtle PACKAGE GREENPtr

voidDESTROY(green)

GREEN* greenCODE:

free_green(green)

Page 70: Running Away to C

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

Page 71: Running Away to C

voidturtles(green, message) GREEN * green char * message PPCODE: { char **ret = turtles(green, message); while (*ret != NULL) { PUSHs(sv_2mortal(newSVpv(*ret, 0))); ret++; } }

Page 72: Running Away to C

XS blocksintcount_colours(turtle)

GREEN* turtlePREINIT:char *name = “george”;CODE:RETVAL = reds(turtle, name)

+ greens(turtle, name);OUTPUT:RETVAL

Page 73: Running Away to C

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

}

Page 74: Running Away to C

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

}

Page 75: Running Away to C

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

}

Page 76: Running Away to C

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

Page 77: Running Away to C

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;

Page 78: Running Away to C

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

}

Page 79: Running Away to C

C speed hotness

anticoagulativeneuroanatomicaldeterminateness

aeromechanicalaminoguanidineheterophylesis

Page 80: Running Away to C

General XS info

• Lovely man pages– perlxs– perlxstut– perlcall, perlapi, perlwhatever

• Bother someone you know• Inline::C!• Inline::C!

Page 81: Running Away to C

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 familyhave feathers and they hoot, While all the sisters dress in fur and have long tails to boot.