.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.40) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" ======================================================================== .\" .IX Title "FFI::Platypus::Type 3pm" .TH FFI::Platypus::Type 3pm "2020-11-08" "perl v5.32.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" FFI::Platypus::Type \- Defining types for FFI::Platypus .SH "VERSION" .IX Header "VERSION" version 1.34 .SH "SYNOPSIS" .IX Header "SYNOPSIS" \&\s-1OO\s0 Interface: .PP .Vb 3 \& use FFI::Platypus; \& my $ffi = FFI::Platypus\->new( api => 1 ); \& $ffi\->type(\*(Aqint\*(Aq => \*(Aqmy_int\*(Aq); .Ve .SH "DESCRIPTION" .IX Header "DESCRIPTION" \&\fBNote\fR: This document assumes that you are using \f(CW\*(C`api => 1\*(C'\fR, which you should be using for all new code. .PP This document describes how to define types using FFI::Platypus. Types may be \*(L"defined\*(R" ahead of time, or simply used when defining or attaching functions. .PP .Vb 5 \& # Example of defining types \& use FFI::Platypus; \& my $ffi = FFI::Platypus\->new( api => 1 ); \& $ffi\->type(\*(Aqint\*(Aq); \& $ffi\->type(\*(Aqstring\*(Aq); \& \& # Example of simply using types in function declaration or attachment \& my $f = $ffi\->function(puts => [\*(Aqstring\*(Aq] => \*(Aqint\*(Aq); \& $ffi\->attach(puts => [\*(Aqstring\*(Aq] => \*(Aqint\*(Aq); .Ve .PP Unless you are using aliases the FFI::Platypus#type method is not necessary, but they will throw an exception if the type is incorrectly specified or not supported, which may be helpful for determining if the types are available or not. .PP Note: This document sometimes uses the term \*(L"C Function\*(R" as short hand for function implemented in a compiled language. Unless the term is referring literally to a C function example code, you can assume that it should also work with another compiled language. .SS "meta information about types" .IX Subsection "meta information about types" You can get the size of a type using the FFI::Platypus#sizeof method. .PP .Vb 2 \& my $intsize = $ffi\->sizeof(\*(Aqint\*(Aq); # usually 4 \& my $intarraysize = $ffi\->sizeof(\*(Aqint[64]\*(Aq); # usually 256 .Ve .SS "converting types" .IX Subsection "converting types" Sometimes it is necessary to convert types. In particular various pointer types often need to be converted for consumption in Perl. For this purpose the FFI::Platypus#cast method is provided. It needs to be used with care though, because not all type combinations are supported. Here are some useful ones: .PP .Vb 1 \& my $address = $ffi\->cast(\*(Aqstring\*(Aq => \*(Aqopaque\*(Aq, $string); .Ve .PP This converts a Perl string to a pointer address that can be used by functions that take an \f(CW\*(C`opaque\*(C'\fR type. Be carefully though that the Perl string is not resized or free'd while in use from C code. .PP .Vb 1 \& my $string = $ffi\->cast(\*(Aqopaque\*(Aq => \*(Aqstring\*(Aq, $pointer); .Ve .PP This does the opposite, converting a null terminated string (the type of strings used by C) into a Perl string. In this case the string is copied, so the other language is free to deallocate or otherwise manipulate the string after the conversion without adversely affecting the Perl. .SS "aliases" .IX Subsection "aliases" Some times using alternate names is useful for documenting the purpose of an argument or return type. For this \*(L"aliases\*(R" can be helpful. The second argument to the FFI::Platypus#type method can be used to define a type alias that can later be used by function declaration and attachment. .PP .Vb 6 \& use FFI::Platypus; \& my $ffi = FFI::Platypus\->new( api => 1 ); \& $ffi\->type(\*(Aqint\*(Aq => \*(Aqmyint\*(Aq); \& $ffi\->type(\*(Aqstring\*(Aq => \*(Aqmystring\*(Aq); \& my $f = $ffi\->function( puts => [\*(Aqmystring\*(Aq] => \*(Aqmyint\*(Aq ); \& $ffi\->attach( puts => [\*(Aqmystring\*(Aq] => \*(Aqmyint\*(Aq ); .Ve .PP Aliases are contained without the FFI::Platypus object, so feel free to define your own crazy types without stepping on the toes of other \&\s-1CPAN\s0 developers using Platypus. .PP One useful application of an alias is when you know types are different on two different platforms: .PP .Vb 7 \& if($^O eq \*(AqMSWin32\*(Aq) \& { \& $type\->type(\*(Aqsint16\*(Aq => \*(Aqfoo_t\*(Aq); \& } elsif($^O eq \*(Aqlinux\*(Aq) \& { \& $type\->type(\*(Aqsint32\*(Aq => \*(Aqfoo_t\*(Aq); \& } \& \& # function foo takes 16 bit signed integer on Windows \& # and a 32 bit signed integer on Linux. \& $ffi\->attach( foo => [ \*(Aqfoo_t\*(Aq ] => \*(Aqvoid\*(Aq ); .Ve .SH "TYPE CATEGORIES" .IX Header "TYPE CATEGORIES" .SS "Native types" .IX Subsection "Native types" So called native types are the types that the \s-1CPU\s0 understands that can be passed on the argument stack or returned by a function. It does not include more complicated types like arrays or structs, which can be passed via pointers (see the opaque type below). Generally native types include void, integers, floats and pointers. .PP \fIthe void type\fR .IX Subsection "the void type" .PP This can be used as a return value to indicate a function does not return a value (or if you want the return value to be ignored). .PP .Vb 1 \& $ffi\->type( foo => [] => \*(Aqvoid\*(Aq ); .Ve .PP Newer versions of Platypus also allow you to omit the return type and \&\f(CW\*(C`void\*(C'\fR is assumed. .PP .Vb 1 \& $ffi\->type( foo => [] ); .Ve .PP It doesn't really make sense to use \f(CW\*(C`void\*(C'\fR in any other context. However, because of historical reasons involving older versions of Perl. .PP It doesn't really make sense for \f(CW\*(C`void\*(C'\fR to be passed in as an argument. However, because C functions that take no arguments frequently are specified as taking \f(CW\*(C`void\*(C'\fR as this was required by older C compilers, as a special case you can specify a function's arguments as taking a single \f(CW\*(C`void\*(C'\fR to mean it takes no arguments. .PP .Vb 4 \& # C: void foo(void); \& $ffi\->type( foo => [\*(Aqvoid\*(Aq] ); \& # same (but probably better) \& $ffi\->type( foo => [] ); .Ve .PP \fIinteger types\fR .IX Subsection "integer types" .PP The following native integer types are always available (parentheticals indicates the usual corresponding C type): .IP "sint8" 4 .IX Item "sint8" Signed 8 bit byte (\f(CW\*(C`signed char\*(C'\fR, \f(CW\*(C`int8_t\*(C'\fR). .IP "uint8" 4 .IX Item "uint8" Unsigned 8 bit byte (\f(CW\*(C`unsigned char\*(C'\fR, \f(CW\*(C`uint8_t\*(C'\fR). .IP "sint16" 4 .IX Item "sint16" Signed 16 bit integer (\f(CW\*(C`short\*(C'\fR, \f(CW\*(C`int16_t\*(C'\fR) .IP "uint16" 4 .IX Item "uint16" Unsigned 16 bit integer (\f(CW\*(C`unsigned short\*(C'\fR, \f(CW\*(C`uint16_t\*(C'\fR) .IP "sint32" 4 .IX Item "sint32" Signed 32 bit integer (\f(CW\*(C`int\*(C'\fR, \f(CW\*(C`int32_t\*(C'\fR) .IP "uint32" 4 .IX Item "uint32" Unsigned 32 bit integer (\f(CW\*(C`unsigned int\*(C'\fR, \f(CW\*(C`uint32_t\*(C'\fR) .IP "sint64" 4 .IX Item "sint64" Signed 64 bit integer (\f(CW\*(C`long long\*(C'\fR, \f(CW\*(C`int64_t\*(C'\fR) .IP "uint64" 4 .IX Item "uint64" Unsigned 64 bit integer (\f(CW\*(C`unsigned long long\*(C'\fR, \&\f(CW\*(C`uint64_t\*(C'\fR) .PP You may also use \f(CW\*(C`uchar\*(C'\fR, \f(CW\*(C`ushort\*(C'\fR, \f(CW\*(C`uint\*(C'\fR and \f(CW\*(C`ulong\*(C'\fR as short names for \f(CW\*(C`unsigned char\*(C'\fR, \f(CW\*(C`unsigned short\*(C'\fR, \f(CW\*(C`unsigned int\*(C'\fR and \&\f(CW\*(C`unsigned long\*(C'\fR. .PP These integer types are also available, but there actual size and sign may depend on the platform. .IP "char" 4 .IX Item "char" Somewhat confusingly, \f(CW\*(C`char\*(C'\fR is an integer type! This is really an alias for either \f(CW\*(C`sint8_t\*(C'\fR or \f(CW\*(C`uint8_t\*(C'\fR depending on your platform. If you want to pass a character (not integer) in to a C function that takes a character you want to use the perl ord function. Here is an example that uses the standard libc \f(CW\*(C`isalpha\*(C'\fR, \f(CW\*(C`isdigit\*(C'\fR type functions: .Sp .Vb 1 \& use FFI::Platypus; \& \& my $ffi = FFI::Platypus\->new; \& $ffi\->lib(undef); \& $ffi\->type(\*(Aqint\*(Aq => \*(Aqcharacter\*(Aq); \& \& my @list = qw( \& alnum alpha ascii blank cntrl digit lower print punct \& space upper xdigit \& ); \& \& $ffi\->attach("is$_" => [\*(Aqcharacter\*(Aq] => \*(Aqint\*(Aq) for @list; \& \& my $char = shift(@ARGV) || \*(Aqa\*(Aq; \& \& no strict \*(Aqrefs\*(Aq; \& printf "\*(Aq%s\*(Aq is %s %s\en", $char, $_, &{\*(Aqis\*(Aq.$_}(ord $char) for @list; .Ve .IP "size_t" 4 .IX Item "size_t" This is usually an \f(CW\*(C`unsigned long\*(C'\fR, but it is up to the compiler to decide. The \f(CW\*(C`malloc\*(C'\fR function is defined in terms of \f(CW\*(C`size_t\*(C'\fR: .Sp .Vb 1 \& $ffi\->attach( malloc => [\*(Aqsize_t\*(Aq] => \*(Aqopaque\*(Aq; .Ve .Sp (Note that you can get \f(CW\*(C`malloc\*(C'\fR from FFI::Platypus::Memory). .IP "long, unsigned long" 4 .IX Item "long, unsigned long" On 64 bit systems, this is usually a 64 bit integer. On 32 bit systems this is frequently a 32 bit integer (and \f(CW\*(C`long long\*(C'\fR or \&\f(CW\*(C`unsigned long long\*(C'\fR are for 64 bit). .PP There are a number of other types that may or may not be available if they are detected when FFI::Platypus is installed. This includes things like \f(CW\*(C`wchar_t\*(C'\fR, \f(CW\*(C`off_t\*(C'\fR, \f(CW\*(C`wint_t\*(C'\fR. You can use this script to list all the integer types that FFI::Platypus knows about, plus how they are implemented. .PP .Vb 1 \& use FFI::Platypus; \& \& my $ffi = FFI::Platypus\->new; \& \& foreach my $type_name (sort FFI::Platypus\->types) \& { \& my $meta = $ffi\->type_meta($type_name); \& next unless $meta\->{element_type} eq \*(Aqint\*(Aq; \& printf "%20s %s\en", $type_name, $meta\->{ffi_type}; \& } .Ve .PP If you need a common system type that is not provided, please open a ticket in the Platypus project's GitHub issue tracker. Be sure to include the usual header file the type can be found in. .PP \fIEnum types\fR .IX Subsection "Enum types" .PP C provides enumerated types, which are typically implemented as integer types. .PP .Vb 4 \& enum { \& BAR = 1, \& BAZ = 2 \& } foo_t; \& \& void f(enum foo_t foo); .Ve .PP Platypus provides \f(CW\*(C`enum\*(C'\fR and \f(CW\*(C`senum\*(C'\fR types for the integer types used to represent enum and signed enum types respectively. .PP .Vb 5 \& use constant BAR => 1; \& use constant BAZ => 2; \& $ffi\->attach( f => [ \*(Aqenum\*(Aq ] => \*(Aqvoid\*(Aq ); \& f(BAR); \& f(BAZ); .Ve .PP When do you use \f(CW\*(C`senum\*(C'\fR? Anytime the enum has negative values: .PP .Vb 4 \& enum { \& BAR = \-1; \& BAZ = 2; \& } foo_t; \& \& void f(enum foo_t foo); .Ve .PP Perl: .PP .Vb 5 \& use constant BAR => \-1; \& use constant BAZ => 2; \& $ffi\->attach( f => [ \*(Aqsenum\*(Aq ] => \*(Aqvoid\*(Aq ); \& f(BAR); \& f(BAZ); .Ve .PP Dealing with enumerated values with \s-1FFI\s0 can be tricky because these are usually defined in C header files and cannot be found in dynamic libraries. For trivial usage you can do as illustrated above, simply define your own Perl constants. For more complicated usage, or where the values might vary from platform to platform you may want to consider the new Platypus bundle interface to define Perl constants (essentially the same as an enumerated value) from C space. This is more reliable, but does require a compiler at install time. See FFI::Platypus::Constant for details. .PP The main \s-1FAQ\s0 (\*(L"\s-1FAQ\*(R"\s0 in FFI::Platypus) also has a discussion on dealing with constants and enumerated types. .PP There is also a type plugin (FFI::Platypus::Type::Enum) that can be helpful in writing interfaces that use enums. .PP \fIBoolean types\fR .IX Subsection "Boolean types" .PP At install time Platypus attempts to detect the correct type for \f(CW\*(C`bool\*(C'\fR for your platform, and you can use that. \f(CW\*(C`bool\*(C'\fR is really an integer type, but the type used varies from platform to platform. .PP C header: .PP .Vb 2 \& #include \& bool foo(); .Ve .PP Platypus .PP .Vb 1 \& $ffi\->attach( foo => [] => \*(Aqbool\*(Aq ); .Ve .PP If you get an exception when trying to use this type it means you either have a very old version of Platypus, or for some reason it was unable to detect the correct type at install time. Please open a ticket if that is the case. .PP \fIfloating point types\fR .IX Subsection "floating point types" .PP The following native floating point types are always available (parentheticals indicates the usual corresponding C type): .IP "float" 4 .IX Item "float" Single precision floating point (\fIfloat\fR) .IP "double" 4 .IX Item "double" Double precision floating point (\fIdouble\fR) .IP "longdouble" 4 .IX Item "longdouble" Floating point that may be larger than \f(CW\*(C`double\*(C'\fR (\fIlongdouble\fR). This type is only available if supported by the C compiler used to build FFI::Platypus. There may be a performance penalty for using this type, even if your Perl uses long doubles internally for its number value (\s-1NV\s0) type, because of the way FFI::Platypus interacts with \&\f(CW\*(C`libffi\*(C'\fR. .Sp As an argument type either regular number values (\s-1NV\s0) or instances of Math::LongDouble are accepted. When used as a return type, Math::LongDouble will be used, if you have that module installed. Otherwise the return type will be downgraded to whatever your Perl's number value (\s-1NV\s0) is. .IP "complex_float" 4 .IX Item "complex_float" Complex single precision floating point (\fIfloat complex\fR) .IP "complex_double" 4 .IX Item "complex_double" Complex double precision floating point (\fIdouble complex\fR) .Sp \&\f(CW\*(C`complex_float\*(C'\fR and \f(CW\*(C`complex_double\*(C'\fR are only available if supported by your C compiler and by libffi. Complex numbers are only supported in very recent versions of libffi, and as of this writing the latest production version doesn't work on x86_64. It does seem to work with the latest production version of libffi on 32 bit Intel (x86), and with the latest libffi version in git on x86_64. .PP \fIopaque pointers\fR .IX Subsection "opaque pointers" .PP Opaque pointers are simply a pointer to a region of memory that you do not manage, and do not know or care about its structure. It is like a \f(CW\*(C`void *\*(C'\fR in C. These types are represented in Perl space as integers and get converted to and from pointers by FFI::Platypus. You may use \&\f(CW\*(C`pointer\*(C'\fR as an alias for \f(CW\*(C`opaque\*(C'\fR, although this is discouraged. (The Platypus documentation uses the convention of using \*(L"pointer\*(R" to refer to pointers to known types (see below) and \*(L"opaque\*(R" as short hand for opaque pointer). .PP As an example, libarchive defines \f(CW\*(C`struct archive\*(C'\fR type in its header files, but does not define its content. Internally it is defined as a \&\f(CW\*(C`struct\*(C'\fR type, but the caller does not see this. It is therefore opaque to its caller. There are \f(CW\*(C`archive_read_new\*(C'\fR and \&\f(CW\*(C`archive_write_new\*(C'\fR functions to create a new instance of this opaque object and \f(CW\*(C`archive_read_free\*(C'\fR and \f(CW\*(C`archive_write_free\*(C'\fR to destroy this objects when you are done. .PP C header: .PP .Vb 5 \& struct archive; \& struct archive *archive_read_new(void); \& struct archive *archive_write_new(void); \& int archive_free(struct archive *); \& int archive_write_free(struct archive *); .Ve .PP Perl code: .PP .Vb 5 \& $lib\->find_lib( lib => \*(Aqarchive\*(Aq ); \& $ffi\->attach(archive_read_new => [] => \*(Aqopaque\*(Aq); \& $ffi\->attach(archive_write_new => [] => \*(Aqopaque\*(Aq); \& $ffi\->attach(archive_read_free => [\*(Aqopaque\*(Aq] => \*(Aqint\*(Aq); \& $ffi\->attach(archive_write_free => [\*(Aqopaque\*(Aq] => \*(Aqint\*(Aq); .Ve .PP It is often useful to alias an \f(CW\*(C`opaque\*(C'\fR type like this so that you know what the object represents: .PP .Vb 5 \& $lib\->find_lib( lib => \*(Aqarchive\*(Aq ); \& $ffi\->type(\*(Aqopaque\*(Aq => \*(Aqarchive\*(Aq); \& $ffi\->attach(archive_read_new => [] => \*(Aqarchive\*(Aq); \& $ffi\->attach(archive_read_free => [\*(Aqarchive\*(Aq] => \*(Aqint\*(Aq); \& ... .Ve .PP As a special case, when you pass \f(CW\*(C`undef\*(C'\fR into a function that takes an opaque type it will be translated into \f(CW\*(C`NULL\*(C'\fR for C. When a C function returns a \s-1NULL\s0 pointer, it will be translated back to \f(CW\*(C`undef\*(C'\fR. .PP There are a number of useful utility functions for dealing with opaque types in the FFI::Platypus::Memory module. .SS "Objects" .IX Subsection "Objects" Object types are thin wrappers around two native types: integer and \&\f(CW\*(C`opaque\*(C'\fR types. They are just blessed references around either of those two types so that methods can be defined on them, but when they get passed to a Platypus xsub they are converted into the native integer or \f(CW\*(C`opaque\*(C'\fR types. This type is most useful when a \s-1API\s0 provides an \s-1OO\s0 style interface with an integer or \f(CW\*(C`opaque\*(C'\fR value acting as an instance of a class. There are two detailed examples in the main Platypus documentation using libarchive and unix open: .ie n .IP """libarchive"" in FFI::Platypus" 4 .el .IP "``libarchive'' in FFI::Platypus" 4 .IX Item "libarchive in FFI::Platypus" .PD 0 .ie n .IP """unix open"" in FFI::Platypus" 4 .el .IP "``unix open'' in FFI::Platypus" 4 .IX Item "unix open in FFI::Platypus" .PD .SS "Strings" .IX Subsection "Strings" From the \s-1CPU\s0's perspective, strings are just pointers. From Perl and C's perspective, those pointers point to a series of characters. For C they are null terminates (\*(L"\e0\*(R"). FFI::Platypus handles the details where they differ. Basically when you see \f(CW\*(C`char *\*(C'\fR or \f(CW\*(C`const char *\*(C'\fR used in a C header file you can expect to be able to use the \f(CW\*(C`string\*(C'\fR type. .PP .Vb 1 \& $ffi\->attach( puts => [ \*(Aqstring\*(Aq ] => \*(Aqint\*(Aq ); .Ve .PP The pointer passed into C (or other language) is to the content of the actual scalar, which means it can modify the content of a scalar. .PP \&\fB\s-1NOTE\s0\fR: When used as a return type, the string is \fIcopied\fR into a new scalar rather than using the original address. This is due to the ownership model of scalars in Perl, but it is also most of the time what you want. .PP This can be problematic when a function returns a string that the callee is expected to free. Consider the functions: .PP .Vb 7 \& char * \& get_string() \& { \& char *buffer; \& buffer = malloc(20); \& strcpy(buffer, "Perl"); \& } \& \& void \& free_string(char *buffer) \& { \& free(buffer); \& } .Ve .PP This \s-1API\s0 returns a string that you are expected to free when you are done with it. (At least they have provided an \s-1API\s0 for freeing the string instead of expecting you to call libc free)! A simple binding to get the string would be: .PP .Vb 2 \& $ffi\->attach( get_string => [] => \*(Aqstring\*(Aq ); # memory leak \& my $str = get_string(); .Ve .PP Which will work to a point, but the memory allocated by get_string will leak. Instead you need to get the opaque pointer, cast it to a string and then free it. .PP .Vb 5 \& $ffi\->attach( get_string => [] => \*(Aqopaque\*(Aq ); \& $ffi\->attach( free_string => [\*(Aqopaque\*(Aq] => \*(Aqvoid\*(Aq ); \& my $ptr = get_string(); \& my $str = $ffi\->cast( \*(Aqopaque\*(Aq => \*(Aqstring\*(Aq, $ptr ); # copies the string \& free_string($ptr); .Ve .PP If you are doing this sort of thing a lot, it can be worth adding a custom type: .PP .Vb 10 \& $ffi\->attach( free_string => [\*(Aqopaque\*(Aq] => \*(Aqvoid\*(Aq ); \& $ffi\->custom_type( \*(Aqmy_string\*(Aq => { \& native_type => \*(Aqopaque\*(Aq, \& native_to_perl => sub { \& my($ptr) = @_; \& my $str = $ffi\->cast( \*(Aqopaque\*(Aq => \*(Aqstring\*(Aq, $ptr ); # copies the string \& free_string($ptr); \& $str; \& } \& }); \& \& $ffi\->attach( get_string => [] => \*(Aqmy_string\*(Aq ); \& my $str = get_string(); .Ve .PP Since version 0.62, pointers and arrays to strings are supported as a first class type. Prior to that FFI::Platypus::Type::StringArray and FFI::Platypus::Type::StringPointer could be used, though their use in new code is discouraged. .PP .Vb 2 \& $ffi\->attach( foo => [\*(Aqstring[]\*(Aq] => \*(Aqvoid\*(Aq ); \& foo( [ \*(Aqarray\*(Aq, \*(Aqof\*(Aq, \*(Aqstrings\*(Aq ] ); \& \& $ffi\->attach( bar => [\*(Aqstring*\*(Aq] => \*(Aqvoid\*(Aq ); \& my $string = \*(Aqbaz\*(Aq; \& bar( \e$string ); # $string may be modified. .Ve .PP Strings are not allowed as return types from closure. This, again is due to the ownership model of scalars in Perl. (There is no way for Perl to know when calling language is done with the memory allocated to the string). Consider the \s-1API:\s0 .PP .Vb 1 \& typedef const char *(*get_message_t)(void); \& \& void \& print_message(get_message_t get_message) \& { \& const char *str; \& str = get_message(); \& printf("message = %s\en", str); \& } .Ve .PP It feels like this should be able to work: .PP .Vb 6 \& $ffi\->type(\*(Aq()\->string\*(Aq => \*(Aqget_message_t\*(Aq); # not ok \& $ffi\->attach( print_message => [\*(Aqget_message_t\*(Aq] => \*(Aqvoid\*(Aq ); \& my $get_message = $ffi\->closure(sub { \& return "my message"; \& }); \& print_message($get_message); .Ve .PP If the type declaration for \f(CW\*(C`get_message_t\*(C'\fR were legal, then this script would likely segfault or in the very least corrupt memory. The problem is that once \f(CW"my message"\fR is returned from the closure Perl doesn't have a reference to it anymore and will free it. To do this safely, you have to keep a reference to the scalar around and return an opaque pointer to the string using a cast. .PP .Vb 9 \& $ffi\->type(\*(Aq()\->opaque\*(Aq => \*(Aqget_message_t\*(Aq); \& $ffi\->attach( print_message => [\*(Aqget_message_t\*(Aq] => \*(Aqvoid\*(Aq ); \& my $get_message => $ffi\->closure(sub { \& our $message = "my message"; # needs to be our so that it doesn\*(Aqt \& # get free\*(Aqd \& my $ptr = $ffi\->cast(\*(Aqstring\*(Aq => \*(Aqopaque\*(Aq, $message); \& return $ptr; \& }); \& print_message($get_message); .Ve .SS "Pointer / References" .IX Subsection "Pointer / References" In C you can pass a pointer to a variable to a function in order accomplish the task of pass by reference. In Perl the same task is accomplished by passing a reference (although you can also modify the argument stack thus Perl supports proper pass by reference as well). .PP With FFI::Platypus you can define a pointer to any native, string or record type. You cannot (at least not yet) define a pointer to a pointer or a pointer to an array or any other type not otherwise supported. When passing in a pointer to something you must make sure to pass in a reference to a scalar, or \f(CW\*(C`undef\*(C'\fR (\f(CW\*(C`undef\*(C'\fR will be translated int \f(CW\*(C`NULL\*(C'\fR). .PP If the C code makes a change to the value pointed to by the pointer, the scalar will be updated before returning to Perl space. Example, with C code. .PP .Vb 8 \& /* foo.c */ \& void increment_int(int *value) \& { \& if(value != NULL) \& (*value)++; \& else \& fprintf(stderr, "NULL pointer!\en"); \& } \& \& # foo.pl \& use FFI::Platypus; \& my $ffi = FFI::Platypus\->new( api => 1 ); \& $ffi\->lib(\*(Aqlibfoo.so\*(Aq); # change to reflect the dynamic lib \& # that contains foo.c \& $ffi\->type(\*(Aqint*\*(Aq => \*(Aqint_p\*(Aq); \& $ffi\->attach(increment_int => [\*(Aqint_p\*(Aq] => \*(Aqvoid\*(Aq); \& my $i = 0; \& increment_int(\e$i); # $i == 1 \& increment_int(\e$i); # $i == 2 \& increment_int(\e$i); # $i == 3 \& increment_int(undef); # prints "NULL pointer!\en" .Ve .PP Older versions of Platypus did not support pointers to strings or records. .SS "Records" .IX Subsection "Records" Records are structured data of a fixed length. In C they are called \&\f(CW\*(C`struct\*(C'\fRs. .PP The Platypus native way of working with structured data is via the \f(CW\*(C`record\*(C'\fR type. There is also \s-1FFI::C\s0 which has some overlapping functionality. Briefly, \s-1FFI::C\s0 supports \f(CW\*(C`union\*(C'\fR and arrays of structured types, but not passing structured data by-value, while the \f(CW\*(C`record\*(C'\fR type doesn't support \f(CW\*(C`union\*(C'\fR or arrays of structured data, but does support passing structured data by-value. The remainder of this section will discuss the native Platypus \f(CW\*(C`record\*(C'\fR type, but you should remember that for some applications \s-1FFI::C\s0 might be more appropriate. .PP To declare a record type, use \f(CW\*(C`record\*(C'\fR: .PP .Vb 1 \& $ffi\->type( \*(Aqrecord (42)\*(Aq => \*(Aqmy_record_of_size_42_bytes\*(Aq ); .Ve .PP The easiest way to mange records with Platypus is by using FFI::Platypus::Record to define a record layout for a record class. Here is a brief example: .PP .Vb 1 \& package My::UnixTime; \& \& use FFI::Platypus::Record; \& \& record_layout_1(qw( \& int tm_sec \& int tm_min \& int tm_hour \& int tm_mday \& int tm_mon \& int tm_year \& int tm_wday \& int tm_yday \& int tm_isdst \& long tm_gmtoff \& string tm_zone \& )); \& \& my $ffi = FFI::Platypus\->new( api => 1 ); \& $ffi\->lib(undef); \& # define a record class My::UnixTime and alias it to "tm" \& $ffi\->type("record(My::UnixTime)*" => \*(Aqtm\*(Aq); \& \& # attach the C localtime function as a constructor \& $ffi\->attach( localtime => [\*(Aqtime_t*\*(Aq] => \*(Aqtm\*(Aq, sub { \& my($inner, $class, $time) = @_; \& $time = time unless defined $time; \& $inner\->(\e$time); \& }); \& \& package main; \& \& # now we can actually use our My::UnixTime class \& my $time = My::UnixTime\->localtime; \& printf "time is %d:%d:%d %s\en", \& $time\->tm_hour, \& $time\->tm_min, \& $time\->tm_sec, \& $time\->tm_zone; .Ve .PP For more detailed usage, see FFI::Platypus::Record. .PP Platypus does not manage the structure of a record (that is up to you), it just keeps track of their size and makes sure that they are copied correctly when used as a return type. A record in Perl is just a string of bytes stored as a scalar. In addition to defining a record layout for a record class, there are a number of tools you can use manipulate records in Perl, two notable examples are pack and unpack and Convert::Binary::C. .PP Here is an example with commentary that uses Convert::Binary::C to extract the component time values from the C \f(CW\*(C`localtime\*(C'\fR function, and then smushes them back together to get the original \f(CW\*(C`time_t\*(C'\fR (an integer). .PP .Vb 3 \& use Convert::Binary::C; \& use FFI::Platypus; \& use Data::Dumper qw( Dumper ); \& \& my $c = Convert::Binary::C\->new; \& \& # Alignment of zero (0) means use \& # the alignment of your CPU \& $c\->configure( Alignment => 0 ); \& \& # parse the tm record structure so \& # that Convert::Binary::C knows \& # what to spit out and suck in \& $c\->parse(<sizeof("tm"); \& \& # create the Platypus instance and create the appropriate \& # types and functions \& my $ffi = FFI::Platypus\->new( api => 1 ); \& $ffi\->lib(undef); \& $ffi\->type("record($tm_size)*" => \*(Aqtm\*(Aq); \& $ffi\->attach( [ localtime => \*(Aqmy_localtime\*(Aq ] => [\*(Aqtime_t*\*(Aq] => \*(Aqtm\*(Aq ); \& $ffi\->attach( [ time => \*(Aqmy_time\*(Aq ] => [\*(Aqtm\*(Aq] => \*(Aqtime_t\*(Aq ); \& \& # =============================================== \& # get the tm struct from the C localtime function \& # note that we pass in a reference to the value that time \& # returns because localtime takes a pointer to time_t \& # for some reason. \& my $time_hashref = $c\->unpack( tm => my_localtime(\etime) ); \& \& # tm_zone comes back from Convert::Binary::C as an opaque, \& # cast it into a string. We localize it to just this do \& # block so that it will be a pointer when we pass it back \& # to C land below. \& do { \& local $time_hashref\->{tm_zone} = $ffi\->cast(opaque => string => $time_hashref\->{tm_zone}); \& print Dumper($time_hashref); \& }; \& \& # =============================================== \& # convert the tm struct back into an epoch value \& my $time = my_time( $c\->pack( tm => $time_hashref ) ); \& \& print "time = $time\en"; \& print "perl time = ", time, "\en"; .Ve .PP You can also link a record type to a class. It will then be accepted when blessed into that class as an argument passed into a C function, and when it is returned from a C function it will be blessed into that class. Basically: .PP .Vb 3 \& $ffi\->type( \*(Aqrecord(My::Class)*\*(Aq => \*(Aqmy_class\*(Aq ); \& $ffi\->attach( my_function1 => [ \*(Aqmy_class\*(Aq ] => \*(Aqvoid\*(Aq ); \& $ffi\->attach( my_function2 => [ ] => \*(Aqmy_class\*(Aq ); .Ve .PP The only thing that your class \s-1MUST\s0 provide is either a \&\f(CW\*(C`ffi_record_size\*(C'\fR or \f(CW\*(C`_ffi_record_size\*(C'\fR class method that returns the size of the record in bytes. .PP Here is a longer practical example, once again using the tm struct: .PP .Vb 1 \& package My::UnixTime; \& \& use FFI::Platypus; \& use FFI::TinyCC; \& use FFI::TinyCC::Inline \*(Aqtcc_eval\*(Aq; \& \& # store the source of the tm struct \& # for repeated use later \& my $tm_source = <new( api => 1 ); \& $ffi\->lib(undef); \& # define a record class My::UnixTime and alias it \& # to "tm" \& $ffi\->type("record(My::UnixTime)*" => \*(Aqtm\*(Aq); \& \& # attach the C localtime function as a constructor \& $ffi\->attach( [ localtime => \*(Aq_new\*(Aq ] => [\*(Aqtime_t*\*(Aq] => \*(Aqtm\*(Aq ); \& \& # the constructor needs to be wrapped in a Perl sub, \& # because localtime is expecting the time_t (if provided) \& # to come in as the first argument, not the second. \& # We could also acomplish something similar using \& # custom types. \& sub new { _new(\e($_[1] || time)) } \& \& # for each attribute that we are interested in, create \& # get and set accessors. We just make accessors for \& # hour, minute and second, but we could make them for \& # all the fields if we needed. \& foreach my $attr (qw( hour min sec )) \& { \& my $tcc = FFI::TinyCC\->new; \& $tcc\->compile_string(qq{ \& $tm_source \& int \& get_$attr (struct tm *tm) \& { \& return tm\->tm_$attr; \& } \& void \& set_$attr (struct tm *tm, int value) \& { \& tm\->tm_$attr = value; \& } \& }); \& $ffi\->attach( [ $tcc\->get_symbol("get_$attr") => "get_$attr" ] => [ \*(Aqtm\*(Aq ] => \*(Aqint\*(Aq ); \& $ffi\->attach( [ $tcc\->get_symbol("set_$attr") => "set_$attr" ] => [ \*(Aqtm\*(Aq ] => \*(Aqint\*(Aq ); \& } \& \& package main; \& \& # now we can actually use our My::UnixTime class \& my $time = My::UnixTime\->new; \& printf "time is %d:%d:%d\en", $time\->get_hour, $time\->get_min, $time\->get_sec; .Ve .PP Contrast a record type which is stored as a scalar string of bytes in Perl to an opaque pointer which is stored as an integer in Perl. Both are treated as pointers in C functions. The situations when you usually want to use a record are when you know ahead of time what the size of the object that you are working with and probably something about its structure. Because a function that returns a structure copies the structure into a Perl data structure, you want to make sure that it is okay to copy the record objects that you are dealing with if any of your functions will be returning one of them. .PP Opaque pointers should be used when you do not know the size of the object that you are using, or if the objects are created and free'd through an \s-1API\s0 interface other than \f(CW\*(C`malloc\*(C'\fR and \f(CW\*(C`free\*(C'\fR. .PP The examples in this section actually use pointers to records (note the trailing star \f(CW\*(C`*\*(C'\fR in the declarations). Most programming languages allow you to pass or return a record as either pass-by-value or as a pointer (pass-by-reference). .PP C code: .PP .Vb 3 \& struct { int a; } foo_t; \& void pass_by_value_example( struct foo_t foo ); \& void pass_by_reference_example( struct foo_t *foo ); .Ve .PP Perl code: .PP .Vb 8 \& { \& package Foo; \& use FFI::Platypus::Record; \& record_layout_1( int => \*(Aqa\*(Aq ); \& } \& $ffi\->type( \*(AqRecord(Foo)\*(Aq => \*(Aqfoo_t\*(Aq ); \& $ffi\->attach( pass_by_value_example => [ \*(Aqfoo_t\*(Aq ] => \*(Aqvoid\*(Aq ); \& $ffi\->attach( pass_by_reference_example => [ \*(Aqfoo_t*\*(Aq ] => \*(Aqvoid\*(Aq ); .Ve .PP As with strings, functions that return a pointer to a record are actually copied. .PP C code: .PP .Vb 1 \& struct foo_t *return_struct_pointer_example(); .Ve .PP Perl code: .PP .Vb 3 \& $ffi\->attach( return_struct_pointer_example => [] => \*(Aqfoo_t*\*(Aq ); \& my $foo = return_struct_pointer_example(); \& # $foo is a copy of the record returned by the function. .Ve .PP As with strings, if the \s-1API\s0 expects you to free the record it returns (it is misbehaving a little, but lets set that aside), then you can work around this by returning an \f(CW\*(C`opaque\*(C'\fR type, casting to the record, and finally freeing the original pointer. .PP .Vb 5 \& use FFI::Platypus::Memory qw( free ); \& $ffi\->attach( return_struct_pointer_example => [] => \*(Aqopaque\*(Aq ); \& my $foo_ptr = return_struct_pointer_example(); \& my $foo = $ffi\->cast( \*(Aqopaque\*(Aq => \*(Aqfoo_t*\*(Aq, $foo_ptr ); \& free $foo_ptr; .Ve .SS "Fixed length arrays" .IX Subsection "Fixed length arrays" Fixed length arrays of native types and strings are supported by FFI::Platypus. Like pointers, if the values contained in the array are updated by the C function these changes will be reflected when it returns to Perl space. An example of using this is the Unix \f(CW\*(C`pipe\*(C'\fR command which returns a list of two file descriptors as an array. .PP .Vb 1 \& use FFI::Platypus; \& \& my $ffi = FFI::Platypus\->new( api => 1 ); \& $ffi\->lib(undef); \& $ffi\->attach([pipe=>\*(Aqmypipe\*(Aq] => [\*(Aqint[2]\*(Aq] => \*(Aqint\*(Aq); \& \& my @fd = (0,0); \& mypipe(\e@fd); \& my($fd1,$fd2) = @fd; \& \& print "$fd1 $fd2\en"; .Ve .PP Because of the way records are implemented, an array of records does not make sense and is not currently supported. .SS "Variable length arrays" .IX Subsection "Variable length arrays" [version 0.22] .PP Variable length arrays are supported for argument types can also be specified by using the \f(CW\*(C`[]\*(C'\fR notation but by leaving the size empty: .PP .Vb 1 \& $ffi\->type(\*(Aqint[]\*(Aq => \*(Aqvar_int_array\*(Aq); .Ve .PP When used as an argument type it will probe the array reference that you pass in to determine the correct size. Usually you will need to communicate the size of the array to the C code. One way to do this is to pass the length of the array in as an additional argument. For example the C code: .PP .Vb 10 \& int \& sum(int *array, int size) \& { \& int total, i; \& for (i = 0, total = 0; i < size; i++) \& { \& total += array[i]; \& } \& return total; \& } .Ve .PP Can be called from Perl like this: .PP .Vb 1 \& use FFI::Platypus; \& \& my $ffi = FFI::Platypus\->new( api => 1 ) \& $ffi\->lib(\*(Aq./var_array.so\*(Aq); \& \& $ffi\->attach( sum => [ \*(Aqint[]\*(Aq, \*(Aqint\*(Aq ] => \*(Aqint\*(Aq ); \& \& my @list = (1..100); \& \& print sum(\e@list, scalar @list), "\en"; .Ve .PP Another method might be to have a special value, such as 0 or \s-1NULL\s0 indicate the termination of the array. .PP Because of the way records are implemented, an array of records does not make sense and is not currently supported. .SS "Closures" .IX Subsection "Closures" A closure (sometimes called a \*(L"callback\*(R", we use the \f(CW\*(C`libffi\*(C'\fR terminology) is a Perl subroutine that can be called from C. In order to be called from C it needs to be passed to a C function. To define the closure type you need to provide a list of argument types and a return type. As of this writing only native types and strings are supported as closure argument types and only native types are supported as closure return types. Here is an example, with C code: .PP [ version 0.54 ] .PP \&\s-1EXPERIMENTAL:\s0 As of version 0.54, the record type (see FFI::Platypus::Record) is also experimentally supported as a closure argument type. One caveat is that the record member type string_rw is \s-1NOT\s0 supported and probably never will be. .PP .Vb 3 \& /* \& * closure.c \- on Linux compile with: gcc closure.c \-shared \-o closure.so \-fPIC \& */ \& \& #include \& \& typedef int (*closure_t)(int); \& closure_t my_closure = NULL; \& \& void set_closure(closure_t value) \& { \& my_closure = value; \& } \& \& int call_closure(int value) \& { \& if(my_closure != NULL) \& return my_closure(value); \& else \& fprintf(stderr, "closure is NULL\en"); \& } .Ve .PP And the Perl code: .PP .Vb 1 \& use FFI::Platypus; \& \& my $ffi = FFI::Platypus\->new( api => 1 ); \& $ffi\->lib(\*(Aq./closure.so\*(Aq); \& $ffi\->type(\*(Aq(int)\->int\*(Aq => \*(Aqclosure_t\*(Aq); \& \& $ffi\->attach(set_closure => [\*(Aqclosure_t\*(Aq] => \*(Aqvoid\*(Aq); \& $ffi\->attach(call_closure => [\*(Aqint\*(Aq] => \*(Aqint\*(Aq); \& \& my $closure1 = $ffi\->closure(sub { $_[0] * 2 }); \& set_closure($closure1); \& print call_closure(2), "\en"; # prints "4" \& \& my $closure2 = $ffi\->closure(sub { $_[0] * 4 }); \& set_closure($closure2); \& print call_closure(2), "\en"; # prints "8" .Ve .PP If you have a pointer to a function in the form of an \f(CW\*(C`opaque\*(C'\fR type, you can pass this in place of a closure type: .PP .Vb 1 \& use FFI::Platypus; \& \& my $ffi = FFI::Platypus\->new( api => 1 ); \& $ffi\->lib(\*(Aq./closure.so\*(Aq); \& $ffi\->type(\*(Aq(int)\->int\*(Aq => \*(Aqclosure_t\*(Aq); \& \& $ffi\->attach(set_closure => [\*(Aqclosure_t\*(Aq] => \*(Aqvoid\*(Aq); \& $ffi\->attach(call_closure => [\*(Aqint\*(Aq] => \*(Aqint\*(Aq); \& \& my $closure = $ffi\->closure(sub { $_[0] * 6 }); \& my $opaque = $ffi\->cast(closure_t => \*(Aqopaque\*(Aq, $closure); \& set_closure($opaque); \& print call_closure(2), "\en"; # prints "12" .Ve .PP The syntax for specifying a closure type is a list of comma separated types in parentheticals followed by a narrow arrow \f(CW\*(C`\->\*(C'\fR, followed by the return type for the closure. For example a closure that takes a pointer, an integer and a string and returns an integer would look like this: .PP .Vb 1 \& $ffi\->type(\*(Aq(opaque, int, string) \-> int\*(Aq => \*(Aqmy_closure_type\*(Aq); .Ve .PP Care needs to be taken with scoping and closures, because of the way Perl and C handle responsibility for allocating memory differently. Perl keeps reference counts and frees objects when nothing is referencing them. In C the code that allocates the memory is considered responsible for explicitly free'ing the memory for objects it has created when they are no longer needed. When you pass a closure into a C function, the C code has a pointer or reference to that object, but it has no way up letting Perl know when it is no longer using it. As a result, if you do not keep a reference to your closure around it will be free'd by Perl and if the C code ever tries to call the closure it will probably \s-1SIGSEGV.\s0 Thus supposing you have a C function \f(CW\*(C`set_closure\*(C'\fR that takes a Perl closure, this is almost always wrong: .PP .Vb 1 \& set_closure($ffi\->closure({ $_[0] * 2 })); # BAD .Ve .PP In some cases, you may want to create a closure shouldn't ever be free'd. For example you are passing a closure into a C function that will retain it for the lifetime of your application. You can use the sticky method to keep the closure, without the need to keep a reference of the closure: .PP .Vb 7 \& { \& my $closure = $ffi\->closure(sub { $_[0] * 2 }); \& $closure\->sticky; \& set_closure($closure); # OKAY \& } \& # closure still exists and is accesible from C, but \& # not from Perl land. .Ve .SS "Custom Types" .IX Subsection "Custom Types" \fICustom Types in Perl\fR .IX Subsection "Custom Types in Perl" .PP Platypus custom types are the rough analogue to typemaps in the \s-1XS\s0 world. They offer a method for converting Perl types into native types that the \f(CW\*(C`libffi\*(C'\fR can understand and pass on to the C code. .PP Example 1: Integer constants .IX Subsection "Example 1: Integer constants" .PP Say you have a C header file like this: .PP .Vb 4 \& /* possible foo types: */ \& #define FOO_STATIC 1 \& #define FOO_DYNAMIC 2 \& #define FOO_OTHER 3 \& \& typedef int foo_t; \& \& void foo(foo_t foo); \& foo_t get_foo(); .Ve .PP The challenge is here that once the source is processed by the C pre-processor the name/value mappings for these \f(CW\*(C`FOO_\*(C'\fR constants are lost. There is no way to fetch them from the library once it is compiled and linked. .PP One common way of implementing this would be to create and export constants in your Perl module, like this: .PP .Vb 1 \& package Foo; \& \& use FFI::Platypus; \& use base qw( Exporter ); \& \& our @EXPORT_OK = qw( FOO_STATIC FOO_DYNAMIC FOO_OTHER foo get_foo ); \& \& use constant FOO_STATIC => 1; \& use constant FOO_DYNAMIC => 2; \& use constant FOO_OTHER => 3; \& \& my $ffi = FFI::Platypus\->new( api => 1 ); \& $ffi\->attach(foo => [\*(Aqint\*(Aq] => \*(Aqvoid\*(Aq); \& $ffi\->attach(get_foo => [] => \*(Aqint\*(Aq); .Ve .PP Then you could use the module thus: .PP .Vb 2 \& use Foo qw( foo FOO_STATIC ); \& foo(FOO_STATIC); .Ve .PP If you didn't want to rely on integer constants or exports, you could also define a custom type, and allow strings to be passed into your function, like this: .PP .Vb 1 \& package Foo; \& \& use FFI::Platypus; \& \& our @EXPORT_OK = qw( foo get_foo ); \& \& my %foo_types = ( \& static => 1, \& dynamic => 2, \& other => 3, \& ); \& my %foo_types_reverse = reverse %foo_types; \& \& my $ffi = FFI::Platypus\->new( api => 1 ); \& $ffi\->custom_type(foo_t => { \& native_type => \*(Aqint\*(Aq, \& native_to_perl => sub { \& $foo_types{$_[0]}; \& }, \& perl_to_native => sub { \& $foo_types_reverse{$_[0]}; \& }, \& }); \& \& $ffi\->attach(foo => [\*(Aqfoo_t\*(Aq] => \*(Aqvoid\*(Aq); \& $ffi\->attach(get_foo => [] => \*(Aqfoo_t\*(Aq); .Ve .PP Now when an argument of type \f(CW\*(C`foo_t\*(C'\fR is called for it will be converted from an appropriate string representation, and any function that returns a \f(CW\*(C`foo_t\*(C'\fR type will return a string instead of the integer representation: .PP .Vb 2 \& use Foo; \& foo(\*(Aqstatic\*(Aq); .Ve .PP If the library that you are using has a lot of these constants you can try using Convert::Binary::C or another C header parser to obtain the appropriate name/value pairings for the constants that you need. .PP Example 2: Blessed references .IX Subsection "Example 2: Blessed references" .PP Supposing you have a C library that uses an opaque pointer with a pseudo \&\s-1OO\s0 interface, like this: .PP .Vb 1 \& typedef struct foo_t; \& \& foo_t *foo_new(); \& void foo_method(foo_t *, int argument); \& void foo_free(foo_t *); .Ve .PP One approach to adapting this to Perl would be to create a \s-1OO\s0 Perl interface like this: .PP .Vb 1 \& package Foo; \& \& use FFI::Platypus; \& use FFI::Platypus::API qw( arguments_get_string ); \& \& my $ffi = FFI::Platypus\->new( api => 1 ); \& $ffi\->custom_type(foo_t => { \& native_type => \*(Aqopaque\*(Aq, \& native_to_perl => sub { \& my $class = arguments_get_string(0); \& bless \e$_[0], $class; \& } \& perl_to_native => sub { ${$_[0]} }, \& }); \& \& $ffi\->attach([ foo_new => \*(Aqnew\*(Aq ] => [ \*(Aqstring\*(Aq ] => \*(Aqfoo_t\*(Aq ); \& $ffi\->attach([ foo_method => \*(Aqmethod\*(Aq ] => [ \*(Aqfoo_t\*(Aq, \*(Aqint\*(Aq ] => \*(Aqvoid\*(Aq); \& $ffi\->attach([ foo_free => \*(AqDESTROY\*(Aq ] => [ \*(Aqfoo_t\*(Aq ] => \*(Aqvoid\*(Aq); \& \& my $foo = Foo\->new; .Ve .PP Here we are blessing a reference to the opaque pointer when we return the custom type for \f(CW\*(C`foo_t\*(C'\fR, and dereferencing that reference before we pass it back in. The function \f(CW\*(C`arguments_get_string\*(C'\fR queries the C arguments to get the class name to make sure the object is blessed into the correct class (for more details on the custom type \s-1API\s0 see FFI::Platypus::API), so you can inherit and extend this class like a normal Perl class. This works because the C \*(L"constructor\*(R" ignores the class name that we pass in as the first argument. If you have a C \&\*(L"constructor\*(R" like this that takes arguments you'd have to write a wrapper for new. .PP A good example of a C library that uses this pattern, including inheritance is \f(CW\*(C`libarchive\*(C'\fR. Platypus comes with a more extensive example in \f(CW\*(C`examples/archive.pl\*(C'\fR that demonstrates this. .PP Example 3: Pointers with pack / unpack .IX Subsection "Example 3: Pointers with pack / unpack" .PP \&\s-1TODO\s0 .PP See example FFI::Platypus::Type::StringPointer. .PP Example 4: Custom Type modules and the Custom Type \s-1API\s0 .IX Subsection "Example 4: Custom Type modules and the Custom Type API" .PP \&\s-1TODO\s0 .PP See example FFI::Platypus::Type::PointerSizeBuffer. .PP Example 5: Custom Type on \s-1CPAN\s0 .IX Subsection "Example 5: Custom Type on CPAN" .PP You can distribute your own Platypus custom types on \s-1CPAN,\s0 if you think they may be applicable to others. The default namespace is prefix with \&\f(CW\*(C`FFI::Platypus::Type::\*(C'\fR, though you can stick it anywhere (under your own namespace may make more sense if the custom type is specific to your application). .PP A good example and pattern to follow is FFI::Platypus::Type::StringArray. .SH "SEE ALSO" .IX Header "SEE ALSO" .IP "FFI::Platypus" 4 .IX Item "FFI::Platypus" Main platypus documentation. .IP "FFI::Platypus::API" 4 .IX Item "FFI::Platypus::API" Custom types \s-1API.\s0 .IP "FFI::Platypus::Type::StringPointer" 4 .IX Item "FFI::Platypus::Type::StringPointer" String pointer type. .SH "AUTHOR" .IX Header "AUTHOR" Author: Graham Ollis .PP Contributors: .PP Bakkiaraj Murugesan (bakkiaraj) .PP Dylan Cali (calid) .PP pipcet .PP Zaki Mughal (zmughal) .PP Fitz Elliott (felliott) .PP Vickenty Fesunov (vyf) .PP Gregor Herrmann (gregoa) .PP Shlomi Fish (shlomif) .PP Damyan Ivanov .PP Ilya Pavlov (Ilya33) .PP Petr Pisar (ppisar) .PP Mohammad S Anwar (\s-1MANWAR\s0) .PP Håkon Hægland (hakonhagland, \s-1HAKONH\s0) .PP Meredith (merrilymeredith, \s-1MHOWARD\s0) .PP Diab Jerius (\s-1DJERIUS\s0) .SH "COPYRIGHT AND LICENSE" .IX Header "COPYRIGHT AND LICENSE" This software is copyright (c) 2015,2016,2017,2018,2019,2020 by Graham Ollis. .PP This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.