typemap in perl/xs

88
Wine label from Perl (located in Germany) Thanks , Wendy and Liz!

Upload: charsbar

Post on 05-Dec-2014

1.014 views

Category:

Technology


0 download

DESCRIPTION

for OSDC.TW 2013

TRANSCRIPT

Page 1: typemap in Perl/XS

Wine label from Perl (located in Germany)

Thanks , Wendy and Liz!

Page 2: typemap in Perl/XS

... and MST

Page 3: typemap in Perl/XS

typemap in Perl/XS

Kenichi Ishigaki(charsbar)

@OSDC.TW 2013April 19, 2013

Page 4: typemap in Perl/XS

Let me ask you first.

Page 5: typemap in Perl/XS

Have you ever written an

extension that bridges C and Perl?

Page 6: typemap in Perl/XS

Part I: XS is ...?

Page 7: typemap in Perl/XS

Perl has a feature to load an external C

library.

use DynaLoader;my @paths = dl_findfile(...);my $lib = dl_load_file($path);

Page 8: typemap in Perl/XS

This won't work correctly unless the library conforms

with Perl's convention.

use DynaLoader;my @paths = dl_findfile(...);my $lib = dl_load_file($path);

Page 9: typemap in Perl/XS

So we need something in-

between.

Perl XS C library

Page 10: typemap in Perl/XS

Writing the one-in-between is fairly

easy.

Page 11: typemap in Perl/XS

(as long as you don't add

anything extra)

Page 12: typemap in Perl/XS

The simplest form of the one-in-between starts like

this:#include "EXTERN.h"#include "perl.h"#include "XSUB.h"#include "ppport.h"#include <foo.h>

MODULE = Foo PACKAGE = Foo

intfunc(const char* str)

Page 13: typemap in Perl/XS

These three lines are to use Perl API.

#include "EXTERN.h"#include "perl.h"#include "XSUB.h"#include "ppport.h"#include <foo.h>

MODULE = Foo PACKAGE = Foo

intfunc(const char* str)

Page 14: typemap in Perl/XS

This is for portability between perls.

#include "EXTERN.h"#include "perl.h"#include "XSUB.h"#include "ppport.h"#include <foo.h>

MODULE = Foo PACKAGE = Foo

intfunc(const char* str)

Page 15: typemap in Perl/XS

This is to import C functions from the library.

#include "EXTERN.h"#include "perl.h"#include "XSUB.h"#include "ppport.h"#include <foo.h>

MODULE = Foo PACKAGE = Foo

intfunc(const char* str)

Page 16: typemap in Perl/XS

Module and package declarations.

#include "EXTERN.h"#include "perl.h"#include "XSUB.h"#include "ppport.h"#include <foo.h>

MODULE = Foo PACKAGE = Foo

intfunc(const char* str)

Page 17: typemap in Perl/XS

The function declarations to export (XSUBs) follow.

#include "EXTERN.h"#include "perl.h"#include "XSUB.h"#include "ppport.h"#include <foo.h>

MODULE = Foo PACKAGE = Foo

intfunc(const char* str)

Page 18: typemap in Perl/XS

As with .h files, there should be only declarations.

#include "EXTERN.h"#include "perl.h"#include "XSUB.h"#include "ppport.h"#include <foo.h>

MODULE = Foo PACKAGE = Foo

intfunc(const char* str)

Page 19: typemap in Perl/XS

Nothing difficult (in principle).

Page 20: typemap in Perl/XS

The library you use may not always be

that simple.

Page 21: typemap in Perl/XS

People may add something written in C with a variety of

Perl API.

Page 22: typemap in Perl/XS

If someone's XS code scares you, please remember.

Page 23: typemap in Perl/XS

What's difficult is not the XS

interface itself.

Page 24: typemap in Perl/XS

It's something else that makes

the matter complicated.

Page 25: typemap in Perl/XS

Don't hesitate writing XS interface if you find a useful

C library.

Page 26: typemap in Perl/XS

Part II: How .xs file is compiled

Page 27: typemap in Perl/XS

To build an interface library, we need to turn its XS

declaration into pure C code.

Page 28: typemap in Perl/XS

If you already have Makefile.PL, run it, and

then, make.

$ perl Makefile.PL && make

Page 29: typemap in Perl/XS

If you have Build.PL, do something like this (or maybe ./Build build).

$ perl Build.PL && ./Build

Page 30: typemap in Perl/XS

If you don't have either, Milla or Minilla will help

you (ask miyagawa-san).

Page 31: typemap in Perl/XS

The most important XSUB part will be translated like

this:XS_EUPXS(XS_Foo_func){ dVAR; dXSARGS; if (items != 1) croak_xs_usage(cv, "str"); { int RETVAL; dXSTARG; const char* str = (const char *)SvPV_nolen(ST(0)); RETVAL = func(str); XSprePUSH; PUSHi((IV)RETVAL); } XSRETURN(1);}

Page 32: typemap in Perl/XS

A function exposed to the Perl world takes a Perl variable as its

