line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package FFI::Platypus::Lang::CPP; |
2
|
|
|
|
|
|
|
|
3
|
4
|
|
|
4
|
|
34254
|
use strict; |
|
4
|
|
|
|
|
10
|
|
|
4
|
|
|
|
|
189
|
|
4
|
4
|
|
|
4
|
|
23
|
use warnings; |
|
4
|
|
|
|
|
6
|
|
|
4
|
|
|
|
|
163
|
|
5
|
4
|
|
|
4
|
|
2038
|
use FFI::ExtractSymbols qw( extract_symbols ); |
|
4
|
|
|
|
|
18199
|
|
|
4
|
|
|
|
|
277
|
|
6
|
4
|
|
|
4
|
|
1943
|
use FFI::Platypus; |
|
4
|
|
|
|
|
13571
|
|
|
4
|
|
|
|
|
1386
|
|
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
our $VERSION = '0.04'; |
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
|
|
|
|
|
|
|
C++: |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
// on Linux compile with: g++ --shared -o basic.so basic.cpp |
20
|
|
|
|
|
|
|
// elsewhere, consult your C++ compiler documentation |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
class Foo { |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
public: |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
// note you should avoid inlining functions |
27
|
|
|
|
|
|
|
// for classes you intend to use with FFI |
28
|
|
|
|
|
|
|
// as the compiler may not emit code/symbols |
29
|
|
|
|
|
|
|
// for those functions. |
30
|
|
|
|
|
|
|
Foo(); |
31
|
|
|
|
|
|
|
~Foo(); |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
int get_bar(); |
34
|
|
|
|
|
|
|
void set_bar(int); |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
int _size(); |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
private: |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
int bar; |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
}; |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
Foo::Foo() |
45
|
|
|
|
|
|
|
{ |
46
|
|
|
|
|
|
|
bar = 0; |
47
|
|
|
|
|
|
|
} |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
Foo::~Foo() |
50
|
|
|
|
|
|
|
{ |
51
|
|
|
|
|
|
|
} |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
int |
54
|
|
|
|
|
|
|
Foo::get_bar() |
55
|
|
|
|
|
|
|
{ |
56
|
|
|
|
|
|
|
return bar; |
57
|
|
|
|
|
|
|
} |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
void |
60
|
|
|
|
|
|
|
Foo::set_bar(int value) |
61
|
|
|
|
|
|
|
{ |
62
|
|
|
|
|
|
|
bar = value; |
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
int |
66
|
|
|
|
|
|
|
Foo::_size() |
67
|
|
|
|
|
|
|
{ |
68
|
|
|
|
|
|
|
return sizeof(Foo); |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
Perl: |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
package Foo; |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
use FFI::Platypus; |
76
|
|
|
|
|
|
|
use FFI::Platypus::Memory qw( malloc free ); |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
my $ffi = FFI::Platypus->new; |
79
|
|
|
|
|
|
|
$ffi->lang('CPP'); |
80
|
|
|
|
|
|
|
$ffi->lib('./basic.so'); |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
$ffi->custom_type( Foo => { |
83
|
|
|
|
|
|
|
native_type => 'opaque', |
84
|
|
|
|
|
|
|
perl_to_native => sub { ${ $_[0] } }, |
85
|
|
|
|
|
|
|
native_to_perl => sub { bless \$_[0], 'Foo' }, |
86
|
|
|
|
|
|
|
}); |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
$ffi->attach( [ 'Foo::Foo()' => '_new' ] => ['Foo'] => 'void' ); |
89
|
|
|
|
|
|
|
$ffi->attach( [ 'Foo::~Foo()' => '_DESTROY' ] => ['Foo'] => 'void' ); |
90
|
|
|
|
|
|
|
$ffi->attach( [ 'Foo::get_bar()' => 'get_bar' ] => ['Foo'] => 'int' ); |
91
|
|
|
|
|
|
|
$ffi->attach( [ 'Foo::set_bar(int)' |
92
|
|
|
|
|
|
|
=> 'set_bar' ] => ['Foo','int'] |
93
|
|
|
|
|
|
|
=> 'void' ); |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
my $size = $ffi->function('Foo::_size()' => [] => 'int')->call; |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
sub new |
98
|
|
|
|
|
|
|
{ |
99
|
|
|
|
|
|
|
my($class) = @_; |
100
|
|
|
|
|
|
|
my $ptr = malloc $size; |
101
|
|
|
|
|
|
|
my $self = bless \$ptr, $class; |
102
|
|
|
|
|
|
|
_new($self); |
103
|
|
|
|
|
|
|
$self; |
104
|
|
|
|
|
|
|
} |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
sub DESTROY |
107
|
|
|
|
|
|
|
{ |
108
|
|
|
|
|
|
|
my($self) = @_; |
109
|
|
|
|
|
|
|
_DESTROY($self); |
110
|
|
|
|
|
|
|
free($$self); |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
package main; |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
my $foo = Foo->new; |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
print $foo->get_bar, "\n"; # 0 |
118
|
|
|
|
|
|
|
$foo->set_bar(22); |
119
|
|
|
|
|
|
|
print $foo->get_bar. "\n"; # 22 |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
=head1 DESCRIPTION |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
This module provides some hooks for Platypus so that C++ names can be |
124
|
|
|
|
|
|
|
mangled for you. It uses the same primitive types as C. This document |
125
|
|
|
|
|
|
|
also documents issues and caveats that I have discovered in my attempts |
126
|
|
|
|
|
|
|
to work with C++ and FFI. |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
This module is somewhat experimental. It is also available for adoption |
129
|
|
|
|
|
|
|
for anyone either sufficiently knowledgable about C++ or eager enough to |
130
|
|
|
|
|
|
|
learn enough about C++. If you are interested, please send me a pull |
131
|
|
|
|
|
|
|
request or two on the project's GitHub. |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
There are numerous difficulties and caveats involved in using C++ |
134
|
|
|
|
|
|
|
libraries from Perl via FFI. This document is intended to enlighten on |
135
|
|
|
|
|
|
|
that subject. |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
Note that in addition to using pre-compiled C++ libraries you can bundle |
138
|
|
|
|
|
|
|
C++ code with your Perl distribution using L. For a |
139
|
|
|
|
|
|
|
complete example, which attempts to address the caveats listed below you |
140
|
|
|
|
|
|
|
can take a look at this sample distro on GitHub: |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
L |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
=head1 CAVEATS |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
In general I have done my research of FFI and C++ using the Gnu C++ |
147
|
|
|
|
|
|
|
compiler. I have done some testing with C as well. |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
=head2 name mangling |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
C++ names are "mangled" to handle features such as function overloading |
152
|
|
|
|
|
|
|
and the fact that some characters in the C++ names are illegal machine |
153
|
|
|
|
|
|
|
code symbol names. What this means is that the C++ member function |
154
|
|
|
|
|
|
|
C looks like C<_ZN3Foo7get_barEv> to L. |
155
|
|
|
|
|
|
|
What makes this even trickier is that different C++ compilers provide |
156
|
|
|
|
|
|
|
different mangling formats. When you use the L |
157
|
|
|
|
|
|
|
method to tell Platypus that you are intending to use it with C++, like |
158
|
|
|
|
|
|
|
this: |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
$ffi->lang('CPP'); |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
it will mangle the names that you give it. That saves you having to |
163
|
|
|
|
|
|
|
figure out the "real" name for C. |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
The current implementation uses the C command or |
166
|
|
|
|
|
|
|
L if it is installed. If |
167
|
|
|
|
|
|
|
C cannot be found at install time, then |
168
|
|
|
|
|
|
|
L will be made a prerequsite, so |
169
|
|
|
|
|
|
|
you can have some confidence that this feature will work even if your |
170
|
|
|
|
|
|
|
platform does not provide C. The XS module is not a |
171
|
|
|
|
|
|
|
prerequsite when C IS found because using C does not |
172
|
|
|
|
|
|
|
require invoking the compiler and may be more reliable. |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
If the approach to mangling C++ names described above does not work for |
175
|
|
|
|
|
|
|
you, or if it makes you feel slightly queasy, then you can also write C |
176
|
|
|
|
|
|
|
wrapper functions around each C++ method that you want to call from |
177
|
|
|
|
|
|
|
Perl. You can write these wrapper functions right in your C++ code |
178
|
|
|
|
|
|
|
using the C trick: |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
class Foo { |
181
|
|
|
|
|
|
|
public: |
182
|
|
|
|
|
|
|
int bar() { return 1; } |
183
|
|
|
|
|
|
|
} |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
extern "C" int |
186
|
|
|
|
|
|
|
my_bar(Class *foo) |
187
|
|
|
|
|
|
|
{ |
188
|
|
|
|
|
|
|
return foo->bar(); |
189
|
|
|
|
|
|
|
} |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
Then instead of attaching C attach C. |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
$ffi->attach( my_bar => [ 'Foo' ] => 'int' ); |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
=head2 constructors, destructors and methods |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
Constructors and destructors are essentially just functions that do not |
198
|
|
|
|
|
|
|
return a value that need to be called when the object is created and |
199
|
|
|
|
|
|
|
when it is no longer needed (respectively). They take a pointer to the |
200
|
|
|
|
|
|
|
object (C) as their first argument. Constructors can take |
201
|
|
|
|
|
|
|
additional arguments, as you might expect they just come after the |
202
|
|
|
|
|
|
|
object itself. Destructors take no arguments other than the object |
203
|
|
|
|
|
|
|
itself (C). |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
You need to alloate the memory needed for the object before you call the |
206
|
|
|
|
|
|
|
constructor and free it after calling the destructor. The tricky bit is |
207
|
|
|
|
|
|
|
figuring out how much memory to allocate. If you have access to the |
208
|
|
|
|
|
|
|
header file that describes the class and a compiler you can compute the |
209
|
|
|
|
|
|
|
size from within C++ and hand it off to Perl using a static method as I |
210
|
|
|
|
|
|
|
did in the L above. |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
Regular methods also take the object pointer as their first argument. |
213
|
|
|
|
|
|
|
Additional arguments follow, and they may or may not return a value. |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
=head2 inline functions |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
C++ compilers typically do not emit symbols for inlined functions. If |
218
|
|
|
|
|
|
|
you get a message like this: |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
unable to find Foo::get_bar() at basic line 21 |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
even though you are sure that class has that method, this is probably |
223
|
|
|
|
|
|
|
the problem that you are having. The Gnu C++ compiler, C has an |
224
|
|
|
|
|
|
|
option to force it to emit the symbols, even for inlined functions: |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
-fkeep-inline-functions # use this |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
Clang has an option to do the opposite of this: |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
-fvisibility-inlines-hidden # do not use this |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
but unhelpfully not a way to keep inlined functions. This appears to be |
233
|
|
|
|
|
|
|
a deliberate design decision made by the clang developers and it makes |
234
|
|
|
|
|
|
|
sense for C++, since inline functions are typically defined in C++ |
235
|
|
|
|
|
|
|
header files (.h) so it is difficult to determine in which object file |
236
|
|
|
|
|
|
|
the uninlined inlined functions should go. |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
If you have the source of the C++ and you can recompile it you can also |
239
|
|
|
|
|
|
|
optionally change it to not use inlined functions. In addition to |
240
|
|
|
|
|
|
|
removing any C keywords from the source, you need to move the |
241
|
|
|
|
|
|
|
implementations of any methods outside of the class body. That is, do |
242
|
|
|
|
|
|
|
not do this: |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
class Foo { |
245
|
|
|
|
|
|
|
public: |
246
|
|
|
|
|
|
|
int bar() { return 1; } # WRONG |
247
|
|
|
|
|
|
|
} |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
Do this: |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
class Foo { |
252
|
|
|
|
|
|
|
public: |
253
|
|
|
|
|
|
|
int bar(); # RIGHT |
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
int |
257
|
|
|
|
|
|
|
Foo::bar() # RIGHT |
258
|
|
|
|
|
|
|
{ |
259
|
|
|
|
|
|
|
return 1; |
260
|
|
|
|
|
|
|
} |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
=head2 the standard C++ library |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
If you are getting errors like this: |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
unable to find Foo::Foo() |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
that can't be explained by the issues described above, set the |
269
|
|
|
|
|
|
|
environment variable FFI_PLATYPUS_DLERROR to a true value and try again. |
270
|
|
|
|
|
|
|
If you see a warning like this: |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
error loading Foo.so: Foo.so: undefined symbol: __gxx_personality_v0 |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
then you probably need to explicitly link with the standard C++ library. |
275
|
|
|
|
|
|
|
The most portable way to deal with this is by using |
276
|
|
|
|
|
|
|
L. |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
=head1 METHODS |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
Generally you will not use this class directly, instead interacting with |
281
|
|
|
|
|
|
|
the L instance. However, the public methods used by |
282
|
|
|
|
|
|
|
Platypus are documented here. |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
=head2 native_type_map |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
my $hashref = FFI::Platypus::Lang::CPP->native_type_map; |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
This returns a hash reference containing the native aliases for the |
289
|
|
|
|
|
|
|
C++ programming languages. That is the keys are native C++ types and the |
290
|
|
|
|
|
|
|
values are libffi native types. |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
=cut |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
sub native_type_map |
295
|
|
|
|
|
|
|
{ |
296
|
3
|
|
|
3
|
1
|
1664
|
require FFI::Platypus::Lang::C; |
297
|
3
|
|
|
|
|
386
|
return FFI::Platypus::Lang::C->native_type_map; |
298
|
|
|
|
|
|
|
} |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
=head2 mangler |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
my $mangler = FFI::Platypus::Lang::CPP->mangler($ffi->libs); |
303
|
|
|
|
|
|
|
# prints _ZN9MyInteger7int_sumEii |
304
|
|
|
|
|
|
|
print $mangler->("MyInteger::int_sum(int, int)"); |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
Returns a subroutine reference that will "mangle" C++ names. |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
=cut |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
if(eval { require FFI::Platypus::Lang::CPP::Demangle::XS }) |
311
|
|
|
|
|
|
|
{ |
312
|
|
|
|
|
|
|
*_demangle = \&FFI::Platypus::Lang::CPP::Demangle::XS::demangle; |
313
|
|
|
|
|
|
|
} |
314
|
|
|
|
|
|
|
else |
315
|
|
|
|
|
|
|
{ |
316
|
6
|
|
|
6
|
|
14892
|
*_demangle = sub { `c++filt $_[0]` }; |
317
|
|
|
|
|
|
|
} |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
sub mangler |
320
|
|
|
|
|
|
|
{ |
321
|
1
|
|
|
1
|
1
|
1305
|
my($class, @libs) = @_; |
322
|
|
|
|
|
|
|
|
323
|
1
|
|
|
|
|
1
|
my %mangle; |
324
|
|
|
|
|
|
|
|
325
|
1
|
|
|
|
|
2
|
foreach my $libpath (@libs) |
326
|
|
|
|
|
|
|
{ |
327
|
|
|
|
|
|
|
extract_symbols($libpath, |
328
|
|
|
|
|
|
|
export => sub { |
329
|
6
|
|
|
6
|
|
3954
|
my($symbol1, $symbol2) = @_; |
330
|
6
|
|
|
|
|
23
|
my $cpp_symbol = _demangle($symbol2); |
331
|
6
|
50
|
|
|
|
47
|
return unless defined $cpp_symbol; |
332
|
6
|
|
|
|
|
14
|
chomp $cpp_symbol; |
333
|
6
|
100
|
|
|
|
54
|
return if $cpp_symbol eq $symbol2; |
334
|
1
|
|
|
|
|
9
|
$mangle{$cpp_symbol} = $symbol1; |
335
|
|
|
|
|
|
|
}, |
336
|
1
|
|
|
|
|
6
|
); |
337
|
|
|
|
|
|
|
} |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
sub { |
340
|
2
|
100
|
|
2
|
|
1270
|
defined $mangle{$_[0]} ? $mangle{$_[0]} : $_[0]; |
341
|
1
|
|
|
|
|
77
|
}; |
342
|
|
|
|
|
|
|
} |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
1; |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
=head1 EXAMPLES |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
See the above L or the C directory that came with |
349
|
|
|
|
|
|
|
this distribution. |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
=head1 SUPPORT |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
If something does not work as advertised, or the way that you think it |
354
|
|
|
|
|
|
|
should, or if you have a feature request, please open an issue on this |
355
|
|
|
|
|
|
|
project's GitHub issue tracker: |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
L |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
=head1 CONTRIBUTING |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
If you have implemented a new feature or fixed a bug then you may make a |
362
|
|
|
|
|
|
|
pull reequest on this project's GitHub repository: |
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
L |
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
Caution: if you do this too frequently I may nominate you as the new |
367
|
|
|
|
|
|
|
maintainer. Extreme caution: if you like that sort of thing. |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
This project's GitHub issue tracker listed above is not Write-Only. If |
370
|
|
|
|
|
|
|
you want to contribute then feel free to browse through the existing |
371
|
|
|
|
|
|
|
issues and see if there is something you feel you might be good at and |
372
|
|
|
|
|
|
|
take a whack at the problem. I frequently open issues myself that I |
373
|
|
|
|
|
|
|
hope will be accomplished by someone in the future but do not have time |
374
|
|
|
|
|
|
|
to immediately implement myself. |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
Another good area to help out in is documentation. I try to make sure |
377
|
|
|
|
|
|
|
that there is good document coverage, that is there should be |
378
|
|
|
|
|
|
|
documentation describing all the public features and warnings about |
379
|
|
|
|
|
|
|
common pitfalls, but an outsider's or alternate view point on such |
380
|
|
|
|
|
|
|
things would be welcome; if you see something confusing or lacks |
381
|
|
|
|
|
|
|
sufficient detail I encourage documentation only pull requests to |
382
|
|
|
|
|
|
|
improve things. |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
=head1 SEE ALSO |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
=over 4 |
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
=item L |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
The Core Platypus documentation. |
391
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
=item L |
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
Bundle C or C++ with your FFI / Perl extension. |
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
=item L |
397
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
Guess the appropriate C++ compiler / linker flags for your C compiler |
399
|
|
|
|
|
|
|
platform combination. |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
=back |
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
=head1 AUTHOR |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
Graham Ollis Eplicease@cpan.orgE |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
This software is copyright (c) 2015 by Graham Ollis. |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under |
412
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
=cut |
415
|
|
|
|
|
|
|
|