1FFI::Platypus::Bundle(3U)ser Contributed Perl DocumentatiFoFnI::Platypus::Bundle(3)
2
3
4
6 FFI::Platypus::Bundle - Bundle foreign code with your Perl module
7
9 version 1.43
10
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 1.00;
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
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 1.00;
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 1.00;
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
435 Compiler or linker flags example
436 There are times when you will want to specify your own compiler and
437 linker flags for the C code that you are bundling. The "TL;DR" is that
438 you can put a ".fbx" file in your "ffi" directory. This is a Perl
439 script that returns a hash reference that is passed into the FFI::Build
440 constructor. This allows you to set a number of options, including
441 compiler and linker flags. A more detailed example follows:
442
443 You may want or need to set compiler and linker flags for your bundled
444 C code. For example, say we have a header file, but instead of putting
445 it in the "ffi" directory we want to put it in a separate directory
446 called "include".
447
448 "include/answer.h":
449
450 #ifndef ANSWER_H
451 #define ANSWER_H
452
453 int answer(void);
454
455 #endif
456
457 "ffi/answer.c":
458
459 #include <answer.h>
460
461 int
462 answer(void)
463 {
464 /* the answer to life the universe and everything */
465 return 42;
466 }
467
468 "lib/Answer.pm":
469
470 package Answer;
471
472 use strict;
473 use warnings;
474 use FFI::Platypus 1.00;
475 use base qw( Exporter );
476
477 our @EXPORT = qw( answer );
478
479 my $ffi = FFI::Platypus->new( api => 1 );
480 $ffi->bundle;
481 $ffi->attach( answer => [] => 'int' );
482
483 1;
484
485 If you try to use this module just as-is you will get an error, about
486 not being able to find the header file. Probably something like this:
487
488 ffi/answer.c:1:10: fatal error: 'answer.h' file not found
489
490 So we put a "answer.fbx" file in the "ffi" directory. (In case you are
491 wondering FBX stands for "Ffi Build and file eXtensions should whenever
492 possible be three characters long"). The name of the file can be
493 anything so long as it ends in ".fbx", we just choose "answer" here
494 because that is the name of the project.
495
496 "ffi/answer.fbx":
497
498 our $DIR;
499
500 return {
501 cflags => "-I/include",
502 source => "$DIR/*.c",
503 }
504
505 The $DIR variable is provided by the builder code. It is the root of
506 the distribution, and is helpful if you need a fully qualified path.
507 In this case you could have also used "ffi/*.c".
508
509 The script returns a hash reference which is passed into the FFI::Build
510 constructor, so you can use any of the options supported by that class.
511 Now we should be able to use our bundled module:
512
513 % perl -Ilib -MAnswer=answer -E 'say answer'
514 42
515
516 Using bundled code with Alien.
517 A useful technique is to use Platypus with Alien technology. The Alien
518 namespace is reserved for providing external non-Perl dependencies for
519 CPAN modules. The nominal Alien module when installed looks for the
520 library locally, and if it can't be found it fetches it from the
521 internet, builds it, and installs it in a private directory so that it
522 can be used by other CPAN modules. For Aliens that provide shared
523 libraries, and that have simple interfaces that do not require
524 additional C code you can easily just pass the shared libraries to
525 Platypus directly. For modules that require some bundled C code and an
526 Alien you have to link the Alien library with your bundled code. If
527 the Alien uses the Alien::Base interface then all you have to do is
528 give the name of the Alien to FFI::Build.
529
530 For example, the "bzip2" library provides an interface that requires
531 the caller to allocate a C "struct" and then pass it to its various
532 functions. The "struct" is actually pretty simple and you could use
533 FFI::C or FFI::Platypus::Record, but here is an example of how you
534 would connect bundled C code with an Alien.
535
536 "ffi/compress.c":
537
538 #include <bzlib.h>
539 #include <stdlib.h>
540
541 int
542 bzip2__new(bz_stream **stream, int blockSize100k, int verbosity, int workFactor )
543 {
544 *stream = malloc(sizeof(bz_stream));
545 (*stream)->bzalloc = NULL;
546 (*stream)->bzfree = NULL;
547 (*stream)->opaque = NULL;
548
549 return BZ2_bzCompressInit(*stream, blockSize100k, verbosity, workFactor );
550 }
551
552 "lib/Bzip2.pm":
553
554 package Bzip2;
555
556 use strict;
557 use warnings;
558 use FFI::Platypus 1.00;
559 use FFI::Platypus::Memory qw( free );
560
561 my $ffi = FFI::Platypus->new( api => 1 );
562 $ffi->bundle;
563
564 $ffi->mangler(sub {
565 my $name = shift;
566 $name =~ s/^/bzip2__/ unless $name =~ /^BZ2_/;
567 $name;
568 });
569
570 =head2 new
571
572 my $bzip2 = Bzip2->new($block_size_100k, $verbosity, $work_flow);
573
574 =cut
575
576 $ffi->attach( new => ['opaque*', 'int', 'int', 'int'] => 'int' => sub {
577 my $xsub = shift;
578 my $class = shift;
579 my $ptr;
580 my $ret = $xsub->(\$ptr, @_);
581 return bless \$ptr, $class;
582 });
583
584 $ffi->attach( [ BZ2_bzCompressEnd => 'DESTROY' ] => ['opaque'] => 'int' => sub {
585 my $xsub = shift;
586 my $self = shift;
587 my $ret = $xsub->($$self);
588 free $$self;
589 });
590
591 1;
592
593 The ".fbx" file that goes with this to make it work with Alien::Libbz2
594 is now pretty trivial:
595
596 "ffi/bz2.fbx":
597
598 {
599 alien => ['Alien::Libbz2'],
600 source => ['ffi/*.c'],
601 };
602
604 Author: Graham Ollis <plicease@cpan.org>
605
606 Contributors:
607
608 Bakkiaraj Murugesan (bakkiaraj)
609
610 Dylan Cali (calid)
611
612 pipcet
613
614 Zaki Mughal (zmughal)
615
616 Fitz Elliott (felliott)
617
618 Vickenty Fesunov (vyf)
619
620 Gregor Herrmann (gregoa)
621
622 Shlomi Fish (shlomif)
623
624 Damyan Ivanov
625
626 Ilya Pavlov (Ilya33)
627
628 Petr Pisar (ppisar)
629
630 Mohammad S Anwar (MANWAR)
631
632 Håkon Hægland (hakonhagland, HAKONH)
633
634 Meredith (merrilymeredith, MHOWARD)
635
636 Diab Jerius (DJERIUS)
637
638 Eric Brine (IKEGAMI)
639
640 szTheory
641
643 This software is copyright (c) 2015,2016,2017,2018,2019,2020 by Graham
644 Ollis.
645
646 This is free software; you can redistribute it and/or modify it under
647 the same terms as the Perl 5 programming language system itself.
648
649
650
651perl v5.32.1 2021-03-18 FFI::Platypus::Bundle(3)