argument.XS_EUPXS(XS_Foo_func){ dVAR; dXSARGS; if (items != 1) croak_xs_usage(cv, "str"); { int RETVAL; dXSTARG; const char* str = (const char *)SvPV_nolen(ST(0)); RETVAL = func(str); XSprePUSH; PUSHi((IV)RETVAL); } XSRETURN(1);}

Page 33: typemap in Perl/XS

However, a Perl variable is actually a structure in C.

XS_EUPXS(XS_Foo_func){ dVAR; dXSARGS; if (items != 1) croak_xs_usage(cv, "str"); { int RETVAL; dXSTARG; const char* str = (const char *)SvPV_nolen(ST(0)); RETVAL = func(str); XSprePUSH; PUSHi((IV)RETVAL); } XSRETURN(1);}

Page 34: typemap in Perl/XS

You can't pass it directly to a C function, and vice versa.

XS_EUPXS(XS_Foo_func){ dVAR; dXSARGS; if (items != 1) croak_xs_usage(cv, "str"); { int RETVAL; dXSTARG; const char* str = (const char *)SvPV_nolen(ST(0)); RETVAL = func(str); XSprePUSH; PUSHi((IV)RETVAL); } XSRETURN(1);}

Page 35: typemap in Perl/XS

The Perl variable is converted and cast into a C value here.

XS_EUPXS(XS_Foo_func){ dVAR; dXSARGS; if (items != 1) croak_xs_usage(cv, "str"); { int RETVAL; dXSTARG; const char* str = (const char *)SvPV_nolen(ST(0)); RETVAL = func(str); XSprePUSH; PUSHi((IV)RETVAL); } XSRETURN(1);}

Page 36: typemap in Perl/XS

Then, the function imported from the library is called.

XS_EUPXS(XS_Foo_func){ dVAR; dXSARGS; if (items != 1) croak_xs_usage(cv, "str"); { int RETVAL; dXSTARG; const char* str = (const char *)SvPV_nolen(ST(0)); RETVAL = func(str); XSprePUSH; PUSHi((IV)RETVAL); } XSRETURN(1);}

Page 37: typemap in Perl/XS

And the return value is converted into a Perl value

again.XS_EUPXS(XS_Foo_func){ dVAR; dXSARGS; if (items != 1) croak_xs_usage(cv, "str"); { int RETVAL; dXSTARG; const char* str = (const char *)SvPV_nolen(ST(0)); RETVAL = func(str); XSprePUSH; PUSHi((IV)RETVAL); } XSRETURN(1);}

Page 38: typemap in Perl/XS

typemap is the key to this conversion.

Page 39: typemap in Perl/XS

Basic type mappings are

defined in ExtUtils::typemap

.$ perldoc -m ExtUtils::typemap

Page 40: typemap in Perl/XS

# basic C typesint T_IVunsigned T_UVunsigned int T_UVlong T_IVunsigned long T_UVshort T_IVunsigned short T_UVchar T_CHARunsigned char T_U_CHARchar * T_PVunsigned char * T_PVconst char * T_PVcaddr_t T_PVwchar_t * T_PVwchar_t T_IV

Page 41: typemap in Perl/XS

# bool_t is defined in <rpc/rpc.h>bool_t T_IVsize_t T_UVssize_t T_IVtime_t T_NVunsigned long *T_OPAQUEPTRchar **T_PACKEDARRAYvoid * T_PTRTime_t * T_PVSV * T_SV

Page 42: typemap in Perl/XS

Any type not listed there should be

added locally, in a file named "typemap".

Page 43: typemap in Perl/XS

Part III: On type mapping

Page 44: typemap in Perl/XS

A typical "typemap" file

has three sections.

Page 45: typemap in Perl/XS

"TYPEMAP" section contains a pair of C type

and XS type.

TYPEMAPchar * T_PV

Page 46: typemap in Perl/XS

How to map should be described in the "INPUT" and

"OUTPUT" sections, if necessary.

INPUTT_PV $var = ($type)SvPV_nolen($arg)

OUTPUTT_PV sv_setpv((SV*)$arg, $var);

Page 47: typemap in Perl/XS

These code fragments will be interpolated while processing an XS file.

INPUTT_PV $var = ($type)SvPV_nolen($arg)

OUTPUTT_PV sv_setpv((SV*)$arg, $var);

Page 48: typemap in Perl/XS

Adding orphan C types is easy.

TYPEMAPmy_id T_IVmy_str T_PV

Page 49: typemap in Perl/XS

Modifying the behavior of an existing type needs some

consideration.

Page 50: typemap in Perl/XS

If you are confident, just add a new code

fragment in your local typemap.

INPUTT_PV if (!SvOK($arg)) { $var = NULL; } else { $var = ($type)SvPV_nolen($arg); }

Page 51: typemap in Perl/XS

Or, you might want to add another typedef in the XS file, before MODULE and PACKAGE

declarations.

typedef char * my_nullable_str;

MODULE Foo PACKAGE FOO

intfunc(my_nullable_str str)

Page 52: typemap in Perl/XS

