我有一个相当大的 Perl 程序,用 PAR::Packer 打包成可执行文件。它使用了相当多的模块。
通常,当 perl 给我一个警告时,比如使用未定义的值,它会打印错误的位置,然后很容易深入并调试它。
但是,我现在面临一个错误(我认为是在 5.22 中引入的),当发生这种情况时,我无法获取位置:
插入后在哈希上使用each()而不重置哈希迭代器会导致未定义的行为,Perl解释器:0xa94010
我尝试设置use warnings FATAL=>'all';
,但没有任何变化,程序不会终止。
也许它来自一个模块?我还能如何确定警告的位置?
最佳答案
warnings pragma 从一组给定类别中发出针对法律代码的警告。虽然 FATAL
将它们更改为 fatal error ,但它不会改变 warn
的工作方式。由于不知道这是如何发出的,因此重写 __WARN__ 钩子(Hook)很有可能会有所帮助
local $SIG{__WARN__} = \&Carp::confess; # or just die
或者您也可以仅删除本地
这一次。
要尝试的另一件事是覆盖 CORE::GLOBAL::warn
BEGIN { *CORE::GLOBAL::warn = sub { die } } # before use Module;
这也会影响模块,如果在模块之前的 BEGIN
中设置 __WARN__
信号也会影响模块。
请注意Carp::Always实现这一点,甚至更多。此外,它通常只需在运行程序时使用 -MCarp::Always
即可激活。感谢ikegami进行澄清。
参见warn和 %SIG hash in perlvar ,还有这个Effective Perler article .
最后,您对每个
有多少次调用?检查全部。
注释中解释说,打印来自 XS,是通过调试器找到的,但仍不清楚是什么代码触发了这一点。然后尝试将流tie
-ing到一个类,在相关文本上触发跟踪。一个最小的例子
TraceError.pm
package TraceError;
use warnings;
use strict;
use Carp qw(longmess confess);
sub TIEHANDLE { bless {} }
sub PRINT {
my $self = shift;
my $prn = join '', @_;
# print "STDERR: $prn"; # TEST
print @_; # or print STDERR @_;
# if ($prn =~ /\QUse of each() on hash after insertion/) # in your code
if ($prn =~ /TRACE/) { # test
print longmess(@_);
}
}
1;
更改为注释掉的 if
行,以便扫描打印件以查找错误消息的文本。下面的其余部分只是对此的测试。在代码中,您需要 main.pl
中的前两行来 use
这个类并将流(文件句柄)绑定(bind)到它,然后所有打印(到 STDERR
)都通过上面的 PRINT
进行。
main.pl
use TraceError;
tie *STDERR,'TraceError';
use warnings;
use strict;
use Pack qw(issue_warn);
call_for_err(Pack->new);
sub call_for_err {
my ($pck) = @_;
$pck->issue_warn("TRACE call_for_err()"); # should catch this print
$pck->issue_warn("from call_for_err()"); # but not this
};
Pack.pm
package Pack;
use warnings;
use strict;
use Exporter qw(import);
our @EXPORT_OK = qw(issue_warn);
sub new { bless {}, $_[0] }
sub issue_warn {
my $self = shift;
warn "In ", __PACKAGE__, ", issue_warn(@_).";
}
1;
输出
In Pack, issue_warn(TRACE, call_for_err()). at Pack.pm line 12. at Pack.pm line 12. Pack::issue_warn('Pack=HASH(0x7016e8)', 'TRACE call_for_err()') called at main.pl line 12 main::call_for_err('Pack=HASH(0x7016e8)') called at main.pl line 8
tie
-ing 类应该写得更好,首先要接受参数(要搜索的文本、要打印的流或句柄)。请参阅perltie和 Tie::Handle ,关于perlmonks的讨论,在 SO 上发布帖子,例如 this one ,尤其是 Camel(第 3 版)中的“绑定(bind)文件句柄”一章。
关于perl - 如何确定 Perl 警告的位置 - 插入后在哈希上使用each(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43059012/