为什么 Perl 调试器不以 do 停止在断点处,而是以 require 停止



在Eclipse中使用Perl EPIC调试器时,为什么执行不是在"do"模块中的断点处停止,而是在"require"模块处停止?

script.pl

use strict;
#use sample;         # <-- Execution stops at breakpoint in printMessage() of 'sample.pm'
#require sample;     # <-- Execution stops at breakpoint in printMessage() of 'sample.pm'
#do 'sample.pm';     # <-- Execution DO NOT STOP at breakpoint in printMessage() of 'sample.pm'
sample::printMessage();

sample.pm

package sample;
sub printMessage
{
    print 'new message!';   
}
1;

我在Komodo IDE和命令行上尝试了这个,得到了相同的结果。

如果你userequire一个文件,Perl 会保留文件名%INC。这可确保文件仅加载一次。您可以在许多不同的其他模块中require相同的模块,并使用sample::printMessage()等功能。将完成第一个require,所有其他将被忽略,因为%INC中已经有一个关键$INC{'sample'} = './sample.pm'

require sample;
require sample;
require sample;
sample::printMessage();
__END__
new message!

如果您use模块而不是require它,则同样适用,因为use只是BEGIN块中的requireimport。在这两种情况下,Perl 都记得这一点。我的假设(没有找到证明这一点的文档)是,调试器能够做同样的事情,甚至读取内部%INC

现在,如果您do文件,则不会触发该%INC机制,这意味着您可以一遍又一遍地do该文件。它不关心文件名。这样做的后果是,如果您多次do文件,即使没有use warnings,它也会抱怨。

do 'sample.pm';
do 'sample.pm';
do 'sample.pm';
__END__
Subroutine printMessage redefined at sample.pm line 4.
Subroutine printMessage redefined at sample.pm line 4.
new message!

我的猜测是调试器也不记得了,因此它不知道它已经加载了sample.pm。文档说:

使用 EXPR 的值作为文件名并执行 文件作为 Perl 脚本。

do 'stat.pl';

很大程度上像

eval `cat stat.pl`;

因此,它只在文件中啜饮并执行内容。没有%INC .调试器没有文件名(顺便说一下,它在EPIC中的调试器与Komodo IDE中的调试器在命令行上相同,图形的只是连接到Perl调试器)。因此,当代码显示 do 时,将忽略您的断点。

如果希望调试器在 sample.pm 的第 5 行停止,即使你do它,也可以通过向上面的行添加 $DB::single = 1; 来告诉调试器执行此操作。

package sample;
sub printMessage
{
    $DB::single = 1;
    print 'new message!';
}

这在perldebug中记录。它将使调试器在下一行停止,相当于在调试器中键入 s,或单击 EPIC 调试器中的单步按钮。


另请参阅:

  • Perlvar for %INC
  • 用于命令行调试器的 perldebug
  • 关于CPAN的 perl5db.pl