私は自分でこの問題を抱えていました。 Devel::Modlist (この回答で示唆されているように) は動的なアプローチを採用しています。スクリプトの特定の実行中に実際にロードされたモジュールを報告します。これは何らかの方法でロードされたモジュールをキャッチしますが、条件付きの要件をキャッチできない場合があります。つまり、次のようなコードがある場合:
if ($some_condition) { require Some::Module }
$some_condition
たまたま false であり、要件としてDevel::Modlist
リストされません。Some::Module
代わりにModule::ExtractUseを使用することにしました。Some::Module
静的分析を行います。つまり、上記の例では常にキャッチされます。一方、次のようなコードについては何もできません。
my $module = "Other::Module";
eval "use $module;";
もちろん、両方のアプローチを使用して、2 つのリストを結合することもできます。
とにかく、これが私が思いついた解決策です:
#! /usr/bin/perl
#---------------------------------------------------------------------
# Copyright 2008 Christopher J. Madsen <perl at cjmweb.net>
#
# This program is free software; you can redistribute it and/or modify
# it under the same terms as Perl itself.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either the
# GNU General Public License or the Artistic License for more details.
#
# Recursively collect dependencies of Perl scripts
#---------------------------------------------------------------------
use strict;
use warnings;
use File::Spec ();
use Module::CoreList ();
use Module::ExtractUse ();
my %need;
my $core = $Module::CoreList::version{'5.008'};
# These modules have lots of dependencies. I don't need to see them now.
my %noRecurse = map { $_ => 1 } qw(
Log::Log4perl
XML::Twig
);
foreach my $file (@ARGV) {
findDeps($file);
}
foreach my $module (sort keys %need) {
print " $module\n";
}
#---------------------------------------------------------------------
sub findDeps
{
my ($file) = @_;
my $p = Module::ExtractUse->new;
$p->extract_use($file);
foreach my $module ($p->array) {
next if exists $core->{$module};
next if $module =~ /^5[._\d]+/; # Ignore "use MIN-PERL-VERSION"
next if $module =~ /\$/; # Run-time specified module
if (++$need{$module} == 1 and not $noRecurse{$module}) {
my $path = findModule($module);
if ($path) { findDeps($path) }
else { warn "WARNING: Can't find $module\n" }
} # end if first use of $module
} # end foreach $module used
} # end findDeps
#---------------------------------------------------------------------
sub findModule
{
my ($module) = @_;
$module =~ s!::|\'!/!g;
$module .= '.pm';
foreach my $dir (@INC) {
my $path = File::Spec->catfile($dir, $module);
return $path if -f $path;
}
return;
} # end findModule
次のように実行します。
perl finddeps.pl scriptToCheck.pl otherScriptToCheck.pl
リストされたスクリプトを実行するために必要なすべての非コア モジュールのリストを出力します。(Module::ExtractUse がそれらを認識できないように、モジュールの読み込みで巧妙なトリックを実行しない限り。)