Search code examples
perlperl-module

Check and report Perl module missing


Is there any way to report the missing modules used in the Perl file beforehand instead of getting as an error.

I have something like use Digest::MD5, use File::DosGlob modules in my Perl program. Whenever the users run the script they are getting an error if there is no specific module installed in their system. They could not understand the default error message given by @INC. So I would like to clearly tell them that these modules need to be installed to run the script.


Solution

  • You could build your own verification by using a BEGIN block. Those are run at compile time, just like use is. Keep in mind that use Foo is essentially nothing else as this:

    BEGIN {
        require Foo;
        Foo->import;
    }
    

    The following code will replace all use statements with a single BEGIN and place them inside an eval. That's essentially like a try/catch mechanism.

    We need the string eval (which is considered evil around here) because require only converts from package names with colons :: to paths if the argument is a bareword. But because we have the name in $module, it's a string, so we need to place it into an eval according to require's docs.

    If that string eval fails, we die. That's caught by the outer eval block and $@ is set. We can then check if it contains our module name, in which case we naively assume the failure was because that module is not installed. This check could be a bit more elaborate.

    We keep track of any failures in $fails, and if there were any, we stop.

    #!/usr/bin/perl
    use strict;
    use warnings;
    
    # all our use statements go here
    BEGIN {
        my $fails;
        foreach my $module ( qw/Digest::MD5 File::DosGlob ASDF/ ) {
            eval {
                eval "require $module" or die; # because $module is not a bareword
                $module->import;
            };
            if ($@ && $@ =~ /$module/) {
                warn "You need to install the $module module";
                $fails++;
            }
        }
        exit if $fails;
    }
    
    # ...
    

    Above I included ASDF, which I don't have, so when run it will say

    You need to install the ASDF module at /home/code/scratch.pl line 1335.

    You might want to make that message a bit more verbose. If your users are not able to understand the default error message that Perl gives when it cannot find a module, it might be wise to include a guide on how to install stuff right there.

    Note that both modules you listed have been included with Perl for a while (read: since March 2002). So why would you want to do this for those modules?

    $ corelist Digest::MD5
    
    Data for 2014-09-14
    Digest::MD5 was first released with perl v5.7.3
    
    $ corelist File::DosGlob
    
    Data for 2014-09-14
    File::DosGlob was first released with perl 5.00405
    

    A better way would be ship your program as a distribution that can be installed, and include a Makefile or a cpanfile or something similar that lists dependencies. There is a guide in perlnewmod on how to start a new module. You'd not want to upload to CPAN obviously, but the basics are the same.

    With this, your users would get all dependencies installed automatically.