From: Ilya Zakharevich Date: Mon, 21 Apr 2003 22:44:37 +0000 (-0700) Subject: XSLoader revisted X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=d7f44de216e72597099819403690905e87b0a15f;p=p5sagit%2Fp5-mst-13.2.git XSLoader revisted Message-ID: <20030422054437.GA8297@math.berkeley.edu> (the XSLoader doc hunk; the h2xs looks like a behavioural change) p4raw-id: //depot/perl@20634 --- diff --git a/ext/DynaLoader/XSLoader_pm.PL b/ext/DynaLoader/XSLoader_pm.PL index 9e6d42b..9f3aaed 100644 --- a/ext/DynaLoader/XSLoader_pm.PL +++ b/ext/DynaLoader/XSLoader_pm.PL @@ -160,6 +160,164 @@ For more complicated interface see L. Many (most) features of DynaLoader are not implemented in XSLoader, like for example the dl_load_flags is not honored by XSLoader. +=head2 Migration from C + +A typical module using L starts like this: + + package YourPackage; + require DynaLoader; + + our @ISA = qw( OnePackage OtherPackage DynaLoader ); + our $VERSION = '0.01'; + bootstrap YourPackage $VERSION; + +Change this to + + package YourPackage; + use XSLoader; + + our @ISA = qw( OnePackage OtherPackage ); + our $VERSION = '0.01'; + XSLoader::load 'YourPackage', $VERSION; + +In other words: replace C by C, remove +C from @ISA, change C by C. Do not +forget to quote the name of your package on the C line, +and add comma (C<,>) before the arguments ($VERSION above). + +Of course, if @ISA contained only C, there is no need to have the +@ISA assignment at all; moreover, if instead of C one uses +backward-compatible + + use vars qw($VERSION @ISA); + +one can remove this reference to @ISA together with the @ISA assignment + +If no $VERSION was specified on the C line, the last line becomes + + XSLoader::load 'YourPackage'; + +=head2 Backward compatible boilerplate + +If you want to have your cake and eat it too, you need a more complicated +boilerplate. + + package YourPackage; + use vars qw($VERSION @ISA); + + @ISA = qw( OnePackage OtherPackage ); + $VERSION = '0.01'; + eval { + require XSLoader; + XSLoader::load('YourPackage', $VERSION); + 1; + } or do { + require DynaLoader; + push @ISA, 'DynaLoader'; + bootstrap YourPackage $VERSION; + }; + +The parentheses about XSLoader::load() arguments are needed since we replaced +C by C, so the compiler does not know that a function +XSLoader::load() is present. + +This boilerplate uses the low-overhead C if present; if used with +an antic Perl which has no C, it falls back to using C. + +=head1 Order of initialization: early load() + +I section in your XS file (see L). +What is described here is equally applicable to L +interface.> + +A sufficiently complicated module using XS would have both Perl code (defined +in F) and XS code (defined in F). If this +Perl code makes calls into this XS code, and/or this XS code makes calls to +the Perl code, one should be careful with the order of initialization. + +The call to XSLoader::load() (or bootstrap()) has three side effects: + +=over + +=item * + +if $VERSION was specified, a sanity check is done to insure that the versions +of the F<.pm> and the (compiled) F<.xs> parts are compatible; + +=item * + +The XSUBs are made accessible from Perl; + +=item * + +If the C section was present in F<.xs> file, the code there is called. + +=back + +Consequently, if the code in F<.pm> file makes calls to these XSUBs, it is +convenient to have XSUBs installed before the Perl code is defined; for +example, this makes prototypes for XSUBs visible to this Perl code. +Alternatively, if the C section makes calls to Perl functions (or +uses Perl variables) defined in F<.pm> file, they must be defined prior to +the call to XSLoader::load() (or bootstrap()). + +The first situation being much more frequent, it makes sense to rewrite the +boilerplate as + + package YourPackage; + use XSLoader; + use vars qw($VERSION @ISA); + + BEGIN { + @ISA = qw( OnePackage OtherPackage ); + $VERSION = '0.01'; + + # Put Perl code used in the BOOT: section here + + XSLoader::load 'YourPackage', $VERSION; + } + + # Put Perl code making calls into XSUBs here + +=head2 The most hairy case + +If the interdependence of your C section and Perl code is +more complicated than this (e.g., the C section makes calls to Perl +functions which make calls to XSUBs with prototypes), get rid of the C +section altogether. Replace it with a function onBOOT(), and call it like +this: + + package YourPackage; + use XSLoader; + use vars qw($VERSION @ISA); + + BEGIN { + @ISA = qw( OnePackage OtherPackage ); + $VERSION = '0.01'; + XSLoader::load 'YourPackage', $VERSION; + } + + # Put Perl code used in onBOOT() function here; calls to XSUBs are + # prototype-checked. + + onBOOT; + + # Put Perl initialization code assuming that XS is initialized here + +=head1 LIMITATIONS + +To reduce the overhead as much as possible, only one possible location +is checked to find the extension DLL (this location is where C +would put the DLL). If not found, the search for the DLL is transparently +delegated to C, which looks for the DLL along the @INC list. + +In particular, this is applicable to the structure of @INC used for testing +not-yet-installed extensions. This means that the overhead of running +uninstalled extension may be much more than running the same extension after +C. + =head1 AUTHOR Ilya Zakharevich: extraction from DynaLoader.