1package FFI::Platypus::Bundle; 2 3use strict; 4use warnings; 5use 5.008004; 6use Carp (); 7 8# ABSTRACT: Bundle foreign code with your Perl module 9our $VERSION = '1.56'; # VERSION 10 11 12package FFI::Platypus; 13 14sub _bundle 15{ 16 my @arg_ptrs; 17 18 if(defined $_[-1] && ref($_[-1]) eq 'ARRAY') 19 { 20 @arg_ptrs = @{ pop @_ }; 21 } 22 23 push @arg_ptrs, undef; 24 25 my($self, $package) = @_; 26 $package = caller unless defined $package; 27 28 require List::Util; 29 30 my($pm) = do { 31 my $pm = "$package.pm"; 32 $pm =~ s{::}{/}g; 33 # if the module is already loaded, we can use %INC 34 # otherwise we can go through @INC and find the first .pm 35 # this doesn't handle all edge cases, but probably enough 36 List::Util::first(sub { (defined $_) && (-f $_) }, ($INC{$pm}, map { "$_/$pm" } @INC)); 37 }; 38 39 Carp::croak "unable to find module $package" unless $pm; 40 41 my @parts = split /::/, $package; 42 my $incroot = $pm; 43 { 44 my $c = @parts; 45 $incroot =~ s![\\/][^\\/]+$!! while $c--; 46 } 47 48 my $txtfn = List::Util::first(sub { -f $_ }, do { 49 my $dir = join '/', @parts; 50 my $file = $parts[-1] . ".txt"; 51 ( 52 "$incroot/auto/$dir/$file", 53 "$incroot/../arch/auto/$dir/$file", 54 ); 55 }); 56 57 my $lib; 58 59 if($txtfn) 60 { 61 $lib = do { 62 my $fh; 63 open($fh, '<', $txtfn) or die "unable to read $txtfn $!"; 64 my $line = <$fh>; 65 close $fh; 66 $line =~ /^FFI::Build\@(.*)$/ 67 ? "$incroot/$1" 68 : Carp::croak "bad format $txtfn"; 69 }; 70 Carp::croak "bundle code is missing: $lib" unless -f $lib; 71 } 72 elsif(-d "$incroot/../ffi") 73 { 74 require FFI::Build::MM; 75 require Capture::Tiny; 76 require Cwd; 77 require File::Spec; 78 my $save = Cwd::getcwd(); 79 chdir "$incroot/.."; 80 my($output, $error) = Capture::Tiny::capture_merged(sub { 81 $lib = eval { 82 my $dist_name = $package; 83 $dist_name =~ s/::/-/g; 84 my $fbmm = FFI::Build::MM->new( save => 0 ); 85 $fbmm->mm_args( DISTNAME => $dist_name ); 86 my $build = $fbmm->load_build('ffi', undef, 'ffi/_build'); 87 $build->build; 88 }; 89 $@; 90 }); 91 if($error) 92 { 93 chdir $save; 94 print STDERR $output; 95 die $error; 96 } 97 else 98 { 99 $lib = File::Spec->rel2abs($lib); 100 chdir $save; 101 } 102 } 103 else 104 { 105 Carp::croak "unable to find bundle code for $package"; 106 } 107 108 my $handle = FFI::Platypus::DL::dlopen($lib, FFI::Platypus::DL::RTLD_PLATYPUS_DEFAULT()) 109 or Carp::croak "error loading bundle code: $lib @{[ FFI::Platypus::DL::dlerror() ]}"; 110 111 $self->{handles}->{$lib} = $handle; 112 113 $self->lib($lib); 114 115 if(my $init = eval { $self->function( 'ffi_pl_bundle_init' => [ 'string', 'sint32', 'opaque[]' ] => 'void' ) }) 116 { 117 $init->call($package, scalar(@arg_ptrs)-1, \@arg_ptrs); 118 } 119 120 if(my $init = eval { $self->function( 'ffi_pl_bundle_constant' => [ 'string', 'opaque' ] => 'void' ) }) 121 { 122 require FFI::Platypus::Constant; 123 my $api = FFI::Platypus::Constant->new($package); 124 $init->call($package, $api->ptr); 125 } 126 127 if(my $address = $self->find_symbol( 'ffi_pl_bundle_fini' )) 128 { 129 push @{ $self->{fini} }, sub { 130 my $self = shift; 131 $self->function( $address => [ 'string' ] => 'void' ) 132 ->call( $package ); 133 }; 134 } 135 136 $self; 137} 138 1391; 140 141__END__ 142 143=pod 144 145=encoding UTF-8 146 147=head1 NAME 148 149FFI::Platypus::Bundle - Bundle foreign code with your Perl module 150 151=head1 VERSION 152 153version 1.56 154 155=head1 SYNOPSIS 156 157C<ffi/foo.c>: 158 159 #include <ffi_platypus_bundle.h> 160 #include <string.h> 161 162 typedef struct { 163 char *name; 164 int value; 165 } foo_t; 166 167 foo_t* 168 foo__new(const char *class_name, const char *name, int value) 169 { 170 (void)class_name; 171 foo_t *self = malloc( sizeof( foo_t ) ); 172 self->name = strdup(name); 173 self->value = value; 174 return self; 175 } 176 177 const char * 178 foo__name(foo_t *self) 179 { 180 return self->name; 181 } 182 183 int 184 foo__value(foo_t *self) 185 { 186 return self->value; 187 } 188 189 void 190 foo__DESTROY(foo_t *self) 191 { 192 free(self->name); 193 free(self); 194 } 195 196C<lib/Foo.pm>: 197 198 package Foo; 199 200 use strict; 201 use warnings; 202 use FFI::Platypus 1.00; 203 204 { 205 my $ffi = FFI::Platypus->new( api => 1 ); 206 207 $ffi->type('object(Foo)' => 'foo_t'); 208 $ffi->mangler(sub { 209 my $name = shift; 210 $name =~ s/^/foo__/; 211 $name; 212 }); 213 214 $ffi->bundle; 215 216 $ffi->attach( new => [ 'string', 'string', 'int' ] => 'foo_t' ); 217 $ffi->attach( name => [ 'foo_t' ] => 'string' ); 218 $ffi->attach( value => [ 'foo_t' ] => 'int' ); 219 $ffi->attach( DESTROY => [ 'foo_t' ] => 'void' ); 220 } 221 222 1; 223 224C<t/foo.t> 225 226 use Test2::V0; 227 use Foo; 228 229 my $foo = Foo->new("platypus", 10); 230 isa_ok $foo, 'Foo'; 231 is $foo->name, "platypus"; 232 is $foo->value, 10; 233 234 done_testing; 235 236C<Makefile.PL>: 237 238 use ExtUtils::MakeMaker; 239 use FFI::Build::MM; 240 my $fbmm = FFI::Build::MM->new; 241 WriteMakefile( 242 $fbmm->mm_args( 243 NAME => 'Foo', 244 DISTNAME => 'Foo', 245 VERSION => '1.00', 246 # ... 247 ) 248 ); 249 250 sub MY::postamble 251 { 252 $fbmm->mm_postamble; 253 } 254 255or C<dist.ini>: 256 257 name = Foo 258 version = 0.01 259 ... 260 261 [FFI::Build] 262 version = 1.04 263 264=head1 DESCRIPTION 265 266This document serves as a tutorial for using the new bundling interface provided 267by L<FFI::Platypus> as of api version 1. It requires L<FFI::Platypus> of at least 2681.00. 269 270Sometimes when writing FFI bindings you need to include a little C code (or your 271favorite compiled language) to finish things off. Alternatively, you might just 272want to write some C code (or your favorite compiled language) to include with your 273Perl module to make a tight loop faster. The bundling interface has you covered. 274 275=head2 Basic example 276 277To illustrate we will go through the files in the synopsis and explain 278how and why they work. To start with we have some C code which emulates object 279oriented code using C<foo__> as a prefix. We use a C struct that we call 280C<foo_t> to store our object data. On the C level the struct acts as a class, 281when combined with its functions that act as methods. The constructor just 282allocates the memory it needs for the C<foo_t> instance, fills in the 283appropriate fields and returns the pointer: 284 285 foo_t* 286 foo__new(const char *class_name, const char *name, int value) 287 { 288 (void) class_name; 289 foo_t *self = malloc( sizeof( foo_t ) ); 290 self->name = strdup(name); 291 self->value = value; 292 return self; 293 } 294 295We include a class name as the first argument, because Perl will include that 296when calling the constructor, but we do not use it here. An exercise for the 297reader would be to add hierarchical inheritance. 298 299There are also some methods which return member values. This class has only 300read only members, but you could have read/write or other methods depending 301on your needs. 302 303 const char * 304 foo__name(foo_t *self) 305 { 306 return self->name; 307 } 308 309We also include a destructor so that the memory owned by the object can be 310freed when it is no longer needed. 311 312 void 313 foo__DESTROY(foo_t *self) 314 { 315 free(self->name); 316 free(self); 317 } 318 319This might start to look a little like a Perl module, and when we look at the Perl 320code that binds to this code, you will see why. First lets prepare the 321L<FFI::Platypus> instance and specify the correct api version: 322 323 my $ffi = FFI::Platypus->new( api => 1 ); 324 325The bundle interface is only supported with api version 1, so if you try to use 326version 0 it will not work. Next we define an object type for C<foo_t> which will 327associate it with the Perl class C<Foo>. 328 329 $ffi->type('object(Foo)' => 'foo_t'); 330 331As object type is a blessed reference to an opaque (default) or integer type which 332can be used as a Perl object. Platypus does the translating of Perl object to and 333from the foo_t pointers that the C code understands. For more details on Platypus 334types see L<FFI::Platypus::Type>. 335 336Next we set the mangler on the Platypus instance so that we can refer to function 337names without the C<foo__> prefix. You could just not use the prefix in your C 338code and skip this step, or you could refer to the function names in their full 339in your Perl code, however, this saves extra typing and allows you to bundle more 340than one class with your Perl code without having to worry about name conflicts. 341 342 $ffi->mangler(sub { 343 my $name = shift; 344 $name =~ s/^/foo__/; 345 $name; 346 }); 347 348Finally we let Platypus know that we will be bundling code. 349 350 $ffi->bundle; 351 352By default, this searches for the appropriate place for your dynamic libraries using 353the current package. In some cases you may need to override this, for example if your 354dist is named C<Foo-Bar> but your specific class is named C<Foo::Bar::Baz>, you'd 355want something like this: 356 357 package Foo::Bar::Baz; 358 use FFI::Platypus 1.00; 359 my $ffi = FFI::Platypus->new( api => 1 ); 360 $ffi->bundle('Foo::Bar'); 361 ... 362 363Now, finally we can attach the methods for our class: 364 365 $ffi->attach( new => [ 'string', 'int' ] => 'foo_t' ); 366 $ffi->attach( name => [ 'foo_t' ] => 'string' ); 367 $ffi->attach( value => [ 'foo_t' ] => 'int' ); 368 $ffi->attach( DESTROY => [ 'foo_t' ] => 'void' ); 369 370Note that we do not have to include the C<foo__> prefix because of the way we set up 371the mangler. If we hadn't done that then we could instead attach with the full names: 372 373 $ffi->attach( [ 'foo__new' => 'new' ] => [ 'string', 'int' ] => 'foo_t' ); 374 $ffi->attach( [ 'foo__name' => 'name' ] => [ 'foo_t' ] => 'string' ); 375 ... 376 377You're done! You can now use this class. Lets write a test to make sure it works, 378 379 use Test2::V0; 380 use Foo; 381 382 my $foo = Foo->new("platypus", 10); 383 isa_ok $foo, 'Foo'; 384 is $foo->name, "platypus"; 385 is $foo->value, 10; 386 387 done_testing; 388 389and use C<prove> to check that it works: 390 391 % prove -lvm 392 t/foo.t .. 393 ok 1 - An object of class 'Foo' isa 'Foo' 394 ok 2 395 ok 3 396 1..3 397 ok 398 All tests successful. 399 Files=1, Tests=3, 0 wallclock secs ( 0.02 usr 0.00 sys + 0.14 cusr 0.03 csys = 0.19 CPU) 400 Result: PASS 401 402Platypus automatically compiles and links the dynamic library for you: 403 404 % ls ffi/_build 405 foo.c.o libFoo.so 406 407The C code will be rebuilt next time if the source code is newer than the object or dynamic libraries 408files. If the source files are not changed, then it won't be rebuilt to save time. If you are using 409the code without MakeMaker, or another build system you are responsible for cleaning up these files. 410This is intended as a convenience to allow you to test your code without having to invoke MakeMaker, 411or C<dzil> or whatever build system you are using. 412 413When you distribute your module though, you will want the dynamic library built just once 414at build-time and installed correctly so that it can be found at run-time. You don't need 415to make any changes to your C or Perl code, but you do need to tell MakeMaker to build and 416install the appropriate files using L<FFI::Build::MM>: 417 418 use ExtUtils::MakeMaker; 419 use FFI::Build::MM; 420 my $fbmm = FFI::Build::MM->new; 421 WriteMakefile( 422 $fbmm->mm_args( 423 NAME => 'Foo', 424 DISTNAME => 'Foo', 425 VERSION => '1.00', 426 # ... 427 ) 428 ); 429 430 sub MY::postamble 431 { 432 $fbmm->mm_postamble; 433 } 434 435And we can invoke all the normal MakeMaker style stuff and our C code will be compiled, linked 436and installed at the appropriate steps. 437 438 % perl Makefile.PL 439 Generating a Unix-style Makefile 440 Writing Makefile for Foo 441 Writing MYMETA.yml and MYMETA.json 442 % make 443 cp lib/Foo.pm blib/lib/Foo.pm 444 "/Users/ollisg/perl5/perlbrew/perls/perl-5.30.0/bin/perl" -MFFI::Build::MM=cmd -e fbx_build 445 CC ffi/foo.c 446 LD blib/lib/auto/share/dist/Foo/lib/libFoo.dylib 447 % make test 448 "/Users/ollisg/perl5/perlbrew/perls/perl-5.30.0/bin/perl" -MFFI::Build::MM=cmd -e fbx_build 449 "/Users/ollisg/perl5/perlbrew/perls/perl-5.30.0/bin/perl" -MFFI::Build::MM=cmd -e fbx_test 450 PERL_DL_NONLAZY=1 "/Users/ollisg/perl5/perlbrew/perls/perl-5.30.0/bin/perl" "-MExtUtils::Command::MM" "-MTest::Harness" "-e" "undef *Test::Harness::Switches; test_harness(0, 'blib/lib', 'blib/arch')" t/*.t 451 t/foo.t .. ok 452 All tests successful. 453 Files=1, Tests=3, 0 wallclock secs ( 0.01 usr 0.00 sys + 0.06 cusr 0.01 csys = 0.08 CPU) 454 Result: PASS 455 456If the C<Makefile.PL> file above looks overly complicated, you can use the 457L<Dist::Zilla::Plugin::FFI::Build> plugin to simplify your life if you are 458using L<Dist::Zilla>: 459 460 [FFI::Build] 461 version = 1.04 462 463Specifying version 1.04 will ensure that any C<.o> or C<.so> files are pruned 464from your build tree and not distributed by mistake. 465 466=head2 Initialization example 467 468The bundle interface also gives you entry points which will be called automatically 469when your code is loaded and unloaded if they are found. 470 471=over 4 472 473=item C<ffi_pl_bundle_init> 474 475 void ffi_pl_bundle_init(const char *package, int argc, void *argv[]); 476 477Called when the dynamic library is loaded. C<package> is the Perl package 478that called C<bundle> from Perl space. C<argc> and C<argv> represents an 479array of opaque pointers that can be passed as an array to bundle as the 480last argument. (the count C<argc> is a little redundant because C<argv> 481is also NULL terminated). 482 483=item C<ffi_pl_bundle_constant> 484 485 void ffi_pl_bundle_constant(const char *package, ffi_platypus_constant_t *c); 486 487Called immediately after C<ffi_pl_bundle_init>, and is intended to allow 488you to set Perl constants from C space. For details on how this works 489and what methods you can call on the C<ffi_platypus_constant_t> instance, 490see L<FFI::Platypus::Constant>. 491 492=item C<ffi_pl_bundle_fini> 493 494 void ffi_pl_bundle_fini(const char *package); 495 496Called when the dynamic library is unloaded. C<package> is the Perl 497package that called C<bundle> from Perl space when the library was 498loaded. B<CAVEAT>: if you attach any functions then this will 499never be called, because attaching functions locks the Platypus 500instance into memory along with the libraries which it is using. 501 502=back 503 504Here is an example that passes the version and a callback back into Perl 505space that emulates the Perl 5.10 C<say> feature. 506 507C<ffi/init.c>: 508 509 #include <ffi_platypus_bundle.h> 510 511 char buffer[512]; 512 const char *version; 513 void (*say)(const char *); 514 515 void 516 ffi_pl_bundle_init(const char *package, int argc, void *argv[]) 517 { 518 version = argv[0]; 519 say = argv[1]; 520 521 say("in init!"); 522 523 snprintf(buffer, 512, "package = %s, version = %s", package, version); 524 say(buffer); 525 526 snprintf(buffer, 512, "args = %d", argc); 527 say(buffer); 528 } 529 530 void 531 ffi_pl_bundle_fini(const char *package) 532 { 533 say("in fini!"); 534 } 535 536C<lib/Init.pm>: 537 538 package Init; 539 540 use strict; 541 use warnings; 542 use FFI::Platypus 1.00; 543 544 our $VERSION = '1.00'; 545 546 { 547 my $ffi = FFI::Platypus->new( api => 1 ); 548 549 my $say = $ffi->closure(sub { 550 my $string = shift; 551 print "$string\n"; 552 }); 553 554 $ffi->bundle([ 555 $ffi->cast( 'string' => 'opaque', $VERSION ), 556 $ffi->cast( '(string)->void' => 'opaque', $say ), 557 ]); 558 559 undef $ffi; 560 undef $say; 561 } 562 563 1; 564 565The deinitialization order for the C<$say> callback and the C<$ffi> 566instance is essential here, so we do it manually with C<undef>: 567 568 undef $ffi; 569 undef $say; 570 571First we deallocate C<$ffi> which calls C<ffi_pl_bundle_fini>, 572which calls C<$say>, so we want to make sure the latter is still 573allocated. Once C<ffi_pl_bundle_fini> is done, we can safely 574deallocate C<$say>. 575 576If C<ffi_pl_bundle_fini> didn't call back into Perl space like 577this then we don't have to be as careful about deallocating 578things in Perl space. 579 580=head2 Compiler or linker flags example 581 582There are times when you will want to specify your own compiler and 583linker flags for the C code that you are bundling. The C<TL;DR> is that 584you can put a C<.fbx> file in your C<ffi> directory. This is a Perl 585script that returns a hash reference that is passed into the 586L<FFI::Build> constructor. This allows you to set a number of options, 587including compiler and linker flags. A more detailed example follows: 588 589You may want or need to set compiler and linker flags for your bundled 590C code. For example, say we have a header file, but instead of 591putting it in the C<ffi> directory we want to put it in a separate 592directory called C<include>. 593 594C<include/answer.h>: 595 596 #ifndef ANSWER_H 597 #define ANSWER_H 598 599 int answer(void); 600 601 #endif 602 603C<ffi/answer.c>: 604 605 #include <answer.h> 606 607 int 608 answer(void) 609 { 610 /* the answer to life the universe and everything */ 611 return 42; 612 } 613 614C<lib/Answer.pm>: 615 616 package Answer; 617 618 use strict; 619 use warnings; 620 use FFI::Platypus 1.00; 621 use Exporter qw( import ); 622 623 our @EXPORT = qw( answer ); 624 625 my $ffi = FFI::Platypus->new( api => 1 ); 626 $ffi->bundle; 627 $ffi->attach( answer => [] => 'int' ); 628 629 1; 630 631If you try to use this module just as-is you will get an error, about 632not being able to find the header file. Probably something like this: 633 634 ffi/answer.c:1:10: fatal error: 'answer.h' file not found 635 636So we put a C<answer.fbx> file in the C<ffi> directory. (In case you 637are wondering FBX stands for "Ffi Build and file eXtensions should 638whenever possible be three characters long"). The name of the file 639can be anything so long as it ends in C<.fbx>, we just choose C<answer> 640here because that is the name of the project. 641 642C<ffi/answer.fbx>: 643 644 our $DIR; 645 646 return { 647 cflags => "-I/include", 648 source => "$DIR/*.c", 649 } 650 651The C<$DIR> variable is provided by the builder code. It is the root 652of the distribution, and is helpful if you need a fully qualified path. 653In this case you could have also used C<ffi/*.c>. 654 655The script returns a hash reference which is passed into the L<FFI::Build> 656constructor, so you can use any of the options supported by that 657class. Now we should be able to use our bundled module: 658 659 % perl -Ilib -MAnswer=answer -E 'say answer' 660 42 661 662=head2 Using bundled code with Alien. 663 664A useful technique is to use Platypus with L<Alien> technology. The 665L<Alien> namespace is reserved for providing external non-Perl dependencies 666for CPAN modules. The nominal L<Alien> module when installed looks 667for the library locally, and if it can't be found it fetches it from 668the internet, builds it, and installs it in a private directory so that 669it can be used by other CPAN modules. For L<Aliens> that provide 670shared libraries, and that have simple interfaces that do not require 671additional C code you can easily just pass the shared libraries 672to Platypus directly. For modules that require some bundled C code 673and an L<Alien> you have to link the L<Alien> library with your bundled 674code. If the L<Alien> uses the L<Alien::Base> interface then all you have 675to do is give the name of the L<Alien> to L<FFI::Build>. 676 677For example, the C<bzip2> library provides an interface that requires 678the caller to allocate a C C<struct> and then pass it to its various 679functions. The C<struct> is actually pretty simple and you could use 680L<FFI::C> or L<FFI::Platypus::Record>, but here is an example of how you 681would connect bundled C code with an L<Alien>. 682 683C<ffi/compress.c>: 684 685 #include <bzlib.h> 686 #include <stdlib.h> 687 688 int 689 bzip2__new(bz_stream **stream, int blockSize100k, int verbosity, int workFactor ) 690 { 691 *stream = malloc(sizeof(bz_stream)); 692 (*stream)->bzalloc = NULL; 693 (*stream)->bzfree = NULL; 694 (*stream)->opaque = NULL; 695 696 return BZ2_bzCompressInit(*stream, blockSize100k, verbosity, workFactor ); 697 } 698 699C<lib/Bzip2.pm>: 700 701 package Bzip2; 702 703 use strict; 704 use warnings; 705 use FFI::Platypus 1.00; 706 use FFI::Platypus::Memory qw( free ); 707 708 my $ffi = FFI::Platypus->new( api => 1 ); 709 $ffi->bundle; 710 711 $ffi->mangler(sub { 712 my $name = shift; 713 $name =~ s/^/bzip2__/ unless $name =~ /^BZ2_/; 714 $name; 715 }); 716 717 =head2 new 718 719 my $bzip2 = Bzip2->new($block_size_100k, $verbosity, $work_flow); 720 721 =cut 722 723 $ffi->attach( new => ['opaque*', 'int', 'int', 'int'] => 'int' => sub { 724 my $xsub = shift; 725 my $class = shift; 726 my $ptr; 727 my $ret = $xsub->(\$ptr, @_); 728 return bless \$ptr, $class; 729 }); 730 731 $ffi->attach( [ BZ2_bzCompressEnd => 'DESTROY' ] => ['opaque'] => 'int' => sub { 732 my $xsub = shift; 733 my $self = shift; 734 my $ret = $xsub->($$self); 735 free $$self; 736 }); 737 738 1; 739 740The C<.fbx> file that goes with this to make it work with L<Alien::Libbz2> 741is now pretty trivial: 742 743C<ffi/bz2.fbx>: 744 745 { 746 alien => ['Alien::Libbz2'], 747 source => ['ffi/*.c'], 748 }; 749 750=head1 AUTHOR 751 752Author: Graham Ollis E<lt>plicease@cpan.orgE<gt> 753 754Contributors: 755 756Bakkiaraj Murugesan (bakkiaraj) 757 758Dylan Cali (calid) 759 760pipcet 761 762Zaki Mughal (zmughal) 763 764Fitz Elliott (felliott) 765 766Vickenty Fesunov (vyf) 767 768Gregor Herrmann (gregoa) 769 770Shlomi Fish (shlomif) 771 772Damyan Ivanov 773 774Ilya Pavlov (Ilya33) 775 776Petr Písař (ppisar) 777 778Mohammad S Anwar (MANWAR) 779 780Håkon Hægland (hakonhagland, HAKONH) 781 782Meredith (merrilymeredith, MHOWARD) 783 784Diab Jerius (DJERIUS) 785 786Eric Brine (IKEGAMI) 787 788szTheory 789 790José Joaquín Atria (JJATRIA) 791 792Pete Houston (openstrike, HOUSTON) 793 794=head1 COPYRIGHT AND LICENSE 795 796This software is copyright (c) 2015,2016,2017,2018,2019,2020 by Graham Ollis. 797 798This is free software; you can redistribute it and/or modify it under 799the same terms as the Perl 5 programming language system itself. 800 801=cut 802