1FFI::Platypus::Bundle(3U)ser Contributed Perl DocumentatiFoFnI::Platypus::Bundle(3)
2
3
4

NAME

6       FFI::Platypus::Bundle - Bundle foreign code with your Perl module
7

VERSION

9       version 1.10
10

SYNOPSIS

12       "ffi/foo.c":
13
14        #include <ffi_platypus_bundle.h>
15        #include <string.h>
16
17        typedef struct {
18          char *name;
19          int value;
20        } foo_t;
21
22        foo_t*
23        foo__new(const char *class_name, const char *name, int value)
24        {
25          (void)class_name;
26          foo_t *self = malloc( sizeof( foo_t ) );
27          self->name = strdup(name);
28          self->value = value;
29          return self;
30        }
31
32        const char *
33        foo__name(foo_t *self)
34        {
35          return self->name;
36        }
37
38        int
39        foo__value(foo_t *self)
40        {
41          return self->value;
42        }
43
44        void
45        foo__DESTROY(foo_t *self)
46        {
47          free(self->name);
48          free(self);
49        }
50
51       "lib/Foo.pm":
52
53        package Foo;
54
55        use strict;
56        use warnings;
57        use FFI::Platypus;
58
59        {
60          my $ffi = FFI::Platypus->new( api => 1 );
61
62          $ffi->type('object(Foo)' => 'foo_t');
63          $ffi->mangler(sub {
64            my $name = shift;
65            $name =~ s/^/foo__/;
66            $name;
67          });
68
69          $ffi->bundle;
70
71          $ffi->attach( new =>     [ 'string', 'string', 'int' ] => 'foo_t'  );
72          $ffi->attach( name =>    [ 'foo_t' ]                   => 'string' );
73          $ffi->attach( value =>   [ 'foo_t' ]                   => 'int'    );
74          $ffi->attach( DESTROY => [ 'foo_t' ]                   => 'void'   );
75        }
76
77        1;
78
79       "t/foo.t"
80
81        use Test::More;
82        use Foo;
83
84        my $foo = Foo->new("platypus", 10);
85        isa_ok $foo, 'Foo';
86        is $foo->name, "platypus";
87        is $foo->value, 10;
88
89        done_testing;
90
91       "Makefile.PL":
92
93        use ExtUtils::MakeMaker;
94        use FFI::Build::MM;
95        my $fbmm = FFI::Build::MM->new;
96        WriteMakefile(
97          $fbmm->mm_args(
98            NAME     => 'Foo',
99            DISTNAME => 'Foo',
100            VERSION  => '1.00',
101            # ...
102          )
103        );
104
105        sub MY::postamble
106        {
107          $fbmm->mm_postamble;
108        }
109
110       or "dist.ini":
111
112        name    = Foo
113        version = 0.01
114        ...
115
116        [FFI::Build]
117        version = 1.04
118

DESCRIPTION

