split_command($pm_to_blib, map { ($self->quote_literal($_) => $self->quote_literal($self->{PM}->{$_})) } sort keys %{$self->{PM}}); $r .= join '', map { "\t\$(NOECHO) $_\n" } @cmds; $r .= qq{\t\$(NOECHO) \$(TOUCH) pm_to_blib\n}; return $r; } # transform dot-separated version string into comma-separated quadruple # examples: '1.2.3.4.5' => '1,2,3,4' # '1.2.3' => '1,2,3,0' sub _ppd_version { my ($self, $string) = @_; return join ',', ((split /\./, $string), (0) x 4)[0..3]; } =item ppd Defines target that creates a PPD (Perl Package Description) file for a binary distribution. =cut sub ppd { my($self) = @_; my $abstract = $self->{ABSTRACT} || ''; $abstract =~ s/\n/\\n/sg; $abstract =~ s/</g; $abstract =~ s/>/>/g; my $author = join(', ',@{ ref $self->{AUTHOR} eq 'ARRAY' ? $self->{AUTHOR} : [ $self->{AUTHOR} || '']}); $author =~ s/</g; $author =~ s/>/>/g; my $ppd_file = "$self->{DISTNAME}.ppd"; my @ppd_chunks = qq(\n); push @ppd_chunks, sprintf <<'PPD_HTML', $abstract, $author; %s %s PPD_HTML push @ppd_chunks, " \n"; if ( $self->{MIN_PERL_VERSION} ) { my $min_perl_version = $self->_ppd_version($self->{MIN_PERL_VERSION}); push @ppd_chunks, sprintf <<'PPD_PERLVERS', $min_perl_version; PPD_PERLVERS } # Don't add "perl" to requires. perl dependencies are # handles by ARCHITECTURE. my %prereqs = %{$self->{PREREQ_PM}}; delete $prereqs{perl}; # Build up REQUIRE foreach my $prereq (sort keys %prereqs) { my $name = $prereq; $name .= '::' unless $name =~ /::/; my $version = $prereqs{$prereq}; my %attrs = ( NAME => $name ); $attrs{VERSION} = $version if $version; my $attrs = join " ", map { qq[$_="$attrs{$_}"] } sort keys %attrs; push @ppd_chunks, qq( \n); } my $archname = $Config{archname}; if ($] >= 5.008) { # archname did not change from 5.6 to 5.8, but those versions may # not be not binary compatible so now we append the part of the # version that changes when binary compatibility may change $archname .= "-$Config{PERL_REVISION}.$Config{PERL_VERSION}"; } push @ppd_chunks, sprintf <<'PPD_OUT', $archname; PPD_OUT if ($self->{PPM_INSTALL_SCRIPT}) { if ($self->{PPM_INSTALL_EXEC}) { push @ppd_chunks, sprintf qq{ %s\n}, $self->{PPM_INSTALL_EXEC}, $self->{PPM_INSTALL_SCRIPT}; } else { push @ppd_chunks, sprintf qq{ %s\n}, $self->{PPM_INSTALL_SCRIPT}; } } if ($self->{PPM_UNINSTALL_SCRIPT}) { if ($self->{PPM_UNINSTALL_EXEC}) { push @ppd_chunks, sprintf qq{ %s\n}, $self->{PPM_UNINSTALL_EXEC}, $self->{PPM_UNINSTALL_SCRIPT}; } else { push @ppd_chunks, sprintf qq{ %s\n}, $self->{PPM_UNINSTALL_SCRIPT}; } } my ($bin_location) = $self->{BINARY_LOCATION} || ''; $bin_location =~ s/\\/\\\\/g; push @ppd_chunks, sprintf <<'PPD_XML', $bin_location; PPD_XML my @ppd_cmds = $self->stashmeta(join('', @ppd_chunks), $ppd_file); return sprintf <<'PPD_OUT', join "\n\t", @ppd_cmds; # Creates a PPD (Perl Package Description) for a binary distribution. ppd : %s PPD_OUT } =item prefixify $MM->prefixify($var, $prefix, $new_prefix, $default); Using either $MM->{uc $var} || $Config{lc $var}, it will attempt to replace it's $prefix with a $new_prefix. Should the $prefix fail to match I a PREFIX was given as an argument to WriteMakefile() it will set it to the $new_prefix + $default. This is for systems whose file layouts don't neatly fit into our ideas of prefixes. This is for heuristics which attempt to create directory structures that mirror those of the installed perl. For example: $MM->prefixify('installman1dir', '/usr', '/home/foo', 'man/man1'); this will attempt to remove '/usr' from the front of the $MM->{INSTALLMAN1DIR} path (initializing it to $Config{installman1dir} if necessary) and replace it with '/home/foo'. If this fails it will simply use '/home/foo/man/man1'. =cut sub prefixify { my($self,$var,$sprefix,$rprefix,$default) = @_; my $path = $self->{uc $var} || $Config_Override{lc $var} || $Config{lc $var} || ''; $rprefix .= '/' if $sprefix =~ m|/$|; warn " prefixify $var => $path\n" if $Verbose >= 2; warn " from $sprefix to $rprefix\n" if $Verbose >= 2; if( $self->{ARGS}{PREFIX} && $path !~ s{^\Q$sprefix\E\b}{$rprefix}s ) { warn " cannot prefix, using default.\n" if $Verbose >= 2; warn " no default!\n" if !$default && $Verbose >= 2; $path = $self->catdir($rprefix, $default) if $default; } print " now $path\n" if $Verbose >= 2; return $self->{uc $var} = $path; } =item processPL (o) Defines targets to run *.PL files. =cut sub processPL { my $self = shift; my $pl_files = $self->{PL_FILES}; return "" unless $pl_files; my $m = ''; foreach my $plfile (sort keys %$pl_files) { my $list = ref($pl_files->{$plfile}) ? $pl_files->{$plfile} : [$pl_files->{$plfile}]; foreach my $target (@$list) { if( $Is{VMS} ) { $plfile = vmsify($self->eliminate_macros($plfile)); $target = vmsify($self->eliminate_macros($target)); } # Normally a .PL file runs AFTER pm_to_blib so it can have # blib in its @INC and load the just built modules. BUT if # the generated module is something in $(TO_INST_PM) which # pm_to_blib depends on then it can't depend on pm_to_blib # else we have a dependency loop. my $pm_dep; my $perlrun; if( defined $self->{PM}{$target} ) { $pm_dep = ''; $perlrun = 'PERLRUN'; } else { $pm_dep = 'pm_to_blib'; $perlrun = 'PERLRUNINST'; } $m .= < in command line arguments. Doesn't handle recursive Makefile C<$(...)> constructs, but handles simple ones. =cut sub quote_paren { my $arg = shift; $arg =~ s{\$\((.+?)\)}{\$\\\\($1\\\\)}g; # protect $(...) $arg =~ s{(?replace_manpage_separator($file_path); Takes the name of a package, which may be a nested package, in the form 'Foo/Bar.pm' and replaces the slash with C<::> or something else safe for a man page file name. Returns the replacement. =cut sub replace_manpage_separator { my($self,$man) = @_; $man =~ s,/+,::,g; return $man; } =item cd =cut sub cd { my($self, $dir, @cmds) = @_; # No leading tab and no trailing newline makes for easier embedding my $make_frag = join "\n\t", map { "cd $dir && $_" } @cmds; return $make_frag; } =item oneliner =cut sub oneliner { my($self, $cmd, $switches) = @_; $switches = [] unless defined $switches; # Strip leading and trailing newlines $cmd =~ s{^\n+}{}; $cmd =~ s{\n+$}{}; my @cmds = split /\n/, $cmd; $cmd = join " \n\t -e ", map $self->quote_literal($_), @cmds; $cmd = $self->escape_newlines($cmd); $switches = join ' ', @$switches; return qq{\$(ABSPERLRUN) $switches -e $cmd --}; } =item quote_literal Quotes macro literal value suitable for being used on a command line so that when expanded by make, will be received by command as given to this method: my $quoted = $mm->quote_literal(q{it isn't}); # returns: # 'it isn'\''t' print MAKEFILE "target:\n\techo $quoted\n"; # when run "make target", will output: # it isn't =cut sub quote_literal { my($self, $text, $opts) = @_; $opts->{allow_variables} = 1 unless defined $opts->{allow_variables}; # Quote single quotes $text =~ s{'}{'\\''}g; $text = $opts->{allow_variables} ? $self->escape_dollarsigns($text) : $self->escape_all_dollarsigns($text); return "'$text'"; } =item escape_newlines =cut sub escape_newlines { my($self, $text) = @_; $text =~ s{\n}{\\\n}g; return $text; } =item max_exec_len Using POSIX::ARG_MAX. Otherwise falling back to 4096. =cut sub max_exec_len { my $self = shift; if (!defined $self->{_MAX_EXEC_LEN}) { if (my $arg_max = eval { require POSIX; &POSIX::ARG_MAX }) { $self->{_MAX_EXEC_LEN} = $arg_max; } else { # POSIX minimum exec size $self->{_MAX_EXEC_LEN} = 4096; } } return $self->{_MAX_EXEC_LEN}; } =item static (o) Defines the static target. =cut sub static { # --- Static Loading Sections --- my($self) = shift; ' ## $(INST_PM) has been moved to the all: target. ## It remains here for awhile to allow for old usage: "make static" static :: $(FIRST_MAKEFILE) $(INST_STATIC) $(NOECHO) $(NOOP) '; } sub static_lib { my($self) = @_; return '' unless $self->has_link_code; my(@m); my @libs; if ($self->{XSMULTI}) { for my $ext ($self->_xs_list_basenames) { my ($v, $d, $f) = File::Spec->splitpath($ext); my @d = File::Spec->splitdir($d); shift @d if $d[0] eq 'lib'; my $instdir = $self->catdir('$(INST_ARCHLIB)', 'auto', @d, $f); my $instfile = $self->catfile($instdir, "$f\$(LIB_EXT)"); my $objfile = "$ext\$(OBJ_EXT)"; push @libs, [ $objfile, $instfile, $instdir ]; } } else { @libs = ([ qw($(OBJECT) $(INST_STATIC) $(INST_ARCHAUTODIR)) ]); } push @m, map { $self->xs_make_static_lib(@$_); } @libs; join "\n", @m; } =item xs_make_static_lib Defines the recipes for the C section. =cut sub xs_make_static_lib { my ($self, $from, $to, $todir) = @_; my @m = sprintf '%s: %s $(MYEXTLIB) %s$(DFSEP).exists'."\n", $to, $from, $todir; push @m, "\t\$(RM_F) \"\$\@\"\n"; push @m, $self->static_lib_fixtures; push @m, $self->static_lib_pure_cmd($from); push @m, "\t\$(CHMOD) \$(PERM_RWX) \$\@\n"; push @m, $self->static_lib_closures($todir); join '', @m; } =item static_lib_closures Records C<$(EXTRALIBS)> in F and F<$(PERL_SRC)/ext.libs>. =cut sub static_lib_closures { my ($self, $todir) = @_; my @m = sprintf <<'MAKE_FRAG', $todir; $(NOECHO) $(ECHO) "$(EXTRALIBS)" > %s$(DFSEP)extralibs.ld MAKE_FRAG # Old mechanism - still available: push @m, <<'MAKE_FRAG' if $self->{PERL_SRC} && $self->{EXTRALIBS}; $(NOECHO) $(ECHO) "$(EXTRALIBS)" >> $(PERL_SRC)$(DFSEP)ext.libs MAKE_FRAG @m; } =item static_lib_fixtures Handles copying C<$(MYEXTLIB)> as starter for final static library that then gets added to. =cut sub static_lib_fixtures { my ($self) = @_; # If this extension has its own library (eg SDBM_File) # then copy that to $(INST_STATIC) and add $(OBJECT) into it. return unless $self->{MYEXTLIB}; "\t\$(CP) \$(MYEXTLIB) \"\$\@\"\n"; } =item static_lib_pure_cmd Defines how to run the archive utility. =cut sub static_lib_pure_cmd { my ($self, $from) = @_; my $ar; if (exists $self->{FULL_AR} && -x $self->{FULL_AR}) { # Prefer the absolute pathed ar if available so that PATH # doesn't confuse us. Perl itself is built with the full_ar. $ar = 'FULL_AR'; } else { $ar = 'AR'; } sprintf <<'MAKE_FRAG', $ar, $from; $(%s) $(AR_STATIC_ARGS) "$@" %s $(RANLIB) "$@" MAKE_FRAG } =item staticmake (o) Calls makeaperl. =cut sub staticmake { my($self, %attribs) = @_; my(@static); my(@searchdirs)=($self->{PERL_ARCHLIB}, $self->{SITEARCHEXP}, $self->{INST_ARCHLIB}); # And as it's not yet built, we add the current extension # but only if it has some C code (or XS code, which implies C code) if (@{$self->{C}}) { @static = $self->catfile($self->{INST_ARCHLIB}, "auto", $self->{FULLEXT}, "$self->{BASEEXT}$self->{LIB_EXT}" ); } # Either we determine now, which libraries we will produce in the # subdirectories or we do it at runtime of the make. # We could ask all subdir objects, but I cannot imagine, why it # would be necessary. # Instead we determine all libraries for the new perl at # runtime. my(@perlinc) = ($self->{INST_ARCHLIB}, $self->{INST_LIB}, $self->{PERL_ARCHLIB}, $self->{PERL_LIB}); $self->makeaperl(MAKE => $self->{MAKEFILE}, DIRS => \@searchdirs, STAT => \@static, INCL => \@perlinc, TARGET => $self->{MAP_TARGET}, TMP => "", LIBPERL => $self->{LIBPERL_A} ); } =item subdir_x (o) Helper subroutine for subdirs =cut sub subdir_x { my($self, $subdir) = @_; my $subdir_cmd = $self->cd($subdir, '$(MAKE) $(USEMAKEFILE) $(FIRST_MAKEFILE) all $(PASTHRU)' ); return sprintf <<'EOT', $subdir_cmd; subdirs :: $(NOECHO) %s EOT } =item subdirs (o) Defines targets to process subdirectories. =cut sub subdirs { # --- Sub-directory Sections --- my($self) = shift; my(@m); # This method provides a mechanism to automatically deal with # subdirectories containing further Makefile.PL scripts. # It calls the subdir_x() method for each subdirectory. foreach my $dir (@{$self->{DIR}}){ push @m, $self->subdir_x($dir); #### print "Including $dir subdirectory\n"; } if (@m){ unshift @m, <<'EOF'; # The default clean, realclean and test targets in this Makefile # have automatically been given entries for each subdir. EOF } else { push(@m, "\n# none") } join('',@m); } =item test (o) Defines the test targets. =cut sub test { my($self, %attribs) = @_; my $tests = $attribs{TESTS} || ''; if (!$tests && -d 't' && defined $attribs{RECURSIVE_TEST_FILES}) { $tests = $self->find_tests_recursive; } elsif (!$tests && -d 't') { $tests = $self->find_tests; } # have to do this because nmake is broken $tests =~ s!/!\\!g if $self->is_make_type('nmake'); # note: 'test.pl' name is also hardcoded in init_dirscan() my @m; my $default_testtype = $Config{usedl} ? 'dynamic' : 'static'; push @m, <{SKIPHASH}{$_}, $linktype, "pure_all"; # no depend on a linktype if SKIPped push @m, "subdirs-test_$linktype :: $directdeps\n"; foreach my $dir (@{ $self->{DIR} }) { my $test = $self->cd($dir, "\$(MAKE) test_$linktype \$(PASTHRU)"); push @m, "\t\$(NOECHO) $test\n"; } push @m, "\n"; if ($tests or -f "test.pl") { for my $testspec ([ '', '' ], [ 'db', ' $(TESTDB_SW)' ]) { my ($db, $switch) = @$testspec; my ($command, $deps); # if testdb, build all but don't test all $deps = $db eq 'db' ? $directdeps : "subdirs-test_$linktype"; if ($linktype eq 'static' and $self->needs_linking) { my $target = File::Spec->rel2abs('$(MAP_TARGET)'); $command = qq{"$target" \$(MAP_PERLINC)}; $deps .= ' $(MAP_TARGET)'; } else { $command = '$(FULLPERLRUN)' . $switch; } push @m, "test${db}_$linktype :: $deps\n"; if ($db eq 'db') { push @m, $self->test_via_script($command, '$(TEST_FILE)') } else { push @m, $self->test_via_script($command, '$(TEST_FILE)') if -f "test.pl"; push @m, $self->test_via_harness($command, '$(TEST_FILES)') if $tests; } push @m, "\n"; } } else { push @m, _sprintf562 <<'EOF', $linktype; testdb_%1$s test_%1$s :: subdirs-test_%1$s $(NOECHO) $(ECHO) 'No tests defined for $(NAME) extension.' EOF } } join "", @m; } =item test_via_harness (override) For some reason which I forget, Unix machines like to have PERL_DL_NONLAZY set for tests. =cut sub test_via_harness { my($self, $perl, $tests) = @_; return $self->SUPER::test_via_harness("PERL_DL_NONLAZY=1 $perl", $tests); } =item test_via_script (override) Again, the PERL_DL_NONLAZY thing. =cut sub test_via_script { my($self, $perl, $script) = @_; return $self->SUPER::test_via_script("PERL_DL_NONLAZY=1 $perl", $script); } =item tool_xsubpp (o) Determines typemaps, xsubpp version, prototype behaviour. =cut sub tool_xsubpp { my($self) = shift; return "" unless $self->needs_linking; my $xsdir; my @xsubpp_dirs = @INC; # Make sure we pick up the new xsubpp if we're building perl. unshift @xsubpp_dirs, $self->{PERL_LIB} if $self->{PERL_CORE}; my $foundxsubpp = 0; foreach my $dir (@xsubpp_dirs) { $xsdir = $self->catdir($dir, 'ExtUtils'); if( -r $self->catfile($xsdir, "xsubpp") ) { $foundxsubpp = 1; last; } } die "ExtUtils::MM_Unix::tool_xsubpp : Can't find xsubpp" if !$foundxsubpp; my $tmdir = $self->catdir($self->{PERL_LIB},"ExtUtils"); my(@tmdeps) = $self->catfile($tmdir,'typemap'); if( $self->{TYPEMAPS} ){ foreach my $typemap (@{$self->{TYPEMAPS}}){ if( ! -f $typemap ) { warn "Typemap $typemap not found.\n"; } else { $typemap = vmsify($typemap) if $Is{VMS}; push(@tmdeps, $typemap); } } } push(@tmdeps, "typemap") if -f "typemap"; # absolutised because with deep-located typemaps, eg "lib/XS/typemap", # if xsubpp is called from top level with # $(XSUBPP) ... -typemap "lib/XS/typemap" "lib/XS/Test.xs" # it says: # Can't find lib/XS/type map in (fulldir)/lib/XS # because ExtUtils::ParseXS::process_file chdir's to .xs file's # location. This is the only way to get all specified typemaps used, # wherever located. my @tmargs = map { '-typemap '.$self->quote_literal(File::Spec->rel2abs($_)) } @tmdeps; $_ = $self->quote_dep($_) for @tmdeps; if( exists $self->{XSOPT} ){ unshift( @tmargs, $self->{XSOPT} ); } if ($Is{VMS} && $Config{'ldflags'} && $Config{'ldflags'} =~ m!/Debug!i && (!exists($self->{XSOPT}) || $self->{XSOPT} !~ /linenumbers/) ) { unshift(@tmargs,'-nolinenumbers'); } $self->{XSPROTOARG} = "" unless defined $self->{XSPROTOARG}; my $xsdirdep = $self->quote_dep($xsdir); # -dep for use when dependency not command return qq{ XSUBPPDIR = $xsdir XSUBPP = "\$(XSUBPPDIR)\$(DFSEP)xsubpp" XSUBPPRUN = \$(PERLRUN) \$(XSUBPP) XSPROTOARG = $self->{XSPROTOARG} XSUBPPDEPS = @tmdeps $xsdirdep\$(DFSEP)xsubpp XSUBPPARGS = @tmargs XSUBPP_EXTRA_ARGS = }; } =item all_target Build man pages, too =cut sub all_target { my $self = shift; return <<'MAKE_EXT'; all :: pure_all manifypods $(NOECHO) $(NOOP) MAKE_EXT } =item top_targets (o) Defines the targets all, subdirs, config, and O_FILES =cut sub top_targets { # --- Target Sections --- my($self) = shift; my(@m); push @m, $self->all_target, "\n" unless $self->{SKIPHASH}{'all'}; push @m, sprintf <<'EOF'; pure_all :: config pm_to_blib subdirs linkext $(NOECHO) $(NOOP) $(NOECHO) $(NOOP) subdirs :: $(MYEXTLIB) $(NOECHO) $(NOOP) config :: $(FIRST_MAKEFILE) blibdirs $(NOECHO) $(NOOP) EOF push @m, ' $(O_FILES) : $(H_FILES) ' if @{$self->{O_FILES} || []} && @{$self->{H} || []}; push @m, q{ help : perldoc ExtUtils::MakeMaker }; join('',@m); } =item writedoc Obsolete, deprecated method. Not used since Version 5.21. =cut sub writedoc { # --- perllocal.pod section --- my($self,$what,$name,@attribs)=@_; my $time = gmtime($ENV{SOURCE_DATE_EPOCH} || time); print "=head2 $time: $what C<$name>\n\n=over 4\n\n=item *\n\n"; print join "\n\n=item *\n\n", map("C<$_>",@attribs); print "\n\n=back\n\n"; } =item xs_c (o) Defines the suffix rules to compile XS files to C. =cut sub xs_c { my($self) = shift; return '' unless $self->needs_linking(); ' .xs.c: $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $(XSUBPP_EXTRA_ARGS) $*.xs > $*.xsc $(MV) $*.xsc $*.c '; } =item xs_cpp (o) Defines the suffix rules to compile XS files to C++. =cut sub xs_cpp { my($self) = shift; return '' unless $self->needs_linking(); ' .xs.cpp: $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $*.xs > $*.xsc $(MV) $*.xsc $*.cpp '; } =item xs_o (o) Defines suffix rules to go from XS to object files directly. This was originally only intended for broken make implementations, but is now necessary for per-XS file under C, since each XS file might have an individual C<$(VERSION)>. =cut sub xs_o { my ($self) = @_; return '' unless $self->needs_linking(); my $m_o = $self->{XSMULTI} ? $self->xs_obj_opt('$*$(OBJ_EXT)') : ''; my $frag = ''; # dmake makes noise about ambiguous rule $frag .= sprintf <<'EOF', $m_o unless $self->is_make_type('dmake'); .xs$(OBJ_EXT) : $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $*.xs > $*.xsc $(MV) $*.xsc $*.c $(CCCMD) $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) $(DEFINE) $*.c %s EOF if ($self->{XSMULTI}) { for my $ext ($self->_xs_list_basenames) { my $pmfile = "$ext.pm"; croak "$ext.xs has no matching $pmfile: $!" unless -f $pmfile; my $version = $self->parse_version($pmfile); my $cccmd = $self->{CONST_CCCMD}; $cccmd =~ s/^\s*CCCMD\s*=\s*//; $cccmd =~ s/\$\(DEFINE_VERSION\)/-DVERSION=\\"$version\\"/; $cccmd =~ s/\$\(XS_DEFINE_VERSION\)/-DXS_VERSION=\\"$version\\"/; $self->_xsbuild_replace_macro($cccmd, 'xs', $ext, 'INC'); my $define = '$(DEFINE)'; $self->_xsbuild_replace_macro($define, 'xs', $ext, 'DEFINE'); # 1 2 3 4 $frag .= _sprintf562 <<'EOF', $ext, $cccmd, $m_o, $define; %1$s$(OBJ_EXT): %1$s.xs $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $*.xs > $*.xsc $(MV) $*.xsc $*.c %2$s $(CCCDLFLAGS) "-I$(PERL_INC)" $(PASTHRU_DEFINE) %4$s $*.c %3$s EOF } } $frag; } # param gets modified sub _xsbuild_replace_macro { my ($self, undef, $xstype, $ext, $varname) = @_; my $value = $self->_xsbuild_value($xstype, $ext, $varname); return unless defined $value; $_[1] =~ s/\$\($varname\)/$value/; } sub _xsbuild_value { my ($self, $xstype, $ext, $varname) = @_; return $self->{XSBUILD}{$xstype}{$ext}{$varname} if $self->{XSBUILD}{$xstype}{$ext}{$varname}; return $self->{XSBUILD}{$xstype}{all}{$varname} if $self->{XSBUILD}{$xstype}{all}{$varname}; (); } 1; =back =head1 SEE ALSO L =cut __END__