“查找未使用的”;使用';d";Perl模块
我正在研究一个非常大、非常古老的“历史发展”代码库。在过去,经常有人会想“哦,我可能需要这个和那个模块,所以我只是把它包括进来…”,后来,人们经常在模块中“缓存”数据(“使用这个和那个”需要几秒钟才能从DB加载几百MB到RAM,是的,这真是一个愚蠢的想法,我们也在做这件事),所以,经常,我们有一个小模块使用,比如20或30个模块,其中90%的模块在源代码中完全未使用,而且,由于在几个使用过的子模块中进行“缓存”,模块往往需要花费一分钟甚至更多的时间来加载,这当然是不可接受的 所以,我正在努力把这件事做得更好。现在,我的方法是浏览所有模块,尽可能多地理解它们,然后查看包括它们在内的所有模块,看看它们是否需要 有没有更简单的方法?我的意思是:有函数返回一个模块的所有子模块“查找未使用的”;使用';d";Perl模块,perl,module,Perl,Module,我正在研究一个非常大、非常古老的“历史发展”代码库。在过去,经常有人会想“哦,我可能需要这个和那个模块,所以我只是把它包括进来…”,后来,人们经常在模块中“缓存”数据(“使用这个和那个”需要几秒钟才能从DB加载几百MB到RAM,是的,这真是一个愚蠢的想法,我们也在做这件事),所以,经常,我们有一个小模块使用,比如20或30个模块,其中90%的模块在源代码中完全未使用,而且,由于在几个使用过的子模块中进行“缓存”,模块往往需要花费一分钟甚至更多的时间来加载,这当然是不可接受的 所以,我正在努力把这
...
return grep { defined &{"$module\::$_"} } keys %{"$module\::"}
,那么,是否有任何简单的方法可以查看默认情况下哪些是导出的,哪些是从何处来的,哪些是在其他模块中使用的
一个简单的例子是Data::Dumper,它几乎包含在每个文件中,即使脚本中不再包含所有调试警告和打印等内容。但模块仍然必须加载Data::Dumper
有什么简单的方法来检查吗
谢谢 以下代码可能是您的解决方案的一部分-它将显示为
使用的每个实例导入的符号:
package traceuse;
use strict;
use warnings;
use Devel::Symdump;
sub import {
my $class = shift;
my $module = shift;
my $caller = caller();
my $before = Devel::Symdump->new($caller);
my $args = \@_;
# more robust way of emulating use?
eval "package $caller; require $module; $module\->import(\@\$args)";
my $after = Devel::Symdump->new($caller);
my @added;
my @after_subs = $after->functions;
my %before_subs = map { ($_,1) } $before->functions;
for my $k (@after_subs) {
push(@added, $k) unless $before_subs{$k};
}
if (@added) {
warn "using module $module added: ".join(' ', @added)."\n";
} else {
warn "no new symbols from using module $module\n";
}
}
1;
然后,只需将“use module…”替换为“use traceuse module…”,您将获得已导入函数的列表
用法示例:
package main;
sub foo { print "debug: foo called with: ".Dumper(\@_)."\n"; }
use traceuse Data::Dumper;
这将输出:
using module Data::Dumper added: main::Dumper
i、 e.您可以知道哪些函数以健壮的方式导入。您可以轻松地将其扩展到报告导入的标量、数组和散列变量—查看Devel::Symdump
上的文档
确定实际使用的函数是等式的另一半。为此,您可能可以对源代码进行简单的grep,即Dumper
是否出现在模块的源代码中,而不是use
行中。这取决于您对源代码的了解
注:
- 可能有一个模块可以完成traceuse的功能-我还没有检查
- 可能有更好的方法来模拟另一个包的“使用”
我有点习惯于使用PPI。看起来是这样的:
#!/usr/local/bin/perl
use strict;
use warnings;
use Data::Dumper;
use Term::ANSIColor;
use PPI;
use PPI::Dumper;
my %doneAlready = ();
$" = ", ";
our $maxDepth = 2;
my $showStuffOtherThanUsedOrNot = 0;
parse("/modules/Test.pm", undef, undef, 0);
sub parse {
my $file = shift;
my $indent = shift || 0;
my $caller = shift || $file;
my $depth = shift || 0;
if($depth && $depth >= $maxDepth) {
return;
}
return unless -e $file;
if(exists($doneAlready{$file}) == 1) {
return;
}
$doneAlready{$file} = 1;
my $skript = PPI::Document->new($file);
my @included = ();
eval {
foreach my $x (@{$skript->find("PPI::Statement::Include")}) {
foreach my $y (@{$x->{children}}) {
push @included, $y->{content} if (ref $y eq "PPI::Token::Word" && $y->{content} !~ /^(use|vars|constant|strict|warnings|base|Carp|no)$/);
}
}
};
my %double = ();
print "===== $file".($file ne $caller ? " (Aufgerufen von $caller)" : "")."\n" if $showStuffOtherThanUsedOrNot;
if($showStuffOtherThanUsedOrNot) {
foreach my $modul (@included) {
next unless -e createFileName($modul);
my $is_crap = ((exists($double{$modul})) ? 1 : 0);
print "\t" x $indent;
print color("blink red") if($is_crap);
print $modul;
print color("reset") if($is_crap);
print "\n";
$double{$modul} = 1;
}
}
foreach my $modul (@included) {
next unless -e createFileName($modul);
my $anyUsed = 0;
my $modulDoc = parse(createFileName($modul), $indent + 1, $file, $depth + 1);
if($modulDoc) {
my @exported = getExported($modulDoc);
print "Exported: \n" if(scalar @exported && $showStuffOtherThanUsedOrNot);
foreach (@exported) {
print(("\t" x $indent)."\t");
if(callerUsesIt($_, $file)) {
$anyUsed = 1;
print color("green"), "$_, ", color("reset") if $showStuffOtherThanUsedOrNot;
} else {
print color("red"), "$_, ", color("reset") if $showStuffOtherThanUsedOrNot;
}
print "\n" if $showStuffOtherThanUsedOrNot;
}
print(("\t" x $indent)."\t") if $showStuffOtherThanUsedOrNot;
print "Subs: " if $showStuffOtherThanUsedOrNot;
foreach my $s (findAllSubs($modulDoc)) {
my $isExported = grep($s eq $_, @exported) ? 1 : 0;
my $rot = callerUsesIt($s, $caller, $modul, $isExported) ? 0 : 1;
$anyUsed = 1 unless $rot;
if($showStuffOtherThanUsedOrNot) {
print color("red") if $rot;
print color("green") if !$rot;
print "$s, ";
print color("reset");
}
}
print "\n" if $showStuffOtherThanUsedOrNot;
print color("red"), "=========== $modul wahrscheinlich nicht in Benutzung!!!\n", color("reset") unless $anyUsed;
print color("green"), "=========== $modul in Benutzung!!!\n", color("reset") if $anyUsed;
}
}
return $skript;
}
sub createFileName {
my $file = shift;
$file =~ s#::#/#g;
$file .= ".pm";
$file = "/modules/$file";
return $file;
}
sub getExported {
my $doc = shift;
my @exported = ();
eval {
foreach my $x (@{$doc->find("PPI::Statement")}) {
my $worthATry = 0;
my $isMatch = 0;
foreach my $y (@{$x->{children}}) {
$worthATry = 1 if(ref $y eq "PPI::Token::Symbol");
if($y eq '@EXPORT') {
$isMatch = 1;
} elsif($isMatch && ref($y) ne "PPI::Token::Whitespace" && ref($y) ne "PPI::Token::Operator" && $y->{content} ne ";") {
push @exported, $y->{content};
}
}
}
};
my @realExported = ();
foreach (@exported) {
eval "\@realExported = $_";
}
return @realExported;
}
sub callerUsesIt {
my $subname = shift;
my $caller = shift;
my $namespace = shift || undef;
my $isExported = shift || 0;
$caller = `cat $caller`;
unless($namespace) {
return 1 if($caller =~ /\b$subname\b/);
} else {
$namespace = createPackageName($namespace);
my $regex = qr#$namespace(?:::|->)$subname#;
if($caller =~ $regex) {
return 1;
}
}
return 0;
}
sub findAllSubs {
my $doc = shift;
my @subs = ();
eval {
foreach my $x (@{$doc->find("PPI::Statement::Sub")}) {
my $foundName = 0;
foreach my $y (@{$x->{children}}) {
no warnings;
if($y->{content} ne "sub" && ref($y) eq "PPI::Token::Word") {
push @subs, $y;
}
use warnings;
}
}
};
return @subs;
}
sub createPackageName {
my $name = shift;
$name =~ s#/modules/##g;
$name =~ s/\.pm$//g;
$name =~ s/\//::/g;
return $name;
}
这真的很难看,也许不是100%有效,但从我现在做的测试来看,这似乎是一个好的开始 这看起来非常棒,但遗憾的是,我没有得到任何输出。我准确地复制了它,但不知怎的,“导入”并没有被调用。我试着在里面死去,但没有结果。知道我做错了什么吗?把traceuse代码放进它自己的文件-traceuse.pm
(注意我刚才在末尾添加的1;
);然后perl-Mtraceuse=Data::Dumper-e1
应该会给您一些输出。您是否还有另一个traceuse.pm文件?如果您还没有,请不要忘记安装Devel::Symdump
。啊,现在它可以工作了。我只是“使用traceuse Data::Dumper”,它没有加载它。但是perl-Mtraceuse=Data::Dumper工作得非常好。谢谢,这个功能一定会派上用场的。