5

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".

JoelFan
  • 37,465
  • 35
  • 132
  • 205

5 Answers5

6

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.

daxim
  • 39,270
  • 4
  • 65
  • 132
  • While I agree with the sentiment, I think the answer needs more work. Are you advocating the shipping of other perl packages or just shipping a copy of their code? The issue here is very common. It's painful in all languages to keep track of the 3rd party modules one uses. As a professional developer who distributes code, I now judge a language on the quality of it's package management. CPAN was once the greatest repository of software known to developers. But...It has taught lessons to other technologies which have less cryptic ways to create a software module. – Mark O'Connor Nov 19 '11 at 12:33
  • I'm advocating neither. I'm actually fond of the standard toolchain, yko laid out the details. I felt like taking on the question at face value, even if it is misguided. – daxim Nov 20 '11 at 21:04
3

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.

yko
  • 2,710
  • 13
  • 15
  • 1
    That is not the "painless" I had in mind! I want to distribute one perl script file, allow the user to just run that script and the script itself installs any missing (but needed) modules without the user having to do any separate action. – JoelFan Nov 18 '11 at 14:02
  • @JoelFan, if you can get it to run on your platform, see Bill Ruppert's answer for *more* "painless". – Axeman Nov 18 '11 at 16:42
  • 4
    Forget painless.... This is the proper answer, distribute the script as a perl module. Users who know how to manage perl distributions can then easily use the standard tooling. For less knowledgeable users provide a script which invokes the installation of your package. In conclusion your issue really is with Perl.... I used it for years and had the same issues. I flirted with using the PAR module but eventually gave up due to the effort involved. Embrace Perl or abandon it. I discovered there is no in-between :-( – Mark O'Connor Nov 19 '11 at 12:21
2

Why not use pp (PAR Packager) that creates an executable. No need for Perl or anything on the target machine.

Bill Ruppert
  • 8,956
  • 7
  • 27
  • 44
  • PAR is very very cool. In my experience it was never as good as TCL's starkits and starpacks, which is massively disappointing. I learned that it was better to spend some time learning how to package perl as a module. Admittedly clunky, but easier to support across multiple platforms. – Mark O'Connor Nov 19 '11 at 12:25
2

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

MichielB
  • 4,181
  • 1
  • 30
  • 39
0

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
Yordan Georgiev
  • 5,114
  • 1
  • 56
  • 53