120       This document serves as a tutorial for using the new bundling interface
121       provided by FFI::Platypus as of api version 1.  It requires
122       FFI::Platypus of at least 1.00.
123
124       Sometimes when writing FFI bindings you need to include a little C code
125       (or your favorite compiled language) to finish things off.
126       Alternatively, you might just want to write some C code (or your
127       favorite compiled language) to include with your Perl module to make a
128       tight loop faster.  The bundling interface has you covered.
129
130   Basic example
131       To illustrate we will go through the files in the synopsis and explain
132       how and why they work.  To start with we have some C code which
133       emulates object oriented code using "foo__" as a prefix.  We use a C
134       struct that we call "foo_t" to store our object data.  On the C level
135       the struct acts as a class, when combined with its functions that act
136       as methods.  The constructor just allocates the memory it needs for the
137       "foo_t" instance, fills in the appropriate fields and returns the
138       pointer:
139
140        foo_t*
141        foo__new(const char *class_name, const char *name, int value)
142        {
143          (void) class_name;
144          foo_t *self = malloc( sizeof( foo_t ) );
145          self->name = strdup(name);
146          self->value = value;
147          return self;
148        }
149
150       We include a class name as the first argument, because Perl will
151       include that when calling the constructor, but we do not use it here.
152       An exercise for the reader would be to add hierarchical inheritance.
153
154       There are also some methods which return member values.  This class has
155       only read only members, but you could have read/write or other methods
156       depending on your needs.
157
158        const char *
159        foo__name(foo_t *self)
160        {
161          return self->name;
162        }
163
164       We also include a destructor so that the memory owned by the object can
165       be freed when it is no longer needed.
166
167        void
168        foo__DESTROY(foo_t *self)
169        {
170          free(self->name);
171          free(self);
172        }
173
174       This might start to look a little like a Perl module, and when we look
175       at the Perl code that binds to this code, you will see why.  First lets
176       prepare the FFI::Platypus instance and specify the correct api version:
177
178        my $ffi = FFI::Platypus->new( api => 1 );
179
180       The bundle interface is only supported with api version 1, so if you
181       try to use version 0 it will not work.  Next we define an object type
182       for "foo_t" which will associate it with the Perl class "Foo".
183
184        $ffi->type('object(Foo)' => 'foo_t');
185
186       As object type is a blessed reference to an opaque (default) or integer
187       type which can be used as a Perl object.  Platypus does the translating
188       of Perl object to and from the foo_t pointers that the C code
189       understands.  For more details on Platypus types see
190       FFI::Platypus::Type.
191
192       Next we set the mangler on the Platypus instance so that we can refer
193       to function names without the "foo__" prefix.  You could just not use
194       the prefix in your C code and skip this step, or you could refer to the
195       function names in their full in your Perl code, however, this saves
196       extra typing and allows you to bundle more than one class with your
197       Perl code without having to worry about name conflicts.
198
199        $ffi->mangler(sub {
200          my $name = shift;
201          $name =~ s/^/foo__/;
202          $name;
203        });
204
205       Finally we let Platypus know that we will be bundling code.
206
207        $ffi->bundle;
208
209       By default, this searches for the appropriate place for your dynamic
210       libraries using the current package.  In some cases you may need to
211       override this, for example if your dist is named "Foo-Bar" but your
212       specific class is named "Foo::Bar::Baz", you'd want something like
213       this:
214
215        package Foo::Bar::Baz;
216        use FFI::Platypus;
217        my $ffi = FFI::Platypus->new( api => 1 );
218        $ffi->bundle('Foo::Bar');
219        ...
220
221       Now, finally we can attach the methods for our class:
222
223        $ffi->attach( new =>     [ 'string', 'int' ] => 'foo_t'  );
224        $ffi->attach( name =>    [ 'foo_t' ]         => 'string' );
225        $ffi->attach( value =>   [ 'foo_t' ]         => 'int'    );
226        $ffi->attach( DESTROY => [ 'foo_t' ]         => 'void'   );
227
228       Note that we do not have to include the "foo__" prefix because of the
229       way we set up the mangler.  If we hadn't done that then we could
230       instead attach with the full names:
231
232        $ffi->attach( [ 'foo__new'  => 'new' ]  => [ 'string', 'int' ] => 'foo_t'  );
233        $ffi->attach( [ 'foo__name' => 'name' ] => [ 'foo_t' ]         => 'string' );
234        ...
235
236       You're done!  You can now use this class.  Lets write a test to make
237       sure it works,
238
239        use strict;
240        use warnings;
241        use Test::More;
242        use Foo;
243
244        my $foo = Foo->new("platypus", 10);
245        isa_ok $foo, 'Foo';
246        is $foo->name, "platypus";
247        is $foo->value, 10;
248
249        done_testing;
250
251       and use "prove" to check that it works:
252
253        % prove -lvm
254        t/foo.t ..
255        ok 1 - An object of class 'Foo' isa 'Foo'
256        ok 2
257        ok 3
258        1..3
259        ok
260        All tests successful.
261        Files=1, Tests=3,  0 wallclock secs ( 0.02 usr  0.00 sys +  0.14 cusr  0.03 csys =  0.19 CPU)
262        Result: PASS
263
264       Platypus automatically compiles and links the dynamic library for you:
265
266        % ls ffi/_build
267        foo.c.o  libFoo.so
268
269       The C code will be rebuilt next time if the source code is newer than
270       the object or dynamic libraries files.  If the source files are not
271       changed, then it won't be rebuilt to save time.  If you are using the
272       code without MakeMaker, or another build system you are responsible for
273       cleaning up these files.  This is intended as a convenience to allow
274       you to test your code without having to invoke MakeMaker, or "dzil" or
275       whatever build system you are using.
276
277       When you distribute your module though, you will want the dynamic
278       library built just once at build-time and installed correctly so that
279       it can be found at run-time.  You don't need to make any changes to
280       your C or Perl code, but you do need to tell MakeMaker to build and
281       install the appropriate files using FFI::Build::MM:
282
283        use ExtUtils::MakeMaker;
284        use FFI::Build::MM;
285        my $fbmm = FFI::Build::MM->new;
286        WriteMakefile(
287          $fbmm->mm_args(
288            NAME     => 'Foo',
289            DISTNAME => 'Foo',
290            VERSION  => '1.00',
291            # ...
292          )
293        );
294
295        sub MY::postamble
296        {
297          $fbmm->mm_postamble;
298        }
299
300       And we can invoke all the normal MakeMaker style stuff and our C code
301       will be compiled, linked and installed at the appropriate steps.
302
303        % perl Makefile.PL
304        Generating a Unix-style Makefile
305        Writing Makefile for Foo
306        Writing MYMETA.yml and MYMETA.json
307        % make
308        cp lib/Foo.pm blib/lib/Foo.pm
309        "/Users/ollisg/perl5/perlbrew/perls/perl-5.30.0/bin/perl" -MFFI::Build::MM=cmd -e fbx_build
310        CC ffi/foo.c
311        LD blib/lib/auto/share/dist/Foo/lib/libFoo.dylib
312        % make test
313        "/Users/ollisg/perl5/perlbrew/perls/perl-5.30.0/bin/perl" -MFFI::Build::MM=cmd -e fbx_build
314        "/Users/ollisg/perl5/perlbrew/perls/perl-5.30.0/bin/perl" -MFFI::Build::MM=cmd -e fbx_test
315        PERL_DL_NONLAZY=1 "/Users/ollisg/perl5/perlbrew/perls/perl-5.30.0/bin/perl" "-MExtUtils::Command::MM" "-MTest::Harness" "-e" "undef *Test::Harness::Switches; test_harness(0, 'blib/lib', 'blib/arch')" t/*.t
316        t/foo.t .. ok
317        All tests successful.
318        Files=1, Tests=3,  0 wallclock secs ( 0.01 usr  0.00 sys +  0.06 cusr  0.01 csys =  0.08 CPU)
319        Result: PASS
320
321       If the "Makefile.PL" file above looks overly complicated, you can use
322       the Dist::Zilla::Plugin::FFI::Build plugin to simplify your life if you
323       are using Dist::Zilla:
324
325        [FFI::Build]
326        version = 1.04
327
328       Specifying version 1.04 will ensure that any ".o" or ".so" files are
329       pruned from your build tree and not distributed by mistake.
330
331   Initialization example
332       The bundle interface also gives you entry points which will be called
333       automatically when your code is loaded and unloaded if they are found.
334
335       "ffi_pl_bundle_init"
336            void ffi_pl_bundle_init(const char *package, int argc, void *argv[]);
337
338           Called when the dynamic library is loaded.  "package" is the Perl
339           package that called "bundle" from Perl space.  "argc" and "argv"
340           represents an array of opaque pointers that can be passed as an
341           array to bundle as the last argument.  (the count "argc" is a
342           little redundant because "argv" is also NULL terminated).
343
344       "ffi_pl_bundle_constant"
345            void ffi_pl_bundle_constant(const char *package, ffi_platypus_constant_t *c);
346
347           Called immediately after "ffi_pl_bundle_init", and is intended to
348           allow you to set Perl constants from C space.  For details on how
349           this works and what methods you can call on the
350           "ffi_platypus_constant_t" instance, see FFI::Platypus::Constant.
351
352       "ffi_pl_bundle_fini"
353            void ffi_pl_bundle_fini(const char *package);
354
355           Called when the dynamic library is unloaded.  "package" is the Perl
356           package that called "bundle" from Perl space when the library was
357           loaded.  CAVEAT: if you attach any functions then this will never
358           be called, because attaching functions locks the Platypus instance
359           into memory along with the libraries which it is using.
360
361       Here is an example that passes the version and a callback back into
362       Perl space that emulates the Perl 5.10 "say" feature.
363
364       "ffi/init.c":
365
366        #include <ffi_platypus_bundle.h>
367
368        char buffer[512];
369        const char *version;
370        void (*say)(const char *);
371
372        void
373        ffi_pl_bundle_init(const char *package, int argc, void *argv[])
374        {
375          version = argv[0];
376          say     = argv[1];
377
378          say("in init!");
379
380          snprintf(buffer, 512, "package = %s, version = %s", package, version);
381          say(buffer);
382
383          snprintf(buffer, 512, "args = %d", argc);
384          say(buffer);
385        }
386
387        void
388        ffi_pl_bundle_fini(const char *package)
389        {
390          say("in fini!");
391        }
392
393       "lib/Init.pm":
394
395        package Init;
396
397        use strict;
398        use warnings;
399        use FFI::Platypus;
400
401        our $VERSION = '1.00';
402
403        {
404          my $ffi = FFI::Platypus->new( api => 1 );
405
406          my $say = $ffi->closure(sub {
407            my $string = shift;
408            print "$string\n";
409          });
410
411          $ffi->bundle([
412            $ffi->cast( 'string' => 'opaque', $VERSION ),
413            $ffi->cast( '(string)->void' => 'opaque', $say ),
414          ]);
415
416          undef $ffi;
417          undef $say;
418        }
419
420        1;
421
422       The deinitialization order for the $say callback and the $ffi instance
423       is essential here, so we do it manually with "undef":
424
425        undef $ffi;
426        undef $say;
427
428       First we deallocate $ffi which calls "ffi_pl_bundle_fini", which calls
429       $say, so we want to make sure the latter is still allocated.  Once
430       "ffi_pl_bundle_fini" is done, we can safely deallocate $say.
431
432       If "ffi_pl_bundle_fini" didn't call back into Perl space like this then
433       we don't have to be as careful about deallocating things in Perl space.
434

AUTHOR

436       Author: Graham Ollis <plicease@cpan.org>
437
438       Contributors:
439
440       Bakkiaraj Murugesan (bakkiaraj)
441
442       Dylan Cali (calid)
443
444       pipcet
445
446       Zaki Mughal (zmughal)
447
448       Fitz Elliott (felliott)
449
450       Vickenty Fesunov (vyf)
451
452       Gregor Herrmann (gregoa)
453
454       Shlomi Fish (shlomif)
455
456       Damyan Ivanov
457
458       Ilya Pavlov (Ilya33)
459
460       Petr Pisar (ppisar)
461
462       Mohammad S Anwar (MANWAR)
463
464       Håkon Hægland (hakonhagland, HAKONH)
465
466       Meredith (merrilymeredith, MHOWARD)
467
468       Diab Jerius (DJERIUS)
469
471       This software is copyright (c) 2015,2016,2017,2018,2019 by Graham
472       Ollis.
473
474       This is free software; you can redistribute it and/or modify it under
475       the same terms as the Perl 5 programming language system itself.
476
477
478
479perl v5.30.1                      2020-02-06          FFI::Platypus::Bundle(3)
Impressum