1*0Sstevel@tonic-gateuse Config; 2*0Sstevel@tonic-gate 3*0Sstevel@tonic-gatesub to_string { 4*0Sstevel@tonic-gate my ($value) = @_; 5*0Sstevel@tonic-gate $value =~ s/\\/\\\\/g; 6*0Sstevel@tonic-gate $value =~ s/'/\\'/g; 7*0Sstevel@tonic-gate return "'$value'"; 8*0Sstevel@tonic-gate} 9*0Sstevel@tonic-gate 10*0Sstevel@tonic-gateunlink "XSLoader.pm" if -f "XSLoader.pm"; 11*0Sstevel@tonic-gateopen OUT, ">XSLoader.pm" or die $!; 12*0Sstevel@tonic-gateprint OUT <<'EOT'; 13*0Sstevel@tonic-gate# Generated from XSLoader.pm.PL (resolved %Config::Config value) 14*0Sstevel@tonic-gate 15*0Sstevel@tonic-gatepackage XSLoader; 16*0Sstevel@tonic-gate 17*0Sstevel@tonic-gate$VERSION = "0.02"; 18*0Sstevel@tonic-gate 19*0Sstevel@tonic-gate# enable debug/trace messages from DynaLoader perl code 20*0Sstevel@tonic-gate# $dl_debug = $ENV{PERL_DL_DEBUG} || 0 unless defined $dl_debug; 21*0Sstevel@tonic-gate 22*0Sstevel@tonic-gateEOT 23*0Sstevel@tonic-gate 24*0Sstevel@tonic-gateprint OUT ' my $dl_dlext = ', to_string($Config::Config{'dlext'}), ";\n" ; 25*0Sstevel@tonic-gate 26*0Sstevel@tonic-gateprint OUT <<'EOT'; 27*0Sstevel@tonic-gate 28*0Sstevel@tonic-gatepackage DynaLoader; 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gate# No prizes for guessing why we don't say 'bootstrap DynaLoader;' here. 31*0Sstevel@tonic-gate# NOTE: All dl_*.xs (including dl_none.xs) define a dl_error() XSUB 32*0Sstevel@tonic-gateboot_DynaLoader('DynaLoader') if defined(&boot_DynaLoader) && 33*0Sstevel@tonic-gate !defined(&dl_error); 34*0Sstevel@tonic-gatepackage XSLoader; 35*0Sstevel@tonic-gate 36*0Sstevel@tonic-gatesub load { 37*0Sstevel@tonic-gate package DynaLoader; 38*0Sstevel@tonic-gate 39*0Sstevel@tonic-gate die q{XSLoader::load('Your::Module', $Your::Module::VERSION)} unless @_; 40*0Sstevel@tonic-gate 41*0Sstevel@tonic-gate my($module) = $_[0]; 42*0Sstevel@tonic-gate 43*0Sstevel@tonic-gate # work with static linking too 44*0Sstevel@tonic-gate my $b = "$module\::bootstrap"; 45*0Sstevel@tonic-gate goto &$b if defined &$b; 46*0Sstevel@tonic-gate 47*0Sstevel@tonic-gate goto retry unless $module and defined &dl_load_file; 48*0Sstevel@tonic-gate 49*0Sstevel@tonic-gate my @modparts = split(/::/,$module); 50*0Sstevel@tonic-gate my $modfname = $modparts[-1]; 51*0Sstevel@tonic-gate 52*0Sstevel@tonic-gateEOT 53*0Sstevel@tonic-gate 54*0Sstevel@tonic-gateprint OUT <<'EOT' if defined &DynaLoader::mod2fname; 55*0Sstevel@tonic-gate # Some systems have restrictions on files names for DLL's etc. 56*0Sstevel@tonic-gate # mod2fname returns appropriate file base name (typically truncated) 57*0Sstevel@tonic-gate # It may also edit @modparts if required. 58*0Sstevel@tonic-gate $modfname = &mod2fname(\@modparts) if defined &mod2fname; 59*0Sstevel@tonic-gate 60*0Sstevel@tonic-gateEOT 61*0Sstevel@tonic-gate 62*0Sstevel@tonic-gateprint OUT <<'EOT'; 63*0Sstevel@tonic-gate my $modpname = join('/',@modparts); 64*0Sstevel@tonic-gate my $modlibname = (caller())[1]; 65*0Sstevel@tonic-gate my $c = @modparts; 66*0Sstevel@tonic-gate $modlibname =~ s,[\\/][^\\/]+$,, while $c--; # Q&D basename 67*0Sstevel@tonic-gate my $file = "$modlibname/auto/$modpname/$modfname.$dl_dlext"; 68*0Sstevel@tonic-gate 69*0Sstevel@tonic-gate# print STDERR "XSLoader::load for $module ($file)\n" if $dl_debug; 70*0Sstevel@tonic-gate 71*0Sstevel@tonic-gate my $bs = $file; 72*0Sstevel@tonic-gate $bs =~ s/(\.\w+)?(;\d*)?$/\.bs/; # look for .bs 'beside' the library 73*0Sstevel@tonic-gate 74*0Sstevel@tonic-gate goto retry if not -f $file or -s $bs; 75*0Sstevel@tonic-gate 76*0Sstevel@tonic-gate my $bootname = "boot_$module"; 77*0Sstevel@tonic-gate $bootname =~ s/\W/_/g; 78*0Sstevel@tonic-gate @dl_require_symbols = ($bootname); 79*0Sstevel@tonic-gate 80*0Sstevel@tonic-gate my $boot_symbol_ref; 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gate if ($^O eq 'darwin') { 83*0Sstevel@tonic-gate if ($boot_symbol_ref = dl_find_symbol(0, $bootname)) { 84*0Sstevel@tonic-gate goto boot; #extension library has already been loaded, e.g. darwin 85*0Sstevel@tonic-gate } 86*0Sstevel@tonic-gate } 87*0Sstevel@tonic-gate 88*0Sstevel@tonic-gate # Many dynamic extension loading problems will appear to come from 89*0Sstevel@tonic-gate # this section of code: XYZ failed at line 123 of DynaLoader.pm. 90*0Sstevel@tonic-gate # Often these errors are actually occurring in the initialisation 91*0Sstevel@tonic-gate # C code of the extension XS file. Perl reports the error as being 92*0Sstevel@tonic-gate # in this perl code simply because this was the last perl code 93*0Sstevel@tonic-gate # it executed. 94*0Sstevel@tonic-gate 95*0Sstevel@tonic-gate my $libref = dl_load_file($file, 0) or do { 96*0Sstevel@tonic-gate require Carp; 97*0Sstevel@tonic-gate Carp::croak("Can't load '$file' for module $module: " . dl_error()); 98*0Sstevel@tonic-gate }; 99*0Sstevel@tonic-gate push(@dl_librefs,$libref); # record loaded object 100*0Sstevel@tonic-gate 101*0Sstevel@tonic-gate my @unresolved = dl_undef_symbols(); 102*0Sstevel@tonic-gate if (@unresolved) { 103*0Sstevel@tonic-gate require Carp; 104*0Sstevel@tonic-gate Carp::carp("Undefined symbols present after loading $file: @unresolved\n"); 105*0Sstevel@tonic-gate } 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate $boot_symbol_ref = dl_find_symbol($libref, $bootname) or do { 108*0Sstevel@tonic-gate require Carp; 109*0Sstevel@tonic-gate Carp::croak("Can't find '$bootname' symbol in $file\n"); 110*0Sstevel@tonic-gate }; 111*0Sstevel@tonic-gate 112*0Sstevel@tonic-gate push(@dl_modules, $module); # record loaded module 113*0Sstevel@tonic-gate 114*0Sstevel@tonic-gate boot: 115*0Sstevel@tonic-gate my $xs = dl_install_xsub("${module}::bootstrap", $boot_symbol_ref, $file); 116*0Sstevel@tonic-gate 117*0Sstevel@tonic-gate # See comment block above 118*0Sstevel@tonic-gate return &$xs(@_); 119*0Sstevel@tonic-gate 120*0Sstevel@tonic-gate retry: 121*0Sstevel@tonic-gate require DynaLoader; 122*0Sstevel@tonic-gate goto &DynaLoader::bootstrap_inherit; 123*0Sstevel@tonic-gate} 124*0Sstevel@tonic-gate 125*0Sstevel@tonic-gate1; 126*0Sstevel@tonic-gate 127*0Sstevel@tonic-gate__END__ 128*0Sstevel@tonic-gate 129*0Sstevel@tonic-gate=head1 NAME 130*0Sstevel@tonic-gate 131*0Sstevel@tonic-gateXSLoader - Dynamically load C libraries into Perl code 132*0Sstevel@tonic-gate 133*0Sstevel@tonic-gate=head1 SYNOPSIS 134*0Sstevel@tonic-gate 135*0Sstevel@tonic-gate package YourPackage; 136*0Sstevel@tonic-gate use XSLoader; 137*0Sstevel@tonic-gate 138*0Sstevel@tonic-gate XSLoader::load 'YourPackage', $YourPackage::VERSION; 139*0Sstevel@tonic-gate 140*0Sstevel@tonic-gate=head1 DESCRIPTION 141*0Sstevel@tonic-gate 142*0Sstevel@tonic-gateThis module defines a standard I<simplified> interface to the dynamic 143*0Sstevel@tonic-gatelinking mechanisms available on many platforms. Its primary purpose is 144*0Sstevel@tonic-gateto implement cheap automatic dynamic loading of Perl modules. 145*0Sstevel@tonic-gate 146*0Sstevel@tonic-gateFor more complicated interface see L<DynaLoader>. Many (most) 147*0Sstevel@tonic-gatefeatures of DynaLoader are not implemented in XSLoader, like for 148*0Sstevel@tonic-gateexample the dl_load_flags is not honored by XSLoader. 149*0Sstevel@tonic-gate 150*0Sstevel@tonic-gate=head2 Migration from C<DynaLoader> 151*0Sstevel@tonic-gate 152*0Sstevel@tonic-gateA typical module using L<DynaLoader|DynaLoader> starts like this: 153*0Sstevel@tonic-gate 154*0Sstevel@tonic-gate package YourPackage; 155*0Sstevel@tonic-gate require DynaLoader; 156*0Sstevel@tonic-gate 157*0Sstevel@tonic-gate our @ISA = qw( OnePackage OtherPackage DynaLoader ); 158*0Sstevel@tonic-gate our $VERSION = '0.01'; 159*0Sstevel@tonic-gate bootstrap YourPackage $VERSION; 160*0Sstevel@tonic-gate 161*0Sstevel@tonic-gateChange this to 162*0Sstevel@tonic-gate 163*0Sstevel@tonic-gate package YourPackage; 164*0Sstevel@tonic-gate use XSLoader; 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate our @ISA = qw( OnePackage OtherPackage ); 167*0Sstevel@tonic-gate our $VERSION = '0.01'; 168*0Sstevel@tonic-gate XSLoader::load 'YourPackage', $VERSION; 169*0Sstevel@tonic-gate 170*0Sstevel@tonic-gateIn other words: replace C<require DynaLoader> by C<use XSLoader>, remove 171*0Sstevel@tonic-gateC<DynaLoader> from @ISA, change C<bootstrap> by C<XSLoader::load>. Do not 172*0Sstevel@tonic-gateforget to quote the name of your package on the C<XSLoader::load> line, 173*0Sstevel@tonic-gateand add comma (C<,>) before the arguments ($VERSION above). 174*0Sstevel@tonic-gate 175*0Sstevel@tonic-gateOf course, if @ISA contained only C<DynaLoader>, there is no need to have the 176*0Sstevel@tonic-gate@ISA assignment at all; moreover, if instead of C<our> one uses 177*0Sstevel@tonic-gatebackward-compatible 178*0Sstevel@tonic-gate 179*0Sstevel@tonic-gate use vars qw($VERSION @ISA); 180*0Sstevel@tonic-gate 181*0Sstevel@tonic-gateone can remove this reference to @ISA together with the @ISA assignment 182*0Sstevel@tonic-gate 183*0Sstevel@tonic-gateIf no $VERSION was specified on the C<bootstrap> line, the last line becomes 184*0Sstevel@tonic-gate 185*0Sstevel@tonic-gate XSLoader::load 'YourPackage'; 186*0Sstevel@tonic-gate 187*0Sstevel@tonic-gate=head2 Backward compatible boilerplate 188*0Sstevel@tonic-gate 189*0Sstevel@tonic-gateIf you want to have your cake and eat it too, you need a more complicated 190*0Sstevel@tonic-gateboilerplate. 191*0Sstevel@tonic-gate 192*0Sstevel@tonic-gate package YourPackage; 193*0Sstevel@tonic-gate use vars qw($VERSION @ISA); 194*0Sstevel@tonic-gate 195*0Sstevel@tonic-gate @ISA = qw( OnePackage OtherPackage ); 196*0Sstevel@tonic-gate $VERSION = '0.01'; 197*0Sstevel@tonic-gate eval { 198*0Sstevel@tonic-gate require XSLoader; 199*0Sstevel@tonic-gate XSLoader::load('YourPackage', $VERSION); 200*0Sstevel@tonic-gate 1; 201*0Sstevel@tonic-gate } or do { 202*0Sstevel@tonic-gate require DynaLoader; 203*0Sstevel@tonic-gate push @ISA, 'DynaLoader'; 204*0Sstevel@tonic-gate bootstrap YourPackage $VERSION; 205*0Sstevel@tonic-gate }; 206*0Sstevel@tonic-gate 207*0Sstevel@tonic-gateThe parentheses about XSLoader::load() arguments are needed since we replaced 208*0Sstevel@tonic-gateC<use XSLoader> by C<require>, so the compiler does not know that a function 209*0Sstevel@tonic-gateXSLoader::load() is present. 210*0Sstevel@tonic-gate 211*0Sstevel@tonic-gateThis boilerplate uses the low-overhead C<XSLoader> if present; if used with 212*0Sstevel@tonic-gatean antic Perl which has no C<XSLoader>, it falls back to using C<DynaLoader>. 213*0Sstevel@tonic-gate 214*0Sstevel@tonic-gate=head1 Order of initialization: early load() 215*0Sstevel@tonic-gate 216*0Sstevel@tonic-gateI<Skip this section if the XSUB functions are supposed to be called from other 217*0Sstevel@tonic-gatemodules only; read it only if you call your XSUBs from the code in your module, 218*0Sstevel@tonic-gateor have a C<BOOT:> section in your XS file (see L<perlxs/"The BOOT: Keyword">). 219*0Sstevel@tonic-gateWhat is described here is equally applicable to L<DynaLoader|DynaLoader> 220*0Sstevel@tonic-gateinterface.> 221*0Sstevel@tonic-gate 222*0Sstevel@tonic-gateA sufficiently complicated module using XS would have both Perl code (defined 223*0Sstevel@tonic-gatein F<YourPackage.pm>) and XS code (defined in F<YourPackage.xs>). If this 224*0Sstevel@tonic-gatePerl code makes calls into this XS code, and/or this XS code makes calls to 225*0Sstevel@tonic-gatethe Perl code, one should be careful with the order of initialization. 226*0Sstevel@tonic-gate 227*0Sstevel@tonic-gateThe call to XSLoader::load() (or bootstrap()) has three side effects: 228*0Sstevel@tonic-gate 229*0Sstevel@tonic-gate=over 230*0Sstevel@tonic-gate 231*0Sstevel@tonic-gate=item * 232*0Sstevel@tonic-gate 233*0Sstevel@tonic-gateif $VERSION was specified, a sanity check is done to insure that the versions 234*0Sstevel@tonic-gateof the F<.pm> and the (compiled) F<.xs> parts are compatible; 235*0Sstevel@tonic-gate 236*0Sstevel@tonic-gate=item * 237*0Sstevel@tonic-gate 238*0Sstevel@tonic-gateThe XSUBs are made accessible from Perl; 239*0Sstevel@tonic-gate 240*0Sstevel@tonic-gate=item * 241*0Sstevel@tonic-gate 242*0Sstevel@tonic-gateIf the C<BOOT:> section was present in F<.xs> file, the code there is called. 243*0Sstevel@tonic-gate 244*0Sstevel@tonic-gate=back 245*0Sstevel@tonic-gate 246*0Sstevel@tonic-gateConsequently, if the code in F<.pm> file makes calls to these XSUBs, it is 247*0Sstevel@tonic-gateconvenient to have XSUBs installed before the Perl code is defined; for 248*0Sstevel@tonic-gateexample, this makes prototypes for XSUBs visible to this Perl code. 249*0Sstevel@tonic-gateAlternatively, if the C<BOOT:> section makes calls to Perl functions (or 250*0Sstevel@tonic-gateuses Perl variables) defined in F<.pm> file, they must be defined prior to 251*0Sstevel@tonic-gatethe call to XSLoader::load() (or bootstrap()). 252*0Sstevel@tonic-gate 253*0Sstevel@tonic-gateThe first situation being much more frequent, it makes sense to rewrite the 254*0Sstevel@tonic-gateboilerplate as 255*0Sstevel@tonic-gate 256*0Sstevel@tonic-gate package YourPackage; 257*0Sstevel@tonic-gate use XSLoader; 258*0Sstevel@tonic-gate use vars qw($VERSION @ISA); 259*0Sstevel@tonic-gate 260*0Sstevel@tonic-gate BEGIN { 261*0Sstevel@tonic-gate @ISA = qw( OnePackage OtherPackage ); 262*0Sstevel@tonic-gate $VERSION = '0.01'; 263*0Sstevel@tonic-gate 264*0Sstevel@tonic-gate # Put Perl code used in the BOOT: section here 265*0Sstevel@tonic-gate 266*0Sstevel@tonic-gate XSLoader::load 'YourPackage', $VERSION; 267*0Sstevel@tonic-gate } 268*0Sstevel@tonic-gate 269*0Sstevel@tonic-gate # Put Perl code making calls into XSUBs here 270*0Sstevel@tonic-gate 271*0Sstevel@tonic-gate=head2 The most hairy case 272*0Sstevel@tonic-gate 273*0Sstevel@tonic-gateIf the interdependence of your C<BOOT:> section and Perl code is 274*0Sstevel@tonic-gatemore complicated than this (e.g., the C<BOOT:> section makes calls to Perl 275*0Sstevel@tonic-gatefunctions which make calls to XSUBs with prototypes), get rid of the C<BOOT:> 276*0Sstevel@tonic-gatesection altogether. Replace it with a function onBOOT(), and call it like 277*0Sstevel@tonic-gatethis: 278*0Sstevel@tonic-gate 279*0Sstevel@tonic-gate package YourPackage; 280*0Sstevel@tonic-gate use XSLoader; 281*0Sstevel@tonic-gate use vars qw($VERSION @ISA); 282*0Sstevel@tonic-gate 283*0Sstevel@tonic-gate BEGIN { 284*0Sstevel@tonic-gate @ISA = qw( OnePackage OtherPackage ); 285*0Sstevel@tonic-gate $VERSION = '0.01'; 286*0Sstevel@tonic-gate XSLoader::load 'YourPackage', $VERSION; 287*0Sstevel@tonic-gate } 288*0Sstevel@tonic-gate 289*0Sstevel@tonic-gate # Put Perl code used in onBOOT() function here; calls to XSUBs are 290*0Sstevel@tonic-gate # prototype-checked. 291*0Sstevel@tonic-gate 292*0Sstevel@tonic-gate onBOOT; 293*0Sstevel@tonic-gate 294*0Sstevel@tonic-gate # Put Perl initialization code assuming that XS is initialized here 295*0Sstevel@tonic-gate 296*0Sstevel@tonic-gate=head1 LIMITATIONS 297*0Sstevel@tonic-gate 298*0Sstevel@tonic-gateTo reduce the overhead as much as possible, only one possible location 299*0Sstevel@tonic-gateis checked to find the extension DLL (this location is where C<make install> 300*0Sstevel@tonic-gatewould put the DLL). If not found, the search for the DLL is transparently 301*0Sstevel@tonic-gatedelegated to C<DynaLoader>, which looks for the DLL along the @INC list. 302*0Sstevel@tonic-gate 303*0Sstevel@tonic-gateIn particular, this is applicable to the structure of @INC used for testing 304*0Sstevel@tonic-gatenot-yet-installed extensions. This means that the overhead of running 305*0Sstevel@tonic-gateuninstalled extension may be much more than running the same extension after 306*0Sstevel@tonic-gateC<make install>. 307*0Sstevel@tonic-gate 308*0Sstevel@tonic-gate=head1 AUTHOR 309*0Sstevel@tonic-gate 310*0Sstevel@tonic-gateIlya Zakharevich: extraction from DynaLoader. 311*0Sstevel@tonic-gate 312*0Sstevel@tonic-gate=cut 313*0Sstevel@tonic-gateEOT 314*0Sstevel@tonic-gate 315*0Sstevel@tonic-gateclose OUT or die $!; 316*0Sstevel@tonic-gate 317