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   112792 use strict;
  4         17  
  4         109  
4 4     4   17 use warnings;
  4         6  
  4         107  
5 4     4   1574 use FFI::ExtractSymbols qw( extract_symbols );
  4         19001  
  4         222  
6 4     4   1195 use FFI::Platypus 1.00;
  4         15256  
  4         1322  
7              
8             our $VERSION = '0.06';
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             You can turn off the use of L
182             completely by setting the environment varaible C
183             to a Perl true value. If set at install time it will also not add it
184             as a prereq.
185              
186             If the approach to mangling C++ names described above does not work for
187             you, or if it makes you feel slightly queasy, then you can also write C
188             wrapper functions around each C++ method that you want to call from
189             Perl. You can write these wrapper functions right in your C++ code
190             using the C trick:
191              
192             class Foo {
193             public:
194             int bar() { return 1; }
195             }
196            
197             extern "C" int
198             my_bar(Class *foo)
199             {
200             return foo->bar();
201             }
202              
203             Then instead of attaching C attach C.
204              
205             $ffi->attach( my_bar => [ 'Foo' ] => 'int' );
206              
207             =head2 constructors, destructors and methods
208              
209             Constructors and destructors are essentially just functions that do not
210             return a value that need to be called when the object is created and
211             when it is no longer needed (respectively). They take a pointer to the
212             object (C) as their first argument. Constructors can take
213             additional arguments, as you might expect they just come after the
214             object itself. Destructors take no arguments other than the object
215             itself (C).
216              
217             You need to alloate the memory needed for the object before you call the
218             constructor and free it after calling the destructor. The tricky bit is
219             figuring out how much memory to allocate. If you have access to the
220             header file that describes the class and a compiler you can compute the
221             size from within C++ and hand it off to Perl using a static method as I
222             did in the L above.
223              
224             Regular methods also take the object pointer as their first argument.
225             Additional arguments follow, and they may or may not return a value.
226              
227             =head2 inline functions
228              
229             C++ compilers typically do not emit symbols for inlined functions. If
230             you get a message like this:
231              
232             unable to find Foo::get_bar() at basic line 21
233              
234             even though you are sure that class has that method, this is probably
235             the problem that you are having. The Gnu C++ compiler, C has an
236             option to force it to emit the symbols, even for inlined functions:
237              
238             -fkeep-inline-functions # use this
239              
240             Clang has an option to do the opposite of this:
241              
242             -fvisibility-inlines-hidden # do not use this
243              
244             but unhelpfully not a way to keep inlined functions. This appears to be
245             a deliberate design decision made by the clang developers and it makes
246             sense for C++, since inline functions are typically defined in C++
247             header files (.h) so it is difficult to determine in which object file
248             the uninlined inlined functions should go.
249              
250             If you have the source of the C++ and you can recompile it you can also
251             optionally change it to not use inlined functions. In addition to
252             removing any C keywords from the source, you need to move the
253             implementations of any methods outside of the class body. That is, do
254             not do this:
255              
256             class Foo {
257             public:
258             int bar() { return 1; } # WRONG
259             }
260              
261             Do this:
262              
263             class Foo {
264             public:
265             int bar(); # RIGHT
266             }
267            
268             int
269             Foo::bar() # RIGHT
270             {
271             return 1;
272             }
273              
274             =head2 the standard C++ library
275              
276             If you are getting errors like this:
277              
278             unable to find Foo::Foo()
279              
280             that can't be explained by the issues described above, set the
281             environment variable FFI_PLATYPUS_DLERROR to a true value and try again.
282             If you see a warning like this:
283              
284             error loading Foo.so: Foo.so: undefined symbol: __gxx_personality_v0
285              
286             then you probably need to explicitly link with the standard C++ library.
287             The most portable way to deal with this is by using
288             L.
289              
290             =head1 METHODS
291              
292             Generally you will not use this class directly, instead interacting with
293             the L instance. However, the public methods used by
294             Platypus are documented here.
295              
296             =head2 native_type_map
297              
298             my $hashref = FFI::Platypus::Lang::CPP->native_type_map;
299              
300             This returns a hash reference containing the native aliases for the
301             C++ programming languages. That is the keys are native C++ types and the
302             values are libffi native types.
303              
304             =cut
305              
306             sub native_type_map
307             {
308 3     3 1 1023 require FFI::Platypus::Lang::C;
309 3         311 return FFI::Platypus::Lang::C->native_type_map;
310             }
311              
312             =head2 mangler
313              
314             my $mangler = FFI::Platypus::Lang::CPP->mangler($ffi->libs);
315             # prints _ZN9MyInteger7int_sumEii
316             print $mangler->("MyInteger::int_sum(int, int)");
317              
318             Returns a subroutine reference that will "mangle" C++ names.
319              
320             =cut
321              
322             if((!$ENV{FFI_PLATYPUS_LANG_CPP_NO_XS}) && eval { require FFI::Platypus::Lang::CPP::Demangle::XS })
323             {
324             *_demangle = \&FFI::Platypus::Lang::CPP::Demangle::XS::demangle;
325             }
326             else
327             {
328 6     6   22858 *_demangle = sub { `c++filt $_[0]` };
329             }
330              
331             sub mangler
332             {
333 1     1 1 1235 my($class, @libs) = @_;
334              
335 1         3 my %mangle;
336              
337 1         2 foreach my $libpath (@libs)
338             {
339             extract_symbols($libpath,
340             export => sub {
341 6     6   5096 my($symbol1, $symbol2) = @_;
342 6         55 my $cpp_symbol = _demangle($symbol2);
343 6 50       126 return unless defined $cpp_symbol;
344 6         28 chomp $cpp_symbol;
345 6 100       125 return if $cpp_symbol eq $symbol2;
346 1         27 $mangle{$cpp_symbol} = $symbol1;
347             },
348 1         6 );
349             }
350              
351             sub {
352 2 100   2   2197 defined $mangle{$_[0]} ? $mangle{$_[0]} : $_[0];
353 1         118 };
354             }
355              
356             1;
357              
358             =head1 EXAMPLES
359              
360             =head2 Using a C++ class without writing bundling any C/C++ code
361              
362             The example in the L shows how you I use a C++ class
363             without writing any wrapper code, though you will have to guess or
364             determine the instance size of the class.
365              
366             =head2 Using a C++ class with a wrapper
367              
368             (For the full source for this example, see examples/wrapper.{pl,cpp}
369             that came with this distribution)
370              
371             Sometimes it is easier to write wrapper functions around your new and
372             delete operations. Consider if you add these functions to the C++
373             source to the example in the L.
374              
375             // These could also be class methods
376             extern "C" Foo*
377             Foo_new()
378             {
379             return new Foo();
380             }
381            
382             extern "C" void
383             Foo_delete(Foo *foo)
384             {
385             delete foo;
386             }
387              
388             Now we can use this class without having to know I
389             what the size of the class is. We declare the constructor and
390             destructor in Perl space like this:
391              
392             $ffi->attach( [ 'Foo_new' => 'new' ] => [] => 'Foo' );
393             $ffi->attach( [ 'Foo_delete' => 'DESTROY' ] => ['Foo'] => 'void' );
394              
395             We've also removed the Perl C and C wrappers as they are
396             unnecessary now, and so the the C++ functions are attached directly to
397             their intended names.
398              
399             =head2 Exceptions
400              
401             (For the full source of this example, see examples/exception.{pl,cpp}
402             that came with this distribution)
403              
404             If your library throws an exception and you do not catch it in C++ it
405             is going to kill your program. As an example, suppose C in
406             the example above throws an exception:
407              
408             void
409             Foo::set_bar(int value)
410             {
411             if(value > 512)
412             throw new FooException("too hot");
413             if(value < 0)
414             throw new FooException("too cold");
415             bar = value;
416             }
417              
418             Now if you try to use C with a bad value like this from Perl:
419              
420             $foo->set_bar(-2);
421              
422             it will crash your Perl program.
423              
424             terminate called after throwing an instance of 'FooException'
425             Abort
426              
427             To handle this, you need to write a wrapper around the C
428             method.
429              
430             static FooException *last_exception = NULL;
431            
432             extern "C" FooException *
433             Foo_get_exception()
434             {
435             return last_exception;
436             }
437            
438             extern "C" void
439             Foo_reset_exception()
440             {
441             if(last_exception != NULL)
442             delete last_exception;
443             last_exception = NULL;
444             }
445            
446             extern "C" void
447             Foo_set_bar(Foo *foo, int value)
448             {
449             try
450             {
451             Foo_reset_exception();
452             foo->set_bar(value);
453             }
454             catch(FooException *e)
455             {
456             last_exception = e;
457             }
458             }
459              
460             Next we will write an interface to the FooException class in Perl:
461              
462             package FooException;
463            
464             use overload '""' => sub { "exception: " . $_[0]->message . "\n" };
465            
466             $ffi->custom_type( FooException => {
467             native_type => 'opaque',
468             perl_to_native => sub { ${ $_[0] } },
469             native_to_perl => sub {
470             defined $_[0]
471             ? (bless \$_[0], 'FooException')
472             : ();
473             },
474             });
475            
476             $ffi->attach(
477             [ 'Foo_get_exception' => 'get_exception' ] => [] => 'FooException'
478             );
479            
480             $ffi->attach(
481             [ 'FooException::message()' => 'message' ] => ['FooException'] => 'string'
482             );
483              
484             And finally we write a wrapper for the Perl C method.
485              
486             $ffi->attach( [ 'Foo_set_bar' => '_set_bar' ] => ['Foo','int']
487             => 'void' );
488             sub set_bar
489             {
490             my($self, $value) = @_;
491             $self->_set_bar($value);
492             my $error = FooException->get_exception;
493             die $error if $error;
494             }
495              
496             And now when we give C a bogus value we get a Perl exception
497             instead of an application crash:
498              
499             exception: too cold
500              
501             So we can easily wrap the call to C in a Perl eval if we want
502             to catch the exception and handle it.
503              
504             =head1 SUPPORT
505              
506             If something does not work as advertised, or the way that you think it
507             should, or if you have a feature request, please open an issue on this
508             project's GitHub issue tracker:
509              
510             L
511              
512             =head1 CONTRIBUTING
513              
514             If you have implemented a new feature or fixed a bug then you may make a
515             pull reequest on this project's GitHub repository:
516              
517             L
518              
519             Caution: if you do this too frequently I may nominate you as the new
520             maintainer. Extreme caution: if you like that sort of thing.
521              
522             This project's GitHub issue tracker listed above is not Write-Only. If
523             you want to contribute then feel free to browse through the existing
524             issues and see if there is something you feel you might be good at and
525             take a whack at the problem. I frequently open issues myself that I
526             hope will be accomplished by someone in the future but do not have time
527             to immediately implement myself.
528              
529             Another good area to help out in is documentation. I try to make sure
530             that there is good document coverage, that is there should be
531             documentation describing all the public features and warnings about
532             common pitfalls, but an outsider's or alternate view point on such
533             things would be welcome; if you see something confusing or lacks
534             sufficient detail I encourage documentation only pull requests to
535             improve things.
536              
537             =head1 SEE ALSO
538              
539             =over 4
540              
541             =item L
542              
543             The Core Platypus documentation.
544              
545             =item L + L
546              
547             Bundle C or C++ with your FFI / Perl extension.
548              
549             =item L
550              
551             Guess the appropriate C++ compiler / linker flags for your C compiler
552             platform combination.
553              
554             =back
555              
556             =head1 AUTHOR
557              
558             Graham Ollis Eplicease@cpan.orgE
559              
560             =head1 COPYRIGHT AND LICENSE
561              
562             This software is copyright (c) 2015 by Graham Ollis.
563              
564             This is free software; you can redistribute it and/or modify it under
565             the same terms as the Perl 5 programming language system itself.
566              
567             =cut
568