How do I find the module dependencies of my Perl script?

25,982

Solution 1

You could dump %INC at the end of your script. It will contain all used and required modules. But of course, this will only be helpful if you don't require modules conditionally (require Foo if $bar).

Solution 2

Check out Module::ScanDeps and the "scandeps.pl" utility that comes with it. It can do a static (and recursive) analysis of your code for dependencies as well as the %INC dump either after compiling or running the program.

Please note that the static source scanning always errs on the side of including too many dependencies. (It is the dependency scanner used by PAR and aims at being easiest on the end-user.)

Finally, you could choose to distribute your script as a CPAN distribution. That sounds much more complicated than it really is. You can use something like Module::Starter to set up a basic skeleton of a tentative App::YourScript distribution. Put your script in the bin/ subdirectory and edit the Makefile.PL to reference all of your direct dependencies. Then, for distribution you do:

  1. perl Makefile.PL
  2. make
  3. make dist

The last step generates a nice App-YourScript-VERSION.tar.gz Now, when the client wants to install all dependencies, he does the following:

  1. Set up the CPAN client correctly. Simply run it and answer the questions. But you're requiring that already anyway.
  2. "tar -xz App-YourScript-VERSION.tar.gz && cd App-YourScript-VERSION"
  3. Run "cpan ."

The CPAN client will now install all direct dependencies and the dependencies of those distributions automatically. Depending on how you set it up, it will either follow the prerequisites recursively automatically or prompt with a y/n each time.

As an example of this, you might check out a few of the App::* distributions on CPAN. I would think App::Ack is a good example. Maybe one of the App::* distributions from my CPAN directory (SMUELLER).

Solution 3

For quick-and-dirty, infrequent use, the %INC is the best way to go. If you have to do this with continuous integration testing or something more robust, there are some other tools to help.

Steffen already mentioned the Module::ScanDeps.

The code in Test::Prereq does this, but it has an additional layer that ensures that your Makefile.PL or Build.PL lists them as a dependency. If you make your scripts look like a normal Perl distribution, that makes it fairly easy to check for new dependencies; just run the test suite again.

Aside from that, you might use a tool such as Module::Extract::Use, which parses the static code looking for use and require statements (although it won't find them in string evals). That gets you just the modules you told your script to load. Also, once you know which modules you loaded, you can combine that with David Cantrell's CPANdeps tool that has already created the dependency tree for most CPAN modules.

Note that you also have to think about optional features too. Your code in this case my not have them, but sometimes you don't load a module until you need it:

sub foo
    {
    require Bar; # don't load until we need to use it
    ....
    }

If you don't exercise that feature in your trial run or test, you won't see that you need Bar for that feature. A similar problem comes up when a module loads a different set of dependency modules in a different environment (say, mod_perl or Windows, and so on).

There's not a good, automated way of testing optional features like that so you can get their dependencies. However, I think that should be on my To Do list since it sounds like an interesting problem.

Solution 4

Another tool in this area, which is used by Dist::Zilla and its AutoPrereqs plugin, is Perl::PrereqScanner. It installs a scan-perl-prereqs program that will use PPI and a few plugins to search for most kinds of prereq declaration, using the minimum versions you define. In general, I suggest this over scanning %INC, which can bring in bogus requirements and ignores versions.

Solution 5

Today I develop my Perl apps as CPAN-like distributions using Dist::Zilla that can take care of the dependencies through the AutoPrereq plugin. Another interesting piece of code in this area is carton.

Share:
25,982
zoul
Author by

zoul

Updated on September 02, 2020

Comments

  • zoul
    zoul over 3 years

    I want another developer to run a Perl script I have written. The script uses many CPAN modules that have to be installed before the script can be run. Is it possible to make the script (or the perl binary) to dump a list of all the missing modules? Perl prints out the missing modules’ names when I attempt to run the script, but this is verbose and does not list all the missing modules at once. I’d like to do something like:

    $ cpan -i `said-script --list-deps`
    

    Or even:

    $ list-deps said-script > required-modules # on my machine
    $ cpan -i `cat required-modules` # on his machine
    

    Is there a simple way to do it? This is not a show stopper, but I would like to make the other developer’s life easier. (The required modules are sprinkled across several files, so that it’s not easy for me to make the list by hand without missing anything. I know about PAR, but it seems a bit too complicated for what I want.)


    Update: Thanks, Manni, that will do. I did not know about %INC, I only knew about @INC. I settled with something like this:

    print join("\n", map { s|/|::|g; s|\.pm$||; $_ } keys %INC);
    

    Which prints out:

    Moose::Meta::TypeConstraint::Registry
    Moose::Meta::Role::Application::ToClass
    Class::C3
    List::Util
    Imager::Color
    …
    

    Looks like this will work.

  • cjm
    cjm over 8 years
    No, static source scanning doesn't always err on the side of including too many dependencies. It can also miss things like eval "require $module", where $module is computed at run time based on some criteria.
  • Boris Däppen
    Boris Däppen over 6 years
    This fits my work flow much better than scandeps. It gives me just the names I have intentionally included. (Subdependencies are mostly not of interest, since modern installers handle them for you.)