And then, add a behavior of this new type in your local

typemap.TYPEMAPmy_nullable_str T_PV_OR_NULL

INPUTT_PV_OR_NULL if (!SvOK($arg)) { $var = NULL; } else { $var = ($type)SvPV_nolen($arg); }

Page 53: typemap in Perl/XS

There is also a much trickier way to do it.

MODULE Foo PACKAGE FOO

intfunc(char * str_or_null)

Page 54: typemap in Perl/XS

If you don't get why this works, see

perlref.INPUTT_PV $var = ${ $var =~ /_or_null$/ ? \qq{NULL} : \qq{($type)SvPV_nolen($arg)} }

Page 55: typemap in Perl/XS

Remove a star and prepend "OUT" (or

"IN_OUT") for an argument called by reference.

MODULE Foo PACKAGE FOO

intfunc(char * str, OUT int len)

Page 56: typemap in Perl/XS

Further Reading

• perlxs• perlxstut• perlxstypemap• perlapi• perlcall• ... and others' XS

code :p

Page 57: typemap in Perl/XS

Part IV: From .h files to XS files

Page 58: typemap in Perl/XS

We've written XS files by hand so

far.

Page 59: typemap in Perl/XS

Of course this can be done with a

tool.

Page 60: typemap in Perl/XS

The best-known tool is h2xs.

Page 61: typemap in Perl/XS

It's mainly used to expose

constants from a C library.

Page 62: typemap in Perl/XS

With the help of C::Scan, you can use

it to expose C functions as well.

$ h2xs -Axan Foo /path/to/header.h

Page 63: typemap in Perl/XS

Defaulting to backwards compatibility with perl 5.xx.xIf you intend this module to be compatible with earlier perl versions, please specify a minimum perl version with the -b option.

Writing Foo/ppport.hScanning typemaps... Scanning /home/xxxx/perl5/perlbrew/perls/perl-5.xx.x/lib/5.xx.x/ExtUtils/typemapScanning /path/to/header.h for functions...Scanning /path/to/header.h for typedefs...Writing Foo/lib/Foo.pmWriting Foo/Foo.xsWriting Foo/typemapWriting Foo/Makefile.PLWriting Foo/READMEWriting Foo/t/Foo.tWriting Foo/ChangesWriting Foo/MANIFEST

Page 64: typemap in Perl/XS

If the library is stable, this may give you a good starting

point.

Page 65: typemap in Perl/XS

However.

Page 66: typemap in Perl/XS

The files h2xs generates are rather

old-fashioned.

Page 67: typemap in Perl/XS

It's not good at updating only a part

of a distribution, either.

Page 68: typemap in Perl/XS

I started writing Convert::H::XS.

https://github.com/charsbar/convert_h_xs

Page 69: typemap in Perl/XS

Convert::H::XS takes a C header file, and looks for the minimum

information to write XS components.

use Convert::H::XS;my $converter = Convert::H::XS->new;$converter->process($h_file);

Page 70: typemap in Perl/XS

Convert::H::XS also provides methods to write XS

components for convenience.

$converter->write_constants( "xs/constants.inc",);

Page 71: typemap in Perl/XS

You can tweak those pieces of information

with a callback.

$converter->write_functions( "xs/functions.inc", sub { my ($type, $name, $args) = @_; ... return ($type, $name, $args);});

Page 72: typemap in Perl/XS

Grateful if you help me improve

this at the hackathon.

Page 73: typemap in Perl/XS

Part V: CPANTS update

Page 74: typemap in Perl/XS

I talked about CPANTS last year.

Page 75: typemap in Perl/XS

CPANTS tests what module authors often

forget to test by themselves.

Page 76: typemap in Perl/XS

Perl QA Hackathon 2013

in Lancaster

Page 77: typemap in Perl/XS

Several metrics are going to be removed.

Page 78: typemap in Perl/XS

Several metrics are going to be added.

Page 79: typemap in Perl/XS

To add new metrics, we need to

find issues.

Page 80: typemap in Perl/XS

Issues are often raised by other QA/toolchain

people.

• Do not ship modules with Module::Install 1.04http://weblog.bulknews.net/post/33907905561/do-not-ship-modules-with-module-install-1-04

• stop shipping MYMETA to CPANhttp://weblog.bulknews.net/post/44251476706/stop-shipping-mymeta-to-cpan

Page 81: typemap in Perl/XS

We need to confirm they are

measurable, and widespread.

Page 82: typemap in Perl/XS

What can I use to confirm?

Page 83: typemap in Perl/XS

• CPANTS databases

• metacpan• CPAN grep

Page 84: typemap in Perl/XS

I just wanted something else.

Page 85: typemap in Perl/XS

Groonga

• a fulltext search engine• a column store• actively developed (monthly

release)

• client/server (http/gqpt)• C API• Web interface

Page 86: typemap in Perl/XS

Groonga::API

https://github.com/charsbar/groonga-api

Page 87: typemap in Perl/XS

Also grateful if you help me improve

this at the hackathon.

Page 88: typemap in Perl/XS

Thank you!