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.58
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 Test2::V0;
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 Test2::V0;
240 use Foo;
241
242 my $foo = Foo->new("platypus", 10);
243 isa_ok $foo, 'Foo';
244 is $foo->name, "platypus";
245 is $foo->value, 10;
246
247 done_testing;
248
249 and use "prove" to check that it works:
250
251 % prove -lvm
252 t/foo.t ..
253 ok 1 - An object of class 'Foo' isa 'Foo'
254 ok 2
255 ok 3
256 1..3
257 ok
258 All tests successful.
259 Files=1, Tests=3, 0 wallclock secs ( 0.02 usr 0.00 sys + 0.14 cusr 0.03 csys = 0.19 CPU)
260 Result: PASS
261
262 Platypus automatically compiles and links the dynamic library for you:
263
264 % ls ffi/_build
265 foo.c.o libFoo.so
266
267 The C code will be rebuilt next time if the source code is newer than
268 the object or dynamic libraries files. If the source files are not
269 changed, then it won't be rebuilt to save time. If you are using the
270 code without MakeMaker, or another build system you are responsible for
271 cleaning up these files. This is intended as a convenience to allow
272 you to test your code without having to invoke MakeMaker, or "dzil" or
273 whatever build system you are using.
274
275 When you distribute your module though, you will want the dynamic
276 library built just once at build-time and installed correctly so that
277 it can be found at run-time. You don't need to make any changes to
278 your C or Perl code, but you do need to tell MakeMaker to build and
279 install the appropriate files using FFI::Build::MM:
280
281 use ExtUtils::MakeMaker;
282 use FFI::Build::MM;
283 my $fbmm = FFI::Build::MM->new;
284 WriteMakefile(
285 $fbmm->mm_args(
286 NAME => 'Foo',
287 DISTNAME => 'Foo',
288 VERSION => '1.00',
289 # ...
290 )
291 );
292
293 sub MY::postamble
294 {
295 $fbmm->mm_postamble;
296 }
297
298 And we can invoke all the normal MakeMaker style stuff and our C code
299 will be compiled, linked and installed at the appropriate steps.
300
301 % perl Makefile.PL
302 Generating a Unix-style Makefile
303 Writing Makefile for Foo
304 Writing MYMETA.yml and MYMETA.json
305 % make
306 cp lib/Foo.pm blib/lib/Foo.pm
307 "/Users/ollisg/perl5/perlbrew/perls/perl-5.30.0/bin/perl" -MFFI::Build::MM=cmd -e fbx_build
308 CC ffi/foo.c
309 LD blib/lib/auto/share/dist/Foo/lib/libFoo.dylib
310 % make test
311 "/Users/ollisg/perl5/perlbrew/perls/perl-5.30.0/bin/perl" -MFFI::Build::MM=cmd -e fbx_build
312 "/Users/ollisg/perl5/perlbrew/perls/perl-5.30.0/bin/perl" -MFFI::Build::MM=cmd -e fbx_test
313 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
314 t/foo.t .. ok
315 All tests successful.
316 Files=1, Tests=3, 0 wallclock secs ( 0.01 usr 0.00 sys + 0.06 cusr 0.01 csys = 0.08 CPU)
317 Result: PASS
318
319 If the "Makefile.PL" file above looks overly complicated, you can use
320 the Dist::Zilla::Plugin::FFI::Build plugin to simplify your life if you
321 are using Dist::Zilla:
322
323 [FFI::Build]
324 version = 1.04
325
326 Specifying version 1.04 will ensure that any ".o" or ".so" files are
327 pruned from your build tree and not distributed by mistake.
328
329 Initialization example
330 The bundle interface also gives you entry points which will be called
331 automatically when your code is loaded and unloaded if they are found.
332
333 "ffi_pl_bundle_init"
334 void ffi_pl_bundle_init(const char *package, int argc, void *argv[]);
335
336 Called when the dynamic library is loaded. "package" is the Perl
337 package that called "bundle" from Perl space. "argc" and "argv"
338 represents an array of opaque pointers that can be passed as an
339 array to bundle as the last argument. (the count "argc" is a
340 little redundant because "argv" is also NULL terminated).
341
342 "ffi_pl_bundle_constant"
343 void ffi_pl_bundle_constant(const char *package, ffi_platypus_constant_t *c);
344
345 Called immediately after "ffi_pl_bundle_init", and is intended to
346 allow you to set Perl constants from C space. For details on how
347 this works and what methods you can call on the
348 "ffi_platypus_constant_t" instance, see FFI::Platypus::Constant.
349
350 "ffi_pl_bundle_fini"
351 void ffi_pl_bundle_fini(const char *package);
352
353 Called when the dynamic library is unloaded. "package" is the Perl
354 package that called "bundle" from Perl space when the library was
355 loaded. CAVEAT: if you attach any functions then this will never
356 be called, because attaching functions locks the Platypus instance
357 into memory along with the libraries which it is using.
358
359 Here is an example that passes the version and a callback back into
360 Perl space that emulates the Perl 5.10 "say" feature.
361
362 "ffi/init.c":
363
364 #include <ffi_platypus_bundle.h>
365
366 char buffer[512];
367 const char *version;
368 void (*say)(const char *);
369
370 void
371 ffi_pl_bundle_init(const char *package, int argc, void *argv[])
372 {
373 version = argv[0];
374 say = argv[1];
375
376 say("in init!");
377
378 snprintf(buffer, 512, "package = %s, version = %s", package, version);
379 say(buffer);
380
381 snprintf(buffer, 512, "args = %d", argc);
382 say(buffer);
383 }
384
385 void
386 ffi_pl_bundle_fini(const char *package)
387 {
388 say("in fini!");
389 }
390
391 "lib/Init.pm":
392
393 package Init;
394
395 use strict;
396 use warnings;
397 use FFI::Platypus 1.00;
398
399 our $VERSION = '1.00';
400
401 {
402 my $ffi = FFI::Platypus->new( api => 1 );
403
404 my $say = $ffi->closure(sub {
405 my $string = shift;
406 print "$string\n";
407 });
408
409 $ffi->bundle([
410 $ffi->cast( 'string' => 'opaque', $VERSION ),
411 $ffi->cast( '(string)->void' => 'opaque', $say ),
412 ]);
413
414 undef $ffi;
415 undef $say;
416 }
417
418 1;
419
420 The deinitialization order for the $say callback and the $ffi instance
421 is essential here, so we do it manually with "undef":
422
423 undef $ffi;
424 undef $say;
425
426 First we deallocate $ffi which calls "ffi_pl_bundle_fini", which calls
427 $say, so we want to make sure the latter is still allocated. Once
428 "ffi_pl_bundle_fini" is done, we can safely deallocate $say.
429
430 If "ffi_pl_bundle_fini" didn't call back into Perl space like this then
431 we don't have to be as careful about deallocating things in Perl space.
432
433 Compiler or linker flags example
434 There are times when you will want to specify your own compiler and
435 linker flags for the C code that you are bundling. The "TL;DR" is that
436 you can put a ".fbx" file in your "ffi" directory. This is a Perl
437 script that returns a hash reference that is passed into the FFI::Build
438 constructor. This allows you to set a number of options, including
439 compiler and linker flags. A more detailed example follows:
440
441 You may want or need to set compiler and linker flags for your bundled
442 C code. For example, say we have a header file, but instead of putting
443 it in the "ffi" directory we want to put it in a separate directory
444 called "include".
445
446 "include/answer.h":
447
448 #ifndef ANSWER_H
449 #define ANSWER_H
450
451 int answer(void);
452
453 #endif
454
455 "ffi/answer.c":
456
457 #include <answer.h>
458
459 int
460 answer(void)
461 {
462 /* the answer to life the universe and everything */
463 return 42;
464 }
465
466 "lib/Answer.pm":
467
468 package Answer;
469
470 use strict;
471 use warnings;
472 use FFI::Platypus 1.00;
473 use Exporter qw( import );
474
475 our @EXPORT = qw( answer );
476
477 my $ffi = FFI::Platypus->new( api => 1 );
478 $ffi->bundle;
479 $ffi->attach( answer => [] => 'int' );
480
481 1;
482
483 If you try to use this module just as-is you will get an error, about
484 not being able to find the header file. Probably something like this:
485
486 ffi/answer.c:1:10: fatal error: 'answer.h' file not found
487
488 So we put a "answer.fbx" file in the "ffi" directory. (In case you are
489 wondering FBX stands for "Ffi Build and file eXtensions should whenever
490 possible be three characters long"). The name of the file can be
491 anything so long as it ends in ".fbx", we just choose "answer" here
492 because that is the name of the project.
493
494 "ffi/answer.fbx":
495
496 our $DIR;
497
498 return {
499 cflags => "-I/include",
500 source => "$DIR/*.c",
501 }
502
503 The $DIR variable is provided by the builder code. It is the root of
504 the distribution, and is helpful if you need a fully qualified path.
505 In this case you could have also used "ffi/*.c".
506
507 The script returns a hash reference which is passed into the FFI::Build
508 constructor, so you can use any of the options supported by that class.
509 Now we should be able to use our bundled module:
510
511 % perl -Ilib -MAnswer=answer -E 'say answer'
512 42
513
514 Using bundled code with Alien.
515 A useful technique is to use Platypus with Alien technology. The Alien
516 namespace is reserved for providing external non-Perl dependencies for
517 CPAN modules. The nominal Alien module when installed looks for the
518 library locally, and if it can't be found it fetches it from the
519 internet, builds it, and installs it in a private directory so that it
520 can be used by other CPAN modules. For Aliens that provide shared
521 libraries, and that have simple interfaces that do not require
522 additional C code you can easily just pass the shared libraries to
523 Platypus directly. For modules that require some bundled C code and an
524 Alien you have to link the Alien library with your bundled code. If
525 the Alien uses the Alien::Base interface then all you have to do is
526 give the name of the Alien to FFI::Build.
527
528 For example, the "bzip2" library provides an interface that requires
529 the caller to allocate a C "struct" and then pass it to its various
530 functions. The "struct" is actually pretty simple and you could use
531 FFI::C or FFI::Platypus::Record, but here is an example of how you
532 would connect bundled C code with an Alien.
533
534 "ffi/compress.c":
535
536 #include <bzlib.h>
537 #include <stdlib.h>
538
539 int
540 bzip2__new(bz_stream **stream, int blockSize100k, int verbosity, int workFactor )
541 {
542 *stream = malloc(sizeof(bz_stream));
543 (*stream)->bzalloc = NULL;
544 (*stream)->bzfree = NULL;
545 (*stream)->opaque = NULL;
546
547 return BZ2_bzCompressInit(*stream, blockSize100k, verbosity, workFactor );
548 }
549
550 "lib/Bzip2.pm":
551
552 package Bzip2;
553
554 use strict;
555 use warnings;
556 use FFI::Platypus 1.00;
557 use FFI::Platypus::Memory qw( free );
558
559 my $ffi = FFI::Platypus->new( api => 1 );
560 $ffi->bundle;
561
562 $ffi->mangler(sub {
563 my $name = shift;
564 $name =~ s/^/bzip2__/ unless $name =~ /^BZ2_/;
565 $name;
566 });
567
568 =head2 new
569
570 my $bzip2 = Bzip2->new($block_size_100k, $verbosity, $work_flow);
571
572 =cut
573
574 $ffi->attach( new => ['opaque*', 'int', 'int', 'int'] => 'int' => sub {
575 my $xsub = shift;
576 my $class = shift;
577 my $ptr;
578 my $ret = $xsub->(\$ptr, @_);
579 return bless \$ptr, $class;
580 });
581
582 $ffi->attach( [ BZ2_bzCompressEnd => 'DESTROY' ] => ['opaque'] => 'int' => sub {
583 my $xsub = shift;
584 my $self = shift;
585 my $ret = $xsub->($$self);
586 free $$self;
587 });
588
589 1;
590
591 The ".fbx" file that goes with this to make it work with Alien::Libbz2
592 is now pretty trivial:
593
594 "ffi/bz2.fbx":
595
596 {
597 alien => ['Alien::Libbz2'],
598 source => ['ffi/*.c'],
599 };
600
602 Author: Graham Ollis <plicease@cpan.org>
603
604 Contributors:
605
606 Bakkiaraj Murugesan (bakkiaraj)
607
608 Dylan Cali (calid)
609
610 pipcet
611
612 Zaki Mughal (zmughal)
613
614 Fitz Elliott (felliott)
615
616 Vickenty Fesunov (vyf)
617
618 Gregor Herrmann (gregoa)
619
620 Shlomi Fish (shlomif)
621
622 Damyan Ivanov
623
624 Ilya Pavlov (Ilya33)
625
626 Petr Písař (ppisar)
627
628 Mohammad S Anwar (MANWAR)
629
630 Håkon Hægland (hakonhagland, HAKONH)
631
632 Meredith (merrilymeredith, MHOWARD)
633
634 Diab Jerius (DJERIUS)
635
636 Eric Brine (IKEGAMI)
637
638 szTheory
639
640 José Joaquín Atria (JJATRIA)
641
642 Pete Houston (openstrike, HOUSTON)
643
645 This software is copyright (c) 2015-2022 by Graham Ollis.
646
647 This is free software; you can redistribute it and/or modify it under
648 the same terms as the Perl 5 programming language system itself.
649
650
651
652perl v5.34.1 2022-06-20 FFI::Platypus::Bundle(3)