mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-19 10:53:58 +00:00
308 lines
12 KiB
Perl
308 lines
12 KiB
Perl
package SelfLoader;
|
|
# use Carp;
|
|
require Exporter;
|
|
@ISA = qw(Exporter);
|
|
@EXPORT = qw(AUTOLOAD);
|
|
$VERSION = "1.0902";
|
|
sub Version {$VERSION}
|
|
$DEBUG = 0;
|
|
|
|
my %Cache; # private cache for all SelfLoader's client packages
|
|
|
|
# allow checking for valid ': attrlist' attachments
|
|
my $nested;
|
|
$nested = qr{ \( (?: (?> [^()]+ ) | (??{ $nested }) )* \) }x;
|
|
my $one_attr = qr{ (?> (?! \d) \w+ (?:$nested)? ) (?:\s*\:\s*|\s+(?!\:)) }x;
|
|
my $attr_list = qr{ \s* : \s* (?: $one_attr )* }x;
|
|
|
|
sub croak { require Carp; goto &Carp::croak }
|
|
|
|
AUTOLOAD {
|
|
print STDERR "SelfLoader::AUTOLOAD for $AUTOLOAD\n" if $DEBUG;
|
|
my $SL_code = $Cache{$AUTOLOAD};
|
|
my $save = $@; # evals in both AUTOLOAD and _load_stubs can corrupt $@
|
|
unless ($SL_code) {
|
|
# Maybe this pack had stubs before __DATA__, and never initialized.
|
|
# Or, this maybe an automatic DESTROY method call when none exists.
|
|
$AUTOLOAD =~ m/^(.*)::/;
|
|
SelfLoader->_load_stubs($1) unless exists $Cache{"${1}::<DATA"};
|
|
$SL_code = $Cache{$AUTOLOAD};
|
|
$SL_code = "sub $AUTOLOAD { }"
|
|
if (!$SL_code and $AUTOLOAD =~ m/::DESTROY$/);
|
|
croak "Undefined subroutine $AUTOLOAD" unless $SL_code;
|
|
}
|
|
print STDERR "SelfLoader::AUTOLOAD eval: $SL_code\n" if $DEBUG;
|
|
|
|
eval $SL_code;
|
|
if ($@) {
|
|
$@ =~ s/ at .*\n//;
|
|
croak $@;
|
|
}
|
|
$@ = $save;
|
|
defined(&$AUTOLOAD) || die "SelfLoader inconsistency error";
|
|
delete $Cache{$AUTOLOAD};
|
|
goto &$AUTOLOAD
|
|
}
|
|
|
|
sub load_stubs { shift->_load_stubs((caller)[0]) }
|
|
|
|
sub _load_stubs {
|
|
my($self, $callpack) = @_;
|
|
my $fh = \*{"${callpack}::DATA"};
|
|
my $currpack = $callpack;
|
|
my($line,$name,@lines, @stubs, $protoype);
|
|
|
|
print STDERR "SelfLoader::load_stubs($callpack)\n" if $DEBUG;
|
|
croak("$callpack doesn't contain an __DATA__ token")
|
|
unless fileno($fh);
|
|
$Cache{"${currpack}::<DATA"} = 1; # indicate package is cached
|
|
|
|
local($/) = "\n";
|
|
while(defined($line = <$fh>) and $line !~ m/^__END__/) {
|
|
if ($line =~ m/^sub\s+([\w:]+)\s*((?:\([\\\$\@\%\&\*\;]*\))?(?:$attr_list)?)/) {
|
|
push(@stubs, $self->_add_to_cache($name, $currpack, \@lines, $protoype));
|
|
$protoype = $2;
|
|
@lines = ($line);
|
|
if (index($1,'::') == -1) { # simple sub name
|
|
$name = "${currpack}::$1";
|
|
} else { # sub name with package
|
|
$name = $1;
|
|
$name =~ m/^(.*)::/;
|
|
if (defined(&{"${1}::AUTOLOAD"})) {
|
|
\&{"${1}::AUTOLOAD"} == \&SelfLoader::AUTOLOAD ||
|
|
die 'SelfLoader Error: attempt to specify Selfloading',
|
|
" sub $name in non-selfloading module $1";
|
|
} else {
|
|
$self->export($1,'AUTOLOAD');
|
|
}
|
|
}
|
|
} elsif ($line =~ m/^package\s+([\w:]+)/) { # A package declared
|
|
push(@stubs, $self->_add_to_cache($name, $currpack, \@lines, $protoype));
|
|
$self->_package_defined($line);
|
|
$name = '';
|
|
@lines = ();
|
|
$currpack = $1;
|
|
$Cache{"${currpack}::<DATA"} = 1; # indicate package is cached
|
|
if (defined(&{"${1}::AUTOLOAD"})) {
|
|
\&{"${1}::AUTOLOAD"} == \&SelfLoader::AUTOLOAD ||
|
|
die 'SelfLoader Error: attempt to specify Selfloading',
|
|
" package $currpack which already has AUTOLOAD";
|
|
} else {
|
|
$self->export($currpack,'AUTOLOAD');
|
|
}
|
|
} else {
|
|
push(@lines,$line);
|
|
}
|
|
}
|
|
close($fh) unless defined($line) && $line =~ /^__END__\s*DATA/; # __END__
|
|
push(@stubs, $self->_add_to_cache($name, $currpack, \@lines, $protoype));
|
|
eval join('', @stubs) if @stubs;
|
|
}
|
|
|
|
|
|
sub _add_to_cache {
|
|
my($self,$fullname,$pack,$lines, $protoype) = @_;
|
|
return () unless $fullname;
|
|
(require Carp), Carp::carp("Redefining sub $fullname")
|
|
if exists $Cache{$fullname};
|
|
$Cache{$fullname} = join('', "package $pack; ",@$lines);
|
|
print STDERR "SelfLoader cached $fullname: $Cache{$fullname}" if $DEBUG;
|
|
# return stub to be eval'd
|
|
defined($protoype) ? "sub $fullname $protoype;" : "sub $fullname;"
|
|
}
|
|
|
|
sub _package_defined {}
|
|
|
|
1;
|
|
__END__
|
|
|
|
=head1 NAME
|
|
|
|
SelfLoader - load functions only on demand
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
package FOOBAR;
|
|
use SelfLoader;
|
|
|
|
... (initializing code)
|
|
|
|
__DATA__
|
|
sub {....
|
|
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
This module tells its users that functions in the FOOBAR package are to be
|
|
autoloaded from after the C<__DATA__> token. See also
|
|
L<perlsub/"Autoloading">.
|
|
|
|
=head2 The __DATA__ token
|
|
|
|
The C<__DATA__> token tells the perl compiler that the perl code
|
|
for compilation is finished. Everything after the C<__DATA__> token
|
|
is available for reading via the filehandle FOOBAR::DATA,
|
|
where FOOBAR is the name of the current package when the C<__DATA__>
|
|
token is reached. This works just the same as C<__END__> does in
|
|
package 'main', but for other modules data after C<__END__> is not
|
|
automatically retrievable, whereas data after C<__DATA__> is.
|
|
The C<__DATA__> token is not recognized in versions of perl prior to
|
|
5.001m.
|
|
|
|
Note that it is possible to have C<__DATA__> tokens in the same package
|
|
in multiple files, and that the last C<__DATA__> token in a given
|
|
package that is encountered by the compiler is the one accessible
|
|
by the filehandle. This also applies to C<__END__> and main, i.e. if
|
|
the 'main' program has an C<__END__>, but a module 'require'd (_not_ 'use'd)
|
|
by that program has a 'package main;' declaration followed by an 'C<__DATA__>',
|
|
then the C<DATA> filehandle is set to access the data after the C<__DATA__>
|
|
in the module, _not_ the data after the C<__END__> token in the 'main'
|
|
program, since the compiler encounters the 'require'd file later.
|
|
|
|
=head2 SelfLoader autoloading
|
|
|
|
The B<SelfLoader> works by the user placing the C<__DATA__>
|
|
token I<after> perl code which needs to be compiled and
|
|
run at 'require' time, but I<before> subroutine declarations
|
|
that can be loaded in later - usually because they may never
|
|
be called.
|
|
|
|
The B<SelfLoader> will read from the FOOBAR::DATA filehandle to
|
|
load in the data after C<__DATA__>, and load in any subroutine
|
|
when it is called. The costs are the one-time parsing of the
|
|
data after C<__DATA__>, and a load delay for the _first_
|
|
call of any autoloaded function. The benefits (hopefully)
|
|
are a speeded up compilation phase, with no need to load
|
|
functions which are never used.
|
|
|
|
The B<SelfLoader> will stop reading from C<__DATA__> if
|
|
it encounters the C<__END__> token - just as you would expect.
|
|
If the C<__END__> token is present, and is followed by the
|
|
token DATA, then the B<SelfLoader> leaves the FOOBAR::DATA
|
|
filehandle open on the line after that token.
|
|
|
|
The B<SelfLoader> exports the C<AUTOLOAD> subroutine to the
|
|
package using the B<SelfLoader>, and this loads the called
|
|
subroutine when it is first called.
|
|
|
|
There is no advantage to putting subroutines which will _always_
|
|
be called after the C<__DATA__> token.
|
|
|
|
=head2 Autoloading and package lexicals
|
|
|
|
A 'my $pack_lexical' statement makes the variable $pack_lexical
|
|
local _only_ to the file up to the C<__DATA__> token. Subroutines
|
|
declared elsewhere _cannot_ see these types of variables,
|
|
just as if you declared subroutines in the package but in another
|
|
file, they cannot see these variables.
|
|
|
|
So specifically, autoloaded functions cannot see package
|
|
lexicals (this applies to both the B<SelfLoader> and the Autoloader).
|
|
The C<vars> pragma provides an alternative to defining package-level
|
|
globals that will be visible to autoloaded routines. See the documentation
|
|
on B<vars> in the pragma section of L<perlmod>.
|
|
|
|
=head2 SelfLoader and AutoLoader
|
|
|
|
The B<SelfLoader> can replace the AutoLoader - just change 'use AutoLoader'
|
|
to 'use SelfLoader' (though note that the B<SelfLoader> exports
|
|
the AUTOLOAD function - but if you have your own AUTOLOAD and
|
|
are using the AutoLoader too, you probably know what you're doing),
|
|
and the C<__END__> token to C<__DATA__>. You will need perl version 5.001m
|
|
or later to use this (version 5.001 with all patches up to patch m).
|
|
|
|
There is no need to inherit from the B<SelfLoader>.
|
|
|
|
The B<SelfLoader> works similarly to the AutoLoader, but picks up the
|
|
subs from after the C<__DATA__> instead of in the 'lib/auto' directory.
|
|
There is a maintenance gain in not needing to run AutoSplit on the module
|
|
at installation, and a runtime gain in not needing to keep opening and
|
|
closing files to load subs. There is a runtime loss in needing
|
|
to parse the code after the C<__DATA__>. Details of the B<AutoLoader> and
|
|
another view of these distinctions can be found in that module's
|
|
documentation.
|
|
|
|
=head2 __DATA__, __END__, and the FOOBAR::DATA filehandle.
|
|
|
|
This section is only relevant if you want to use
|
|
the C<FOOBAR::DATA> together with the B<SelfLoader>.
|
|
|
|
Data after the C<__DATA__> token in a module is read using the
|
|
FOOBAR::DATA filehandle. C<__END__> can still be used to denote the end
|
|
of the C<__DATA__> section if followed by the token DATA - this is supported
|
|
by the B<SelfLoader>. The C<FOOBAR::DATA> filehandle is left open if an
|
|
C<__END__> followed by a DATA is found, with the filehandle positioned at
|
|
the start of the line after the C<__END__> token. If no C<__END__> token is
|
|
present, or an C<__END__> token with no DATA token on the same line, then
|
|
the filehandle is closed.
|
|
|
|
The B<SelfLoader> reads from wherever the current
|
|
position of the C<FOOBAR::DATA> filehandle is, until the
|
|
EOF or C<__END__>. This means that if you want to use
|
|
that filehandle (and ONLY if you want to), you should either
|
|
|
|
1. Put all your subroutine declarations immediately after
|
|
the C<__DATA__> token and put your own data after those
|
|
declarations, using the C<__END__> token to mark the end
|
|
of subroutine declarations. You must also ensure that the B<SelfLoader>
|
|
reads first by calling 'SelfLoader-E<gt>load_stubs();', or by using a
|
|
function which is selfloaded;
|
|
|
|
or
|
|
|
|
2. You should read the C<FOOBAR::DATA> filehandle first, leaving
|
|
the handle open and positioned at the first line of subroutine
|
|
declarations.
|
|
|
|
You could conceivably do both.
|
|
|
|
=head2 Classes and inherited methods.
|
|
|
|
For modules which are not classes, this section is not relevant.
|
|
This section is only relevant if you have methods which could
|
|
be inherited.
|
|
|
|
A subroutine stub (or forward declaration) looks like
|
|
|
|
sub stub;
|
|
|
|
i.e. it is a subroutine declaration without the body of the
|
|
subroutine. For modules which are not classes, there is no real
|
|
need for stubs as far as autoloading is concerned.
|
|
|
|
For modules which ARE classes, and need to handle inherited methods,
|
|
stubs are needed to ensure that the method inheritance mechanism works
|
|
properly. You can load the stubs into the module at 'require' time, by
|
|
adding the statement 'SelfLoader-E<gt>load_stubs();' to the module to do
|
|
this.
|
|
|
|
The alternative is to put the stubs in before the C<__DATA__> token BEFORE
|
|
releasing the module, and for this purpose the C<Devel::SelfStubber>
|
|
module is available. However this does require the extra step of ensuring
|
|
that the stubs are in the module. If this is done I strongly recommend
|
|
that this is done BEFORE releasing the module - it should NOT be done
|
|
at install time in general.
|
|
|
|
=head1 Multiple packages and fully qualified subroutine names
|
|
|
|
Subroutines in multiple packages within the same file are supported - but you
|
|
should note that this requires exporting the C<SelfLoader::AUTOLOAD> to
|
|
every package which requires it. This is done automatically by the
|
|
B<SelfLoader> when it first loads the subs into the cache, but you should
|
|
really specify it in the initialization before the C<__DATA__> by putting
|
|
a 'use SelfLoader' statement in each package.
|
|
|
|
Fully qualified subroutine names are also supported. For example,
|
|
|
|
__DATA__
|
|
sub foo::bar {23}
|
|
package baz;
|
|
sub dob {32}
|
|
|
|
will all be loaded correctly by the B<SelfLoader>, and the B<SelfLoader>
|
|
will ensure that the packages 'foo' and 'baz' correctly have the
|
|
B<SelfLoader> C<AUTOLOAD> method when the data after C<__DATA__> is first
|
|
parsed.
|
|
|
|
=cut
|