If I want to distribute a Perl script, what is the best way to painlessly install any required modules that are missing on the user's system? Extra credit if there is a way to even install/upgrade Perl itself if it is missing or "too old".
问题:
回答1:
Auto-installing software is the best way to make both end users and sysadmins very angry with you. Forget about this approach.
You can simply ship all your dependencies with your application distro, the inc
directory is customary.
回答2:
Usually this ends with CPAN-like package creation.
So, when you need to install all dependencies you type make installdeps
See perldoc perlmodlib
Also Module::Install
may be useful for you and some Makefile.PL example
Makefile.PL
allows you to define deps and required perl version.
Also you may add
use 5.010;
To your script in order to require minimal version of perl to run. See perldoc -f use for details.
回答3:
Why not use pp (PAR Packager) that creates an executable. No need for Perl or anything on the target machine.
回答4:
If you look at cpanminus, this you can install by simply executing one file:
curl -L http://cpanmin.us | perl - --self-upgrade
This might be the behaviour you're looking for; it's done with App::Fatpacker. Check it out:
https://metacpan.org/module/App::FatPacker
回答5:
A semi-automated script taken from here , which should work for people with middle level bash skills and almost 0 level perl skills :
#!/usr/bin/env perl
use strict ; use warnings ;
use 5.10.0 ;
use ExtUtils::Installed;
# quick and dirty check for prerequisites perl modules:
# courtesy of:http://stackoverflow.com/a/9340304/65706
# if you have a calling bash script call by :
# perl "/path/to/isg_pub_preq_checker.pl"
# export ret=$?
# test $ret -ne 0 && doExit 1 "[FATAL] perl modules not found!!!"
my $PrintOkCheck = 1 ;
# check that all the required modules are installed
my ( $ret , $msg ) = doCheckRequiredModules();
unless ( $ret == 0 ) {
print "$msg" ;
# give some time for the user to react
print "printing all installed modules :" ;
my $c = 9 ;
for ( my $i=0;$i<=$c;$i++){
print ( ( $c-$i) . '.') ;
sleep 1 ;
}
print "\n" ;
doListAllInstalledModules();
print "\n" ;
}
exit(0);
sub doListAllInstalledModules {
my $instmod = ExtUtils::Installed->new();
foreach my $module ($instmod->modules()) {
my $version = $instmod->version($module) || "???";
print "found module:$module -- v$version\n";
}
}
#eof sub
sub doCheckRequiredModules {
my @modules = qw(
YAML::Any
Test::More
Spreadsheet::XLSX
Test::Deep
File::Copy::Recursive
IO::HTML
Test::More
Filter::Util::Call
Algorithm::Diff
Text::Diff
Test::Base
Test::CPAN::Meta::YAML
Test::YAML::Valid
Test::YAML::Meta
Test::YAML
Data::Printer
ExtUtils::Installed
Sub::StrictDecl
Spreadsheet::WriteExcel
Mojolicious::Plugin::RenderFile
JSON
Carp::Always
Mojolicious::Plugin::PDFRenderer
Redis::Client
);
for(@modules) {
eval "use $_";
if ($@) {
#flush the screen
print "\033[2J";
print "\033[0;0H";
my $msg = "\n\n\n [FATAL] did not found the following prerequisite perl module: $_ \n\n" ;
$msg .= "\n # == START copy paste == " ;
$msg .= "\n#you must install it otherwise the application will not work" ;
$msg .= "\n#the module could be installef by running the following commands:" ;
# if the user knows already the difference between the running the cmd
# with sudo or he / she probably knows already how-to install perl modules
$msg .= "\n# as a start configure the cpan to install dependancies first \n" ;
$msg .= "\n" . 'perl -MCPAN -e \'my $c = "CPAN::HandleConfig"; $c->load(doit => 1, autoconfig => 1); $c->edit(prerequisites_policy => "follow"); $c->edit(build_requires_install_policy => "yes"); $c->commit\'' . "\n" ;
$msg .= "\n#than install the $_ module by running: \n" ;
$msg .= "\nsudo perl -MCPAN -e 'install $_'\n\n\n" ;
$msg .= "\n # == STOP copy paste == \n\n\n" ;
$msg .= "\n # == START copy paste == " ;
$msg .= "\n# if you seem to be stuck in circular reference kind of loop try even :\n" ;
$msg .= "\nsudo perl -MCPAN -e 'CPAN::Shell->force(qw( install $_));'\n" ;
$msg .= "\n # == STOP copy paste == " ;
$msg .= "\n# You may end-up now with Ctrl + C \n\n\n" ;
return ( 1, "$msg") if $@;
} else {
say "[INFO ] == ok == check for prerequisite perl module : $_" if $PrintOkCheck == 1 ;
}
}
#eof foreach module
return ( 0 , "all required modules found" ) ;
}
#eof sub
# ??!!
#perl -MCPAN -e 'install Module::Signature'
# the following modules have been or might be part of the installable modules
#PDF::WebKit
#HTML::TreeBuilder
#HTML::TreeBuilder::XPath
#HTML::TableExtract
#HTML::ElementTable