XSLoader revisted
Ilya Zakharevich [Mon, 21 Apr 2003 22:44:37 +0000 (15:44 -0700)]
Message-ID: <20030422054437.GA8297@math.berkeley.edu>

(the XSLoader doc hunk; the h2xs looks like a behavioural change)

p4raw-id: //depot/perl@20634

ext/DynaLoader/XSLoader_pm.PL

index 9e6d42b..9f3aaed 100644 (file)
@@ -160,6 +160,164 @@ For more complicated interface see L<DynaLoader>.  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<DynaLoader>
+
+A typical module using L<DynaLoader|DynaLoader> 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<require DynaLoader> by C<use XSLoader>, remove
+C<DynaLoader> from @ISA, change C<bootstrap> by C<XSLoader::load>.  Do not
+forget to quote the name of your package on the C<XSLoader::load> line,
+and add comma (C<,>) before the arguments ($VERSION above).
+
+Of course, if @ISA contained only C<DynaLoader>, there is no need to have the
+@ISA assignment at all; moreover, if instead of C<our> 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<bootstrap> 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<use XSLoader> by C<require>, so the compiler does not know that a function
+XSLoader::load() is present.
+
+This boilerplate uses the low-overhead C<XSLoader> if present; if used with
+an antic Perl which has no C<XSLoader>, it falls back to using C<DynaLoader>.
+
+=head1 Order of initialization: early load()
+
+I<Skip this section if the XSUB functions are supposed to be called from other
+modules only; read it only if you call your XSUBs from the code in your module,
+or have a C<BOOT:> section in your XS file (see L<perlxs/"The BOOT: Keyword">).
+What is described here is equally applicable to L<DynaLoader|DynaLoader>
+interface.>
+
+A sufficiently complicated module using XS would have both Perl code (defined
+in F<YourPackage.pm>) and XS code (defined in F<YourPackage.xs>).  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<BOOT:> 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<BOOT:> 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<BOOT:> section and Perl code is
+more complicated than this (e.g., the C<BOOT:> section makes calls to Perl
+functions which make calls to XSUBs with prototypes), get rid of the C<BOOT:>
+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<make install>
+would put the DLL).  If not found, the search for the DLL is transparently
+delegated to C<DynaLoader>, 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<make install>.
+
 =head1 AUTHOR
 
 Ilya Zakharevich: extraction from DynaLoader.