/usr/lib/x86_64-linux-gnu/perl5/5.24/FFI/Platypus/Type.pod is in libffi-platypus-perl 0.45-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 | # PODNAME: FFI::Platypus::Type
# ABSTRACT: Defining types for FFI::Platypus
# VERSION
__END__
=pod
=encoding UTF-8
=head1 NAME
FFI::Platypus::Type - Defining types for FFI::Platypus
=head1 VERSION
version 0.45
=head1 SYNOPSIS
OO Interface:
use FFI::Platypus;
my $ffi = FFI::Platypus->new;
$ffi->type('int' => 'my_int');
=head1 DESCRIPTION
This document describes how to define types using L<FFI::Platypus>.
Types may be "defined" ahead of time, or simply used when defining or
attaching functions.
# OO example of defining types
use FFI::Platypus;
my $ffi = FFI::Platypus->new;
$ffi->type('int');
$ffi->type('string');
# OO example of simply using types in function declaration or attachment
my $f = $ffi->function(puts => ['string'] => 'int');
$ffi->attach(puts => ['string'] => 'int');
If you are using the declarative interface, you can either pass the
types you need to the L<FFI::Platypus::Declare> C<use> invocation, or
you can use the L<FFI::Platypus::Declare#type> function. The advantage
of the former is that it creates a Perl constant for that type so that
you do not need to use quotation marks when using the type.
# Declarative with use
use FFI::Platypus::Declare 'string', 'int';
attach puts => [string] => int;
# Declarative with type
use FFI::Platypus::Declare;
type 'string';
type 'int';
attach puts => ['string'] => 'int';
Unless you are using aliases the L<FFI::Platypus#type> method or
L<FFI::Platypus::Declare#type> function are not necessary, but they
will throw an exception if the type is incorrectly specified or not
supported, which may be helpful.
Note: This document sometimes uses the term "C Function" 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.
=head2 meta information about types
You can get the size of a type using the L<FFI::Platypus#sizeof> method.
# OO interface
my $intsize = $ffi->sizeof('int');
my intarraysize = $ffi->sizeof('int[64]');
# Declare interface
my $intsize = sizeof 'int';
my intarraysize = sizeof 'int[64]';
=head2 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 L<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:
# OO interface
my $address = $ffi->cast('string' => 'opaque', $string);
my $string = $ffi->cast('opaque' => 'string', $pointer);
# Declare interface
use FFI::Platypus::Declare;
my $address = cast 'string' => 'opaque', $string;
my $string = cast 'opaque' => 'string', $pointer;
=head2 aliases
Some times using alternate names is useful for documenting the purpose
of an argument or return type. For this "aliases" can be helpful. The
second argument to the L<FFI::Platypus#type> method or
L<FFI::Platypus::Declare#type> function can be used to define a type
alias that can later be used by function declaration and attachment.
# OO style
use FFI::Platypus;
my $ffi = FFI::Platypus->new;
$ffi->type('int' => 'myint');
$ffi->type('string' => 'mystring');
my $f = $ffi->function( puts => ['mystring'] => 'myint' );
$ffi->attach( puts => ['mystring'] => 'myint' );
# Declarative style
use FFI::Platypus::Declare;
type 'int' => 'myint';
type 'string' => 'mystring';
attach puts => ['mystring'] => 'myint';
# Declarative style with use (and with fewer quotes)
use FFI::Platypus::Declare
[ int => 'myint' ],
[ string => 'mystring' ];
attach puts => [mystring] => myint;
Aliases are contained without the L<FFI::Platypus> object, or the
current package if you are using L<FFI::Platypus::Declare>, so feel free
to define your own crazy types without stepping on the toes of other
CPAN Platypus developers.
=for stopwords tm
=head1 TYPE CATEGORIES
=head2 Native types
So called native types are the types that the CPU 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.
=head3 the void type
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).
=head3 integer types
The following native integer types are always available (parentheticals
indicates the usual corresponding C type):
=over 4
=item sint8
Signed 8 bit byte (C<signed char>, C<int8_t>).
=item uint8
Unsigned 8 bit byte (C<unsigned char>, C<uint8_t>).
=item sint16
Signed 16 bit integer (C<short>, C<int16_t>)
=item uint16
Unsigned 16 bit integer (C<unsigned short>, C<uint16_t>)
=item sint32
Signed 32 bit integer (C<int>, C<int32_t>)
=item uint32
Unsigned 32 bit integer (C<unsigned int>, C<uint32_t>)
=item sint64
Signed 64 bit integer (C<long> or C<long long>, C<int64_t>)
=item uint64
Unsigned 64 bit integer (C<unsigned long> or C<unsigned long long>,
C<uint64_t>)
=back
You may also use C<uchar>, C<ushort>, C<uint> and C<ulong> as short
names for C<unsigned char>, C<unsigned short>, C<unsigned int> and
C<unsigned long>.
These integer types are also available, but there actual size and sign
may depend on the platform.
=over 4
=item char
Somewhat confusingly, C<char> is an integer type! This is really an
alias for either C<sint8_t> or C<uint8_t> 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 L<ord|perlfunc#ord> function.
Here is an example that uses the standard libc C<isalpha>, C<isdigit>
type functions:
use FFI::Platypus;
my $ffi = FFI::Platypus->new;
$ffi->lib(undef);
$ffi->type('int' => 'character');
my @list = qw(
alnum alpha ascii blank cntrl digit lower print punct
space upper xdigit
);
$ffi->attach("is$_" => ['character'] => 'int') for @list;
my $char = shift(@ARGV) || 'a';
no strict 'refs';
printf "'%s' is %s %s\n", $char, $_, &{'is'.$_}(ord $char) for @list;
=item size_t
This is usually an C<unsigned long>, but it is up to the compiler to
decide. The C<malloc> function is defined in terms of C<size_t>:
use FFI::Platypus::Declare qw( size_t opaque );
attach malloc => [size_t] => opaque;
(Note that you can get C<malloc> from L<FFI::Platypus::Memory>).
=back
There are a number of other types that may or may not be available if
they are detected when L<FFI::Platypus> is installed. This includes
things like C<wchar_t>, C<off_t>, C<wint_t>. You can use this script to
list all the integer types that L<FFI::Platypus> knows about, plus how
they are implemented.
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 'int';
printf "%20s %s\n", $type_name, $meta->{ffi_type};
}
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.
=head3 floating point types
The following native floating point types are always available
(parentheticals indicates the usual corresponding C type):
=over 4
=item float
Single precision floating point (I<float>)
=item double
Double precision floating point (I<double>)
=item longdouble
Floating point that may be larger than C<double> (I<longdouble>). This
type is only available if supported by the C compiler used to build
L<FFI::Platypus>. There may be a performance penalty for using this
type, even if your Perl uses long doubles internally for its number
value (NV) type, because of the way L<FFI::Platypus> interacts with
C<libffi>.
As an argument type either regular number values (NV) or instances of
L<Math::LongDouble> are accepted. When used as a return type,
L<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 (NV) is.
=item complex_float
Complex single precision floating point (I<float complex>)
=item complex_double
Complex double precision floating point (I<double complex>)
C<complex_float> and C<complex_double> 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.
=back
Support for C<complex_float>, C<complex_double> and C<longdouble> are
limited at the moment. Complex types can only be used as simple
arguments (not return types, pointers, arrays or record members) and the
C<longdouble> can only be used as simple argument or return values (not
pointers, arrays or record members). Adding support for these is not
difficult, but time consuming, so if you are in need of these features
please do not hesitate to open a support ticket on the project's github
issue tracker:
L<https://github.com/plicease/FFI-Platypus/issues>
In particular I am hesitant to implementing complex return types, as
there are performance and interface ramifications, and I would
appreciate talking to someone who is actually going to use these
features.
=head3 opaque pointers
Opaque pointers are simply a pointer to a region of memory that you do
not manage, and do not know the structure of. It is like a C<void *> in
C. These types are represented in Perl space as integers and get
converted to and from pointers by L<FFI::Platypus>. You may use
C<pointer> as an alias for C<opaque>. (The Platypus documentation uses
the convention of using "pointer" to refer to pointers to known types
(see below) and "opaque" as short hand for opaque pointer).
As an example, libarchive defines C<struct archive> type in its header
files, but does not define its content. Internally it is defined as a
C<struct> type, but the caller does not see this. It is therefore
opaque to its caller. There are C<archive_read_new> and
C<archive_write_new> functions to create a new instance of this opaque
object and C<archive_read_free> and C<archive_write_free> to destroy
this objects when you are done.
use FFI::Platypus::Declare qw( opaque int );
attach archive_read_new => [] => opaque;
attach archive_write_new => [] => opaque;
attach archive_read_free => [opaque] => int;
attach archive_write_free => [opaque] => int;
As a special case, when you pass C<undef> into a function that takes an
opaque type it will be translated into C<NULL> for C. When a C function
returns a NULL pointer, it will be translated back to C<undef>.
=head2 Strings
From the CPU'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 ("\0"). L<FFI::Platypus> handles the details
where they differ. Basically when you see C<char *> or C<const char *>
used in a C header file you can expect to be able to use the C<string>
type.
use FFI::Platypus::Declare qw( string int );
attach puts => [string] => int;
Currently strings are only supported as simple argument and return types
and as argument (but not return types) for closures. In the future pointers
to strings or arrays of strings may be supported.
=head2 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 is task is
accomplished by passing a reference (although you can also modify the
argument stack thus Perl supports proper pass by reference as well).
With L<FFI::Platypus> you can define a pointer types to any of the
native types described above (that is all the types we have covered so
far except for strings). When using this you must make sure to pass in
a reference to a scalar, or C<undef> (C<undef> will be translated into
C<NULL>).
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.
/* foo.c */
void increment_int(int *value)
{
if(value != NULL)
(*value)++;
else
fprintf(stderr, "NULL pointer!\n");
}
# foo.pl
use FFI::Platypus::Declare 'void', ['int*' =>'int_p'];
lib 'libfoo.so'; # change to reflect the dynamic lib
# that contains foo.c
attach increment_int => [int_p] => void;
my $i = 0;
increment_int(\$i); # $i == 1
increment_int(\$i); # $i == 2
increment_int(\$i); # $i == 3
increment_int(undef); # prints "NULL pointer!\n"
=head2 Records
Records are structured data of a fixed length. In C they are called
C<struct>s To declare a record type, use C<record>:
$ffi->type( 'record (42)' => 'my_record_of_size_42_bytes' );
The easiest way to mange records with Platypus is by using
L<FFI::Platypus::Record> to define a record layout for a record class.
Here is a brief example:
package My::UnixTime;
use FFI::Platypus::Record;
record_layout(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;
$ffi->lib(undef);
# define a record class My::UnixTime and alias it to "tm"
$ffi->type("record(My::UnixTime)" => 'tm');
# attach the C localtime function as a constructor
$ffi->attach( localtime => ['time_t*'] => 'tm', sub {
my($inner, $class, $time) = @_;
$time = time unless defined $time;
$inner->(\$time);
});
package main;
# now we can actually use our My::UnixTime class
my $time = My::UnixTime->localtime;
printf "time is %d:%d:%d %s\n",
$time->tm_hour,
$time->tm_min,
$time->tm_sec,
$time->tm_zone;
For more detailed usage, see L<FFI::Platypus::Record>.
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 L<pack and unpack|perlpacktut>
and L<Convert::Binary::C>.
Here is an example with commentary that uses L<Convert::Binary::C> to
extract the component time values from the C C<localtime> function, and
then smushes them back together to get the original C<time_t> (an
integer).
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(<<ENDC);
struct tm {
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 int tm_gmtoff;
const char *tm_zone;
};
ENDC
# get the size of tm so that we can give it
# to Platypus
my $tm_size = $c->sizeof("tm");
# create the Platypus instance and create the appropriate
# types and functions
my $ffi = FFI::Platypus->new;
$ffi->lib(undef);
$ffi->type("record($tm_size)" => 'tm');
$ffi->attach( [ localtime => 'my_localtime' ] => ['time_t*'] => 'tm' );
$ffi->attach( [ time => 'my_time' ] => ['tm'] => 'time_t' );
# ===============================================
# 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(\time) );
# 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\n";
print "perl time = ", time, "\n";
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:
$ffi->type( 'record(My::Class)' => 'my_class' );
$ffi->attach( my_function1 => [ 'my_class' ] => 'void' );
$ffi->attach( my_function2 => [ ] => 'my_class' );
The only thing that your class MUST provide is either a
C<ffi_record_size> or C<_ffi_record_size> class method that returns the
size of the record in bytes.
Here is a longer practical example, once again using the tm struct:
package My::UnixTime;
use FFI::Platypus;
use FFI::TinyCC;
use FFI::TinyCC::Inline 'tcc_eval';
# store the source of the tm struct
# for repeated use later
my $tm_source = <<ENDTM;
struct tm {
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 int tm_gmtoff;
const char *tm_zone;
};
ENDTM
# calculate the size of the tm struct
# this time using Tiny CC
my $tm_size = tcc_eval qq{
$tm_source
int main()
{
return sizeof(struct tm);
}
};
# To use My::UnixTime as a record class, we need to
# specify a size for the record, a function called
# either ffi_record_size or _ffi_record_size should
# return the size in bytes. This function has to
# be defined before you try to define it as a type.
sub _ffi_record_size { $tm_size };
my $ffi = FFI::Platypus->new;
$ffi->lib(undef);
# define a record class My::UnixTime and alias it
# to "tm"
$ffi->type("record(My::UnixTime)" => 'tm');
# attach the C localtime function as a constructor
$ffi->attach( [ localtime => '_new' ] => ['time_t*'] => 'tm' );
# 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(\($_[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" ] => [ 'tm' ] => 'int' );
$ffi->attach( [ $tcc->get_symbol("set_$attr") => "set_$attr" ] => [ 'tm' ] => 'int' );
}
package main;
# now we can actually use our My::UnixTime class
my $time = My::UnixTime->new;
printf "time is %d:%d:%d\n", $time->get_hour, $time->get_min, $time->get_sec;
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.
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 API interface other than C<malloc> and C<free>.
=head2 Fixed length arrays
Fixed length arrays of native types are supported by L<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 C<pipe> command which returns a
list of two file descriptors as an array.
use FFI::Platypus;
my $ffi = FFI::Platypus->new;
$ffi->lib(undef);
$ffi->attach([pipe=>'mypipe'] => ['int[2]'] => 'int');
my @fd = (0,0);
mypipe(\@fd);
my($fd1,$fd2) = @fd;
print "$fd1 $fd2\n";
=head2 Variable length arrays
[version 0.22]
Variable length arrays are supported for argument types can also be
specified by using the C<[]> notation but by leaving the size empty:
$ffi->type('int[]' => 'var_int_array');
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:
int
sum(int *array, int size)
{
int total,i;
for(i=0,total=0; i<size; i++)
{
total += array[i];
}
return total;
}
Can be called from Perl like this:
use FFI::Platypus;
my $ffi = FFI::Platypus->new;
$ffi->lib('./var_array.so');
$ffi->attach( sum => [ 'int[]', 'int' ] => 'int' );
my @list = (1..100);
print sum(\@list, scalar @list), "\n";
Another method might be to have a special value, such as 0 or NULL
indicate the termination of the array.
=head2 Closures
A closure (called a "callback" by L<FFI::Raw>, we use the C<libffi>
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:
/*
* closure.c - on Linux compile with: gcc closure.c -shared -o closure.so -fPIC
*/
#include <stdio.h>
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\n");
}
And the Perl code:
use FFI::Platypus;
my $ffi = FFI::Platypus->new;
$ffi->lib('./closure.so');
$ffi->type('(int)->int' => 'closure_t');
$ffi->attach(set_closure => ['closure_t'] => 'void');
$ffi->attach(call_closure => ['int'] => 'int');
my $closure1 = $ffi->closure(sub { $_[0] * 2 });
set_closure($closure1);
print call_closure(2), "\n"; # prints "4"
my $closure2 = $ffi->closure(sub { $_[0] * 4 });
set_closure($closure2);
print call_closure(2), "\n"; # prints "8"
If you have a pointer to a function in the form of an C<opaque> type,
you can pass this in place of a closure type:
use FFI::Platypus;
my $ffi = FFI::Platypus->new;
$ffi->lib('./closure.so');
$ffi->type('(int)->int' => 'closure_t');
$ffi->attach(set_closure => ['closure_t'] => 'void');
$ffi->attach(call_closure => ['int'] => 'int');
my $closure = $ffi->closure(sub { $_[0] * 6 });
my $opaque = $ffi->cast(closure_t => 'opaque', $closure);
set_closure($opaque);
print call_closure(2), "\n"; # prints "12"
The syntax for specifying a closure type is a list of comma separated
types in parentheticals followed by a narrow arrow C<-E<gt>>, 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:
$ffi->type('(opaque, int, string) -> int' => 'my_closure_type');
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 SIGSEGV. Thus supposing you have a C function C<set_closure>
that takes a Perl closure, this is almost always wrong:
set_closure(closure { $_[0] * 2 }); # BAD
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 keyword to indicate this, without the need to keep a reference of
the closure:
set_closure(sticky closure { $_[0] * 2 }); # OKAY
=head2 Custom Types
=head3 Custom Types in Perl
Platypus custom types are the rough analogue to typemaps in the XS
world. They offer a method for converting Perl types into native types
that the C<libffi> can understand and pass on to the C code.
=head4 Example 1: Integer constants
Say you have a C header file like this:
/* 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();
One common way of implementing this would be to create and export
constants in your Perl module, like this:
package Foo;
use FFI::Platypus::Declare qw( void int );
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;
attach foo => [int] => void;
attach get_foo => [] => int;
Then you could use the module thus:
use Foo qw( foo FOO_STATIC );
foo(FOO_STATIC);
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:
package Foo;
use FFI::Platypus::Declare qw( void );
use base qw( Exporter );
our @EXPORT_OK = qw( foo get_foo );
my %foo_types = (
static => 1,
dynamic => 2,
other => 3,
);
my %foo_types_reverse = reverse %foo_types;
custom_type foo_t => {
native_type => 'int',
native_to_perl => sub {
$foo_types{$_[0]};
},
perl_to_native => sub {
$foo_types_reverse{$_[0]};
},
};
attach foo => ['foo_t'] => void;
attach get_foo => [] => foo_t;
Now when an argument of type C<foo_t> is called for it will be converted
from an appropriate string representation, and any function that returns
a C<foo_t> type will return a string instead of the integer
representation:
use Foo;
foo('static');
=head4 Example 2: Blessed references
Supposing you have a C library that uses an opaque pointer with a pseudo
OO interface, like this:
typedef struct foo_t;
foo_t *foo_new();
void foo_method(foo_t *, int argument);
void foo_free(foo_t *);
One approach to adapting this to Perl would be to create a OO Perl
interface like this:
package Foo;
use FFI::Platypus::Declare
'void', 'int';
use FFI::Platypus::API qw( arguments_get_string );
custom_type foo_t => {
native_type => 'opaque',
native_to_perl => sub {
my $class = arguments_get_string(0);
bless \$_[0], $class;
}
perl_to_native => sub { ${$_[0]} },
};
attach [ foo_new => 'new' ] => [ string ] => 'foo_t' );
attach [ foo_method => 'method' ] => [ 'foo_t', int ] => void;
attach [ foo_free => 'DESTROY' ] => [ 'foo_t' ] => void;
my $foo = Foo->new;
Here we are blessing a reference to the opaque pointer when we return
the custom type for C<foo_t>, and dereferencing that reference before we
pass it back in. The function C<arguments_get_string> 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 API see
L<FFI::Platypus::API>), so you can inherit and extend this class like a
normal Perl class. This works because the C "constructor" ignores the
class name that we pass in as the first argument. If you have a C
"constructor" like this that takes arguments you'd have to write a
wrapper for new.
I good example of a C library that uses this pattern, including
inheritance is C<libarchive>. Platypus comes with a more extensive
example in C<examples/archive.pl> that demonstrates this.
=head4 Example 3: Pointers with pack / unpack
TODO
See example L<FFI::Platypus::Type::StringPointer>.
=head4 Example 4: Custom Type modules and the Custom Type API
TODO
See example L<FFI::Platypus::Type::PointerSizeBuffer>.
=head4 Example 5: Custom Type on CPAN
You can distribute your own Platypus custom types on CPAN, if you think
they may be applicable to others. The default namespace is prefix with
C<FFI::Platypus::Type::>, though you can stick it anywhere (under your
own namespace may make more sense if the custom type is specific to your
application).
A good example and pattern to follow is
L<FFI::Platypus::Type::StringArray>.
=head3 Custom Types in C/XS
Custom types written in C or XS are a future goal of the
L<FFI::Platypus> project. They should allow some of the flexibility of
custom types written in Perl, with potential performance improvements of
native code.
=head1 SEE ALSO
=over 4
=item L<FFI::Platypus>
Main platypus documentation.
=item L<FFI::Platypus::Declare>
Declarative interface for L<FFI::Platypus>.
=item L<FFI::Platypus::API>
Custom types API.
=item L<FFI::Platypus::Type::StringPointer>
String pointer type.
=back
=head1 AUTHOR
Author: Graham Ollis E<lt>plicease@cpan.orgE<gt>
Contributors:
Bakkiaraj Murugesan (bakkiaraj)
Dylan Cali (calid)
pipcet
Zaki Mughal (zmughal)
Fitz Elliott (felliott)
Vickenty Fesunov (vyf)
Gregor Herrmann (gregoa)
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2015 by Graham Ollis.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut
|