File Coverage

blib/lib/FFI/Platypus/Lang/CPP.pm
Criterion Covered Total %
statement 27 27 100.0
branch 5 6 83.3
condition n/a
subroutine 9 9 100.0
pod 2 2 100.0
total 43 44 97.7


line stmt bran cond sub pod time code
1             package FFI::Platypus::Lang::CPP;
2              
3 4     4   129350 use strict;
  4         20  
  4         123  
4 4     4   22 use warnings;
  4         7  
  4         115  
5 4     4   1886 use FFI::ExtractSymbols qw( extract_symbols );
  4         22082  
  4         243  
6 4     4   1482 use FFI::Platypus 1.00;
  4         16777  
  4         1438  
7              
8             our $VERSION = '0.05';
9              
10             =head1 NAME
11              
12             FFI::Platypus::Lang::CPP - Documentation and tools for using Platypus with
13             the C++ programming language
14              
15             =head1 SYNOPSIS
16              
17             B: The original author of this module considered the techniques used by and
18             documented by this module to be somewhate experimental even back in 2015 when he
19             wrote it. The original author now thinks that it is probably safer to write a C API
20             layer between your C++ library and Perl rather than try to call C++ directly as
21             advocated by this module. While the original author has not yet deprecated this
22             module, users of this module should consider its limitations before using it.
23              
24             C++:
25              
26             // on Linux compile with: g++ --shared -o basic.so basic.cpp
27             // elsewhere, consult your C++ compiler documentation
28            
29             class Foo {
30            
31             public:
32            
33             // note you should avoid inlining functions
34             // for classes you intend to use with FFI
35             // as the compiler may not emit code/symbols
36             // for those functions.
37             Foo();
38             ~Foo();
39            
40             int get_bar();
41             void set_bar(int);
42            
43             int _size();
44            
45             private:
46            
47             int bar;
48            
49             };
50            
51             Foo::Foo()
52             {
53             bar = 0;
54             }
55            
56             Foo::~Foo()
57             {
58             }
59            
60             int
61             Foo::get_bar()
62             {
63             return bar;
64             }
65            
66             void
67             Foo::set_bar(int value)
68             {
69             bar = value;
70             }
71            
72             int
73             Foo::_size()
74             {
75             return sizeof(Foo);
76             }
77              
78             Perl:
79              
80             package Foo;
81            
82             use FFI::Platypus 1.00;
83             use FFI::Platypus::Memory qw( malloc free );
84            
85             my $ffi = FFI::Platypus->new( api => 1 )
86             $ffi->lang('CPP');
87             $ffi->lib('./basic.so');
88            
89             $ffi->custom_type( Foo => {
90             native_type => 'opaque',
91             perl_to_native => sub { ${ $_[0] } },
92             native_to_perl => sub { bless \$_[0], 'Foo' },
93             });
94            
95             $ffi->attach( [ 'Foo::Foo()' => '_new' ] => ['Foo'] => 'void' );
96             $ffi->attach( [ 'Foo::~Foo()' => '_DESTROY' ] => ['Foo'] => 'void' );
97             $ffi->attach( [ 'Foo::get_bar()' => 'get_bar' ] => ['Foo'] => 'int' );
98             $ffi->attach( [ 'Foo::set_bar(int)'
99             => 'set_bar' ] => ['Foo','int']
100             => 'void' );
101            
102             my $size = $ffi->function('Foo::_size()' => [] => 'int')->call;
103            
104             sub new
105             {
106             my($class) = @_;
107             my $ptr = malloc $size;
108             my $self = bless \$ptr, $class;
109             _new($self);
110             $self;
111             }
112            
113             sub DESTROY
114             {
115             my($self) = @_;
116             _DESTROY($self);
117             free($$self);
118             }
119            
120             package main;
121            
122             my $foo = Foo->new;
123            
124             print $foo->get_bar, "\n"; # 0
125             $foo->set_bar(22);
126             print $foo->get_bar. "\n"; # 22
127              
128             =head1 DESCRIPTION
129              
130             This module provides some hooks for Platypus so that C++ names can be
131             mangled for you. It uses the same primitive types as C. This document
132             also documents issues and caveats that I have discovered in my attempts
133             to work with C++ and FFI.
134              
135             This module is somewhat experimental. It is also available for adoption
136             for anyone either sufficiently knowledgable about C++ or eager enough to
137             learn enough about C++. If you are interested, please send me a pull
138             request or two on the project's GitHub.
139              
140             There are numerous difficulties and caveats involved in using C++
141             libraries from Perl via FFI. This document is intended to enlighten on
142             that subject.
143              
144             Note that in addition to using pre-compiled C++ libraries you can bundle
145             C++ code with your Perl distribution using L. For a
146             complete example, which attempts to address the caveats listed below you
147             can take a look at this sample distro on GitHub:
148              
149             L
150              
151             =head1 CAVEATS
152              
153             In general I have done my research of FFI and C++ using the Gnu C++
154             compiler. I have done some testing with C as well.
155              
156             =head2 name mangling
157              
158             C++ names are "mangled" to handle features such as function overloading
159             and the fact that some characters in the C++ names are illegal machine
160             code symbol names. What this means is that the C++ member function
161             C looks like C<_ZN3Foo7get_barEv> to L.
162             What makes this even trickier is that different C++ compilers provide
163             different mangling formats. When you use the L
164             method to tell Platypus that you are intending to use it with C++, like
165             this:
166              
167             $ffi->lang('CPP');
168              
169             it will mangle the names that you give it. That saves you having to
170             figure out the "real" name for C.
171              
172             The current implementation uses the C command or
173             L if it is installed. If
174             C cannot be found at install time, then
175             L will be made a prerequsite, so
176             you can have some confidence that this feature will work even if your
177             platform does not provide C. The XS module is not a
178             prerequsite when C IS found because using C does not
179             require invoking the compiler and may be more reliable.
180              
181             If the approach to mangling C++ names described above does not work for
182             you, or if it makes you feel slightly queasy, then you can also write C
183             wrapper functions around each C++ method that you want to call from
184             Perl. You can write these wrapper functions right in your C++ code
185             using the C trick:
186              
187             class Foo {
188             public:
189             int bar() { return 1; }
190             }
191            
192             extern "C" int
193             my_bar(Class *foo)
194             {
195             return foo->bar();
196             }
197              
198             Then instead of attaching C attach C.
199              
200             $ffi->attach( my_bar => [ 'Foo' ] => 'int' );
201              
202             =head2 constructors, destructors and methods
203              
204             Constructors and destructors are essentially just functions that do not
205             return a value that need to be called when the object is created and
206             when it is no longer needed (respectively). They take a pointer to the
207             object (C) as their first argument. Constructors can take
208             additional arguments, as you might expect they just come after the
209             object itself. Destructors take no arguments other than the object
210             itself (C).
211              
212             You need to alloate the memory needed for the object before you call the
213             constructor and free it after calling the destructor. The tricky bit is
214             figuring out how much memory to allocate. If you have access to the
215             header file that describes the class and a compiler you can compute the
216             size from within C++ and hand it off to Perl using a static method as I
217             did in the L above.
218              
219             Regular methods also take the object pointer as their first argument.
220             Additional arguments follow, and they may or may not return a value.
221              
222             =head2 inline functions
223              
224             C++ compilers typically do not emit symbols for inlined functions. If
225             you get a message like this:
226              
227             unable to find Foo::get_bar() at basic line 21
228              
229             even though you are sure that class has that method, this is probably
230             the problem that you are having. The Gnu C++ compiler, C has an
231             option to force it to emit the symbols, even for inlined functions:
232              
233             -fkeep-inline-functions # use this
234              
235             Clang has an option to do the opposite of this:
236              
237             -fvisibility-inlines-hidden # do not use this
238              
239             but unhelpfully not a way to keep inlined functions. This appears to be
240             a deliberate design decision made by the clang developers and it makes
241             sense for C++, since inline functions are typically defined in C++
242             header files (.h) so it is difficult to determine in which object file
243             the uninlined inlined functions should go.
244              
245             If you have the source of the C++ and you can recompile it you can also
246             optionally change it to not use inlined functions. In addition to
247             removing any C keywords from the source, you need to move the
248             implementations of any methods outside of the class body. That is, do
249             not do this:
250              
251             class Foo {
252             public:
253             int bar() { return 1; } # WRONG
254             }
255              
256             Do this:
257              
258             class Foo {
259             public:
260             int bar(); # RIGHT
261             }
262            
263             int
264             Foo::bar() # RIGHT
265             {
266             return 1;
267             }
268              
269             =head2 the standard C++ library
270              
271             If you are getting errors like this:
272              
273             unable to find Foo::Foo()
274              
275             that can't be explained by the issues described above, set the
276             environment variable FFI_PLATYPUS_DLERROR to a true value and try again.
277             If you see a warning like this:
278              
279             error loading Foo.so: Foo.so: undefined symbol: __gxx_personality_v0
280              
281             then you probably need to explicitly link with the standard C++ library.
282             The most portable way to deal with this is by using
283             L.
284              
285             =head1 METHODS
286              
287             Generally you will not use this class directly, instead interacting with
288             the L instance. However, the public methods used by
289             Platypus are documented here.
290              
291             =head2 native_type_map
292              
293             my $hashref = FFI::Platypus::Lang::CPP->native_type_map;
294              
295             This returns a hash reference containing the native aliases for the
296             C++ programming languages. That is the keys are native C++ types and the
297             values are libffi native types.
298              
299             =cut
300              
301             sub native_type_map
302             {
303 3     3 1 1165 require FFI::Platypus::Lang::C;
304 3         282 return FFI::Platypus::Lang::C->native_type_map;
305             }
306              
307             =head2 mangler
308              
309             my $mangler = FFI::Platypus::Lang::CPP->mangler($ffi->libs);
310             # prints _ZN9MyInteger7int_sumEii
311             print $mangler->("MyInteger::int_sum(int, int)");
312              
313             Returns a subroutine reference that will "mangle" C++ names.
314              
315             =cut
316              
317             if(eval { require FFI::Platypus::Lang::CPP::Demangle::XS })
318             {
319             *_demangle = \&FFI::Platypus::Lang::CPP::Demangle::XS::demangle;
320             }
321             else
322             {
323 6     6   21020 *_demangle = sub { `c++filt $_[0]` };
324             }
325              
326             sub mangler
327             {
328 1     1 1 1359 my($class, @libs) = @_;
329              
330 1         2 my %mangle;
331              
332 1         2 foreach my $libpath (@libs)
333             {
334             extract_symbols($libpath,
335             export => sub {
336 6     6   5071 my($symbol1, $symbol2) = @_;
337 6         79 my $cpp_symbol = _demangle($symbol2);
338 6 50       110 return unless defined $cpp_symbol;
339 6         19 chomp $cpp_symbol;
340 6 100       123 return if $cpp_symbol eq $symbol2;
341 1         29 $mangle{$cpp_symbol} = $symbol1;
342             },
343 1         7 );
344             }
345              
346             sub {
347 2 100   2   2400 defined $mangle{$_[0]} ? $mangle{$_[0]} : $_[0];
348 1         124 };
349             }
350              
351             1;
352              
353             =head1 EXAMPLES
354              
355             =head2 Using a C++ class without writing bundling any C/C++ code
356              
357             The example in the L shows how you I use a C++ class
358             without writing any wrapper code, though you will have to guess or
359             determine the instance size of the class.
360              
361             =head2 Using a C++ class with a wrapper
362              
363             (For the full source for this example, see examples/wrapper.{pl,cpp}
364             that came with this distribution)
365              
366             Sometimes it is easier to write wrapper functions around your new and
367             delete operations. Consider if you add these functions to the C++
368             source to the example in the L.
369              
370             // These could also be class methods
371             extern "C" Foo*
372             Foo_new()
373             {
374             return new Foo();
375             }
376            
377             extern "C" void
378             Foo_delete(Foo *foo)
379             {
380             delete foo;
381             }
382              
383             Now we can use this class without having to know I
384             what the size of the class is. We declare the constructor and
385             destructor in Perl space like this:
386              
387             $ffi->attach( [ 'Foo_new' => 'new' ] => [] => 'Foo' );
388             $ffi->attach( [ 'Foo_delete' => 'DESTROY' ] => ['Foo'] => 'void' );
389              
390             We've also removed the Perl C and C wrappers as they are
391             unnecessary now, and so the the C++ functions are attached directly to
392             their intended names.
393              
394             =head2 Exceptions
395              
396             (For the full source of this example, see examples/exception.{pl,cpp}
397             that came with this distribution)
398              
399             If your library throws an exception and you do not catch it in C++ it
400             is going to kill your program. As an example, suppose C in
401             the example above throws an exception:
402              
403             void
404             Foo::set_bar(int value)
405             {
406             if(value > 512)
407             throw new FooException("too hot");
408             if(value < 0)
409             throw new FooException("too cold");
410             bar = value;
411             }
412              
413             Now if you try to use C with a bad value like this from Perl:
414              
415             $foo->set_bar(-2);
416              
417             it will crash your Perl program.
418              
419             terminate called after throwing an instance of 'FooException'
420             Abort
421              
422             To handle this, you need to write a wrapper around the C
423             method.
424              
425             static FooException *last_exception = NULL;
426            
427             extern "C" FooException *
428             Foo_get_exception()
429             {
430             return last_exception;
431             }
432            
433             extern "C" void
434             Foo_reset_exception()
435             {
436             if(last_exception != NULL)
437             delete last_exception;
438             last_exception = NULL;
439             }
440            
441             extern "C" void
442             Foo_set_bar(Foo *foo, int value)
443             {
444             try
445             {
446             Foo_reset_exception();
447             foo->set_bar(value);
448             }
449             catch(FooException *e)
450             {
451             last_exception = e;
452             }
453             }
454              
455             Next we will write an interface to the FooException class in Perl:
456              
457             package FooException;
458            
459             use overload '""' => sub { "exception: " . $_[0]->message . "\n" };
460            
461             $ffi->custom_type( FooException => {
462             native_type => 'opaque',
463             perl_to_native => sub { ${ $_[0] } },
464             native_to_perl => sub {
465             defined $_[0]
466             ? (bless \$_[0], 'FooException')
467             : ();
468             },
469             });
470            
471             $ffi->attach(
472             [ 'Foo_get_exception' => 'get_exception' ] => [] => 'FooException'
473             );
474            
475             $ffi->attach(
476             [ 'FooException::message()' => 'message' ] => ['FooException'] => 'string'
477             );
478              
479             And finally we write a wrapper for the Perl C method.
480              
481             $ffi->attach( [ 'Foo_set_bar' => '_set_bar' ] => ['Foo','int']
482             => 'void' );
483             sub set_bar
484             {
485             my($self, $value) = @_;
486             $self->_set_bar($value);
487             my $error = FooException->get_exception;
488             die $error if $error;
489             }
490              
491             And now when we give C a bogus value we get a Perl exception
492             instead of an application crash:
493              
494             exception: too cold
495              
496             So we can easily wrap the call to C in a Perl eval if we want
497             to catch the exception and handle it.
498              
499             =head1 SUPPORT
500              
501             If something does not work as advertised, or the way that you think it
502             should, or if you have a feature request, please open an issue on this
503             project's GitHub issue tracker:
504              
505             L
506              
507             =head1 CONTRIBUTING
508              
509             If you have implemented a new feature or fixed a bug then you may make a
510             pull reequest on this project's GitHub repository:
511              
512             L
513              
514             Caution: if you do this too frequently I may nominate you as the new
515             maintainer. Extreme caution: if you like that sort of thing.
516              
517             This project's GitHub issue tracker listed above is not Write-Only. If
518             you want to contribute then feel free to browse through the existing
519             issues and see if there is something you feel you might be good at and
520             take a whack at the problem. I frequently open issues myself that I
521             hope will be accomplished by someone in the future but do not have time
522             to immediately implement myself.
523              
524             Another good area to help out in is documentation. I try to make sure
525             that there is good document coverage, that is there should be
526             documentation describing all the public features and warnings about
527             common pitfalls, but an outsider's or alternate view point on such
528             things would be welcome; if you see something confusing or lacks
529             sufficient detail I encourage documentation only pull requests to
530             improve things.
531              
532             =head1 SEE ALSO
533              
534             =over 4
535              
536             =item L
537              
538             The Core Platypus documentation.
539              
540             =item L + L
541              
542             Bundle C or C++ with your FFI / Perl extension.
543              
544             =item L
545              
546             Guess the appropriate C++ compiler / linker flags for your C compiler
547             platform combination.
548              
549             =back
550              
551             =head1 AUTHOR
552              
553             Graham Ollis Eplicease@cpan.orgE
554              
555             =head1 COPYRIGHT AND LICENSE
556              
557             This software is copyright (c) 2015 by Graham Ollis.
558              
559             This is free software; you can redistribute it and/or modify it under
560             the same terms as the Perl 5 programming language system itself.
561              
562             =cut
563