• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
C to perl binding
 

C to perl binding

on

  • 4,121 views

An overview about

An overview about

Statistics

Views

Total Views
4,121
Views on SlideShare
4,115
Embed Views
6

Actions

Likes
3
Downloads
0
Comments
0

2 Embeds 6

https://twitter.com 5
http://tweetedtimes.com 1

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    C to perl binding C to perl binding Presentation Transcript

    • XS::TNG
      The current status of Perl-C binding
      ShmuelFomberg
      YAPC Tokyo 2010
    • We have XS, don’t we?
      XS is hard
      Not true. The syntax is simple
      XS is not hard
      But when writing XS you are using:
      XS syntax
      Perl guts
      Typesmaps
      C
      Learning all these in the same time, is hard
    • We are not going to talk about XS
      XS is a known problem
      A lot of documentation on the web
      Most of it outdated or just wrong
      We will talk about:
      Ctypes– calling C libraries from Perl
      Libperl++ - embedding and extending Perl using C++ library
      XS++ - XS – C++ binding
    • Who am I
      A Perl programmer from Israel
      I’m here learning Japanese
      Just started a three month course
      My first YAPC talk
      So, yoroshekoonegaishimasu
    • What is Ctypes?
      Port from Python’s Ctypes
      Good idea / interface
      Still in making
      Not on CPAN yet
      Enable to call C functions inside DLLs, without making XS / intermediate DLL
    • Ctypes
      Now let’s see some code:
      use Ctypes;print chr CDLL->msvcrt->toupper({sig=>"cii"})->(ord("y"));# prints ‘Y’
      # a more verbose style:my $func = Ctypes::Function->new
      ( { lib => 'msvcrt',
      name => 'toupper',
      argtypes => 'ii',
      restype => 'c' } );
      print chr $func->(ord("y"));
      # prints ‘Y’
    • Ctypes
      Let’s see more:
      my $func = WinDLL->user32-> MessageBoxA({sig=>"sipppI"});
      $func->(0, "Hi", "BoxBox", 0);
    • Ctypes – built-in types
      Signature details:
      First char – call type. ‘s’ for stdcall, ‘c’ for cdecl.
      Second char – return type
      The rest - arguments
      v => c_void,c => c_byte,C => c_char,s => c_short,S => c_ushort,i => c_int,I => c_uint,
      l => c_long,L => c_ulong,f => c_float,d => c_double,D => c_longdouble,p => c_void_p,
    • Building types - Simple
      my $array = Array( c_ushort, [ 1, 2, 3, 4, 5 ] );$array->[2] == 3;my $multi = Array( $array, $array2, $array3 ); # multidimensional
      my $ushort = c_ushort(25);my $ushortp = Pointer($ushort);$$ushortp == $ushort;${$$ushortp} == 25;
    • Building types – Ad-hoc
      my $struct = Struct([  f1 => c_char('P'),  f2 => c_int(10),  f3 => c_long(90000),]);
      $struct->size == Ctypes::sizeof('c') + Ctypes::sizeof('i') + Ctypes::sizeof('l');$$struct->{f2} == 10;
      my $alignedstruct = Struct({  fields => [   o1 => c_char('Q'),   o2 => c_int(20),   o3 => c_long(180000),  ],  align => 4,});
    • Building types – Callback
      sub cb_func {  my( $ay, $bee ) = @_; return $ay <=> $bee;}
      my $qsort = Ctypes::Function->new  ( { lib    => 'c', name   => 'qsort',   argtypes => 'piip‘, restype => 'v‘, } );
      $cb = Ctypes::Callback->new( &cb_func, 'i', ‘ss');
      my $disarray = Array(c_short , [2, 4, 5, 1, 3] );$qsort->($disarray, $#$disarray+1, Ctypes::sizeof('s'), $cb->ptr);$disarray->_update_;$disarray->[2] == 3
    • Ctypes – Libraries types
      CDLL
      Return type ‘i’, calling style ‘cdecl’
      WinDLL
      Return type ‘i’, calling style ‘stdcall’
      OleDLL
      Calling style “stdcall”
      Return type HRESULT
      Will throw exception automatically on error
    • Ctypes – Libraries types
      PerlDLL
      For calling Perl XS functions
      provides XS environment for the called function
      Checks the Perl error flag after the call
      If there was an exception – re-throws
    • Libperl++
      Extending and Embedding Perl
      The goal: to let C++ do the hard work for you
      Reference counting
      Call stack operations
      Type conversions
      Exception conversions
      http://github.com/Leont/libperl--
    • Libperl++ - Embedding
      Let’s see some code:
      Interpreter universe;universe.use("Carp", 1.000); bool success = universe.eval("print qq{Hello World }");
      # acessing / creating global variables
      universe.scalar("status") = 404;
      universe.hash("table").exists("hello");
      # creates @Module::data :
      Array data = universe.array("Module::data");
    • Libperl++ - Extending
      Let’s say we have this C++ code:
      class player {
      string get_name() const;
      pair<int, int> get_position() const;
      void set_position(pair<int, int>);
      double get_strength() const;
      void set_strength(double);
      void die(string);
      };
    • Libperl++ - Extending
      It can be exported like this:
      Class<player> player_class = universe.add_class("Player"); player_class.add("get_name", &player::get_name); player_class.add("get_position", &player::get_position); player_class.add("set_position", &player::set_position); player_class.add("get_strength", &player::get_strength); player_class.add("set_strength", &player::set_strength); player_class.add("die", &player::die);
      The first line connects a C++ class “player” with
      Perl class “Player”, then we add each method
    • Libperl++ - Extending
      Of course, we can add a plain
      (non-object) module
      Package somewhere = universe.package("foo");
      somewhere.add("other_name", some_function);
    • Libperl++ - Extending
      And the Perl side:
      package Extend;
      use strict;
      use warnings;
      use Exporter 5.57 qw/import/;
      our @EXPORT_OK = qw/hello/;
      use Perlpp::Extend;
      1;
    • Libperl++ - Calling Perl
      You really don’t want to know how much work is to call Perl function from C
      Here is how to do it with Libperl++:
      Ref<Code> some_function = universe.code("some_function");
      some_function("Hello World"); // in scalar context
      some_function.list("Hello World"); // in list context
    • Libperl++ - Calling Perl
      Also works for objects:
      Ref<Any> testr = universe.package("Tester").call("new", 1);
      testr.call("print");
      testr.call("set", 3);
      testr.call("print");
      // automatically calls ‘DESTROY’
    • Libperl++ - Scalars
      Scalar value = universe.value_of(1);
      value += 2;
      // can use all normal operators: + - * / % == > < =
      value = "1"; // the same as setting to 1
      String value = universe.value_of("test");
      value == std::string("test"); // convertible to/from std::string
      value.replace(2, 2, value); // now contains ‘tetest’
      value.insert(2, "st"); // now contains ‘testtest’
      value = "test"; // simple assignment
    • Libperl++ - Arrays
      first
      max
      min
      shuffledsum
      any
      all
      none
      begin/end
      rbegin/rend
      push
      pop
      shift
      unshift
      reverse
      remove
      exists
      length
      clear
      each
      each_index
      map
      grep
      reduce
      Array bar = universe.list("a", "b");int length = bar.length();cout << "bla is " << baz[1] << endl; bar[4] = "e";
      void test(const Scalar::Base& val);
      std::for_each(bar.begin(), bar.end(), test);
      int converter(int arg);
      Array singles = universe.list(1, 2, 3, 4); singles.map(converter).each(test);
    • Libperl++ - Hashs
      insert
      exists
      erase
      clear
      length
      each
      keys
      values
      Hash map = universe.hash();
      map["test"] = "duck";
      map["foo" ] = "bar";
      void printer(const char *key,
      const Scalar::Base& value);
      map.each(printer);
    • Libperl++ - References
      Any Perl variable support take_ref()
      Ref<Scalar> value = universe.value_of(1).take_ref();
      Reference can be specific or generic
      Ref<Scalar>, Ref<Integer>, Ref<Number>, Ref<Any>, Ref<Hash>
      Reference tries to give operations shortcuts to the contained element
      Ref<Hash> ref = hash.take_ref();
      ref["foo"] = "rab";
      is_object
      isa
      is_exactly
      weaken
      bless
      get_classname
    • Libperl++ - custom type convertion
      structmy_type {
      int value;
      my_type(int _value) : value(_value) {}
      };namespace perl {
      namespace typecast {
      template<> structtypemap<my_type> {
      static my_typecast_to(const Scalar::Base& value) {
      return my_type(value.int_value());
      }
      typedef boost::true_typefrom_type;
      static intcast_from(Interpreter&, const my_type& variable) {
      return variable.value;
      }
      };
      }
      }
      Signals that this type can be converted to Perl type
      Can construct any Perl type, (using the interpreter) or any type convertible
    • ExtUtils::XSpp
      XS does not handle objects
      Only functions and constants
      You can write the object binding yourself
      Much fun
      XS++ fills the gap
      “transparent C++ objects in Perl”
    • ExtUtils::XSpp
      It is still XS
      So you need to know all the XS keywords, Perl internals and typemaps
      Plus adds its own little language
      Everything is translated back to XS for compilation
      Module::Build::WithXSpp
      See ExtUtils::XSpp’s example
    • XS++ - XSpp::Example.pm
      package XSpp::Example; use strict; use warnings;
      our $VERSION = '0.01';
      require XSLoader; XSLoader::load('XSpp::Example', $VERSION);
      1;
    • XS++ - C++ headers
      class Animal { public: Animal(const std::string& name); void SetName(const std::string& newName); std::string GetName() const; void MakeSound() const;
      private:
      std::string fName; };
      class Dog : public Animal {
      public:
      Dog(const std::string& name);
      void Bark() const;
      void MakeSound() const;
      };
    • XS++ - xsp file
      #include "Animals.h"
      %module{XSpp::Example};
      class Animal {
      %name{new} Animal(std::string& name);
      ~Animal();
      void MakeSound();
      void SetName(std::string& newName);
      std::string GetName();
      };
      class Dog : public Animal {
      %name{new} Dog(std::string& name);
      ~Dog();
      void MakeSound();
      void Bark();
      };
    • XS++ - Dog.cc
      #include "Animals.h"
      Dog::Dog(const std::string& name) : Animal(name) {}
      void Dog::Bark() const {
      cout << "Woof" << endl;
      }
      void Dog::MakeSound() const {
      Bark();
      }
    • XS++ - Build.PL
      #!/usr/bin/perl -w
      use strict;
      use Module::Build::WithXSpp;
      my $build = Module::Build::WithXSpp->new(
      module_name => 'XSpp::Example',
      license => 'perl',
      requires => {},
      # Provides extra C typemaps for opaque objects:
      extra_typemap_modules => {
      'ExtUtils::Typemap::ObjectMap' => '0.01',
      },
      );
      $build->create_build_script;
    • XS++ - mytype.map
      Animal* O_OBJECT
      Dog* O_OBJECT
      std::string* T_STRINGPTR
      std::string T_STRING
      INPUT
      T_STRING
      $var = std::string(SvPV_nolen($arg))
      T_STRINGPTR
      $var = new std::string(SvPV_nolen($arg))
      OUTPUT
      T_STRING
      $arg = newSVpvn($var.c_str(), $var.length());
      T_STRINGPTR
      $arg = newSVpvn($var->c_str(), $var->length());
      Declare these types as objects to export to Perl space
    • More about typemaps
      ExtUtils::Typemap::Default
      And the other modules in that distribution
    • Thank you
    • Building Libffi
      Download from: http://github.com/atgreen/libffi
      Target platform: Strawberry Perl 5.12
      Needed tools: cygwin
      with make, without gcc
      To build:
      copy src/x86/ffitarget.h to include/ffitarget.h
      run bash
      run configure
      run make
      It will produce binaries in the “.lib” directory:
      Libffi.* => strewberryperl/c/lib
      cygffi-5.dll => strewberryperl/c/bin
    • Building Ctypes
      Download from:
      http://gitorious.org/perl-ctypes
      http://socghop.appspot.com/gsoc/student_project/show/google/gsoc2010/tpf/t127230763807
      Make sure that cygwin is not available
      perl Makefile.pl, dmake – test – install
    • Building Libperl++
      You need C++ Boost
      http://www.boost.org/
      But only the headers
      Libperl++ is a heavy C++ templates user
      Using Module::Build style installer
      perl Build.PL
      perl Build
      perl Build test
      perl Build install
    • Building types - Point
      package t_POINT;use strict;use warnings;use Ctypes;use Ctypes::Type::Struct;our @ISA = qw|Ctypes::Type::Struct|;our $_fields_ = [ ['x',c_int], ['y',c_int], ];
      sub new { my $class = ref($_[0]) || $_[0]; shift; my $self = $class->SUPER::new({fields => $_fields_, values => [ @_ ] }); return bless $self => $class if $self;}
    • Building types - Point
      my $point = new t_POINT( 30, 40 );$$point->{x} == 30;$$point->{y} == 40;$$point->[0] == 30;$$point->[1] == 40;
      # yes, it is overloaded
      my $point_2 = new t_POINT([ y => 30, x => 40 ]);my $point_3 = new t_POINT([ y => 50 ]);