有没有办法事先报告Perl文件中使用的丢失模块,而不是出错。
我的Perl程序中有use Digest::MD5
,use File::DosGlob
个模块。每当用户运行脚本时,如果系统中没有安装特定模块,则会出现错误。他们无法理解@INC
给出的默认错误消息。所以我想清楚告诉他们需要安装这些模块来运行脚本。
答案 0 :(得分:5)
您可以使用Devel::Modlist,它会列出您的程序所需的所有模块。
perl -d:Modlist test.pl
还有另一个模块Module::ScanDeps,它带有一个实用程序scandeps.pl
,您可以在脚本上使用它:
scandeps.pl test.pl
请注意sanity checking your Perl code using perl -c
is dangerous,因此请谨慎使用。
答案 1 :(得分:5)
您可以使用a BEGIN
block建立自己的验证。这些是在编译时运行的,就像use
一样。请注意,use Foo
基本上没有其他内容:
BEGIN {
require Foo;
Foo->import;
}
以下代码会将所有use
语句替换为一个BEGIN
,并将其置于eval
内。这基本上就像try/catch机制。
我们需要字符串eval
(这里被认为是邪恶的),因为require
仅从冒号::
的包名转换为路径(如果参数为a bareword)。但由于我们在$module
中有名称,因此它是一个字符串,因此我们需要根据require
's docs将其放入eval
。
如果该字符串eval
失败,我们die
。由外eval
块和$@
捕获的内容已设置。然后我们可以检查它是否包含我们的模块名称,在这种情况下我们天真地假设失败是因为没有安装该模块。这项检查可能会更精细。
我们会跟踪$fails
中的任何失败,如果有失败,我们会停止。
#!/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;
}
# ...
上面我包括ASDF
,我没有,所以在运行时会说
您需要在/home/code/scratch.pl第1335行安装ASDF模块。
您可能希望使该消息更加冗长。如果您的用户无法理解Perl在无法找到模块时提供的默认错误消息,那么在其中包含有关如何安装内容的指南可能是明智之举。
请注意,您列出的两个模块都包含在a while的Perl中(读取:自2002年3月起)。那你为什么要为这些模块做这个呢?
$ 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
更好的方法是将程序作为可安装的发行版发布,并包含Makefile或cpanfile或列出依赖项的类似内容。 perlnewmod中有关于如何启动新模块的指南。您显然不想上传到CPAN,但基本内容是相同的。
有了这个,您的用户将自动安装所有依赖项。
答案 2 :(得分:1)
你的问题并不清楚“事先”是什么意思。要检查Perl程序的语法是否正确并且直接包含的模块是否可解析,请使用
perl -c <perl-program.pl>
这将检查文件的语法,并确保您的代码存在任何模块use
。但是,它不会传递检查整个依赖关系树,只会检查perl-program.pl
中提到的那些。