在调试复杂的 CPAN 分发时如何定位子程序调用的源文件?
How to locate the source file of a subroutine call when debugging a complex CPAN distribution?
我正在尝试调试 Tk
程序一段时间。问题似乎出在来自顶层 window 的 deiconify()
调用,但是我无法找到定义 deiconify()
sub 的源文件。这是一个虚构的例子,只是为了说明我的意思:
test.pl:
use strict;
use warnings;
use Tk;
my $mw = MainWindow->new( -title => "Main Window" );
$mw->Label(-text => "Debugging", -font => "Times 20")->pack( );
$mw->Button(
-text => 'Quit',
-command => sub { exit },
)->pack;
$mw->Button(
-text => 'Show window',
-command => \&show_window,
)->pack;
my $tl = $mw->Toplevel( -title => "Toplevel 1" );
$tl->Button(
-text => 'Quit',
-command => sub { exit },
)->pack;
$tl->withdraw();
MainLoop;
sub show_window {
#$DB::single = 1;
$tl->deiconify(); # <--- Where is this sub defined??
$tl->raise();
}
我首先尝试 grep 子名称的分布1:
find . -name '*.pm' -exec grep -Hn deiconify {} \;
find . -name '*.xs' -exec grep -Hn deiconify {} \;
find . -name '*.al' -exec grep -Hn deiconify {} \;
find . -name '*.h' -exec grep -Hn deiconify {} \;
然后我尝试运行调试器下的脚本
perl -d test.pl
并在调用 $tl->deiconify()
之前设置一个断点(见上文)。当我在断点
处按下s
DB<1> s
Tk::Submethods::CODE(0x56245540c658)(/home/hakon/perlbrew/perls/perl-5.24.1/lib/site_perl/5.24.1/x86_64-linux/Tk/Submethods.pm:37):
37: *{$package.'::'.$sub} = sub { shift->$fn($sub,@_) };
它显示了 deiconify()
被定义为匿名子程序的行( Tk::Submethods
的第 37 行),但是当我再次按 s
进入匿名子程序时,它只是越过它 returns 到 test.pl
.
中的第 32 行
我怀疑该方法必须以某种方式在 Tk::wm
中定义(因为它与 Window 管理器有关)可能是由自动加载机制或动态加载器定义的?
脚注
1. 命令来自 Tk 发行版的顶级目录 运行。要设置它,运行 首先:
cpan -g Tk
tar zxvf Tk-804.033.tar.gz
cd Tk-804.033
更自由地搜索源代码(特别是包括 *.c
文件)在文件 pTk/mTk/win/tkWinWm.c
中找到字符串 This procedure is invoked to process the "wm deiconify" Tcl command
。它在介绍 C 函数的评论中 WmDeiconifyCmd
,看起来确实是该功能的实际实现。
我没有仔细研究 Tk 模块 XS 代码如何将 C 函数暴露给 Perl 级别,但如果那是您真正感兴趣的,您现在知道端点并且只需要填写在中间:-)
一旦将函数暴露给 Perl 级别,您在上面引用的 Tk::Submethods
中的行显然是将其注入适当符号 table 的位置,因此可以通过 $tl->deiconify()
.
我正在尝试调试 Tk
程序一段时间。问题似乎出在来自顶层 window 的 deiconify()
调用,但是我无法找到定义 deiconify()
sub 的源文件。这是一个虚构的例子,只是为了说明我的意思:
test.pl:
use strict;
use warnings;
use Tk;
my $mw = MainWindow->new( -title => "Main Window" );
$mw->Label(-text => "Debugging", -font => "Times 20")->pack( );
$mw->Button(
-text => 'Quit',
-command => sub { exit },
)->pack;
$mw->Button(
-text => 'Show window',
-command => \&show_window,
)->pack;
my $tl = $mw->Toplevel( -title => "Toplevel 1" );
$tl->Button(
-text => 'Quit',
-command => sub { exit },
)->pack;
$tl->withdraw();
MainLoop;
sub show_window {
#$DB::single = 1;
$tl->deiconify(); # <--- Where is this sub defined??
$tl->raise();
}
我首先尝试 grep 子名称的分布1:
find . -name '*.pm' -exec grep -Hn deiconify {} \;
find . -name '*.xs' -exec grep -Hn deiconify {} \;
find . -name '*.al' -exec grep -Hn deiconify {} \;
find . -name '*.h' -exec grep -Hn deiconify {} \;
然后我尝试运行调试器下的脚本
perl -d test.pl
并在调用 $tl->deiconify()
之前设置一个断点(见上文)。当我在断点
s
DB<1> s
Tk::Submethods::CODE(0x56245540c658)(/home/hakon/perlbrew/perls/perl-5.24.1/lib/site_perl/5.24.1/x86_64-linux/Tk/Submethods.pm:37):
37: *{$package.'::'.$sub} = sub { shift->$fn($sub,@_) };
它显示了 deiconify()
被定义为匿名子程序的行( Tk::Submethods
的第 37 行),但是当我再次按 s
进入匿名子程序时,它只是越过它 returns 到 test.pl
.
我怀疑该方法必须以某种方式在 Tk::wm
中定义(因为它与 Window 管理器有关)可能是由自动加载机制或动态加载器定义的?
脚注
1. 命令来自 Tk 发行版的顶级目录 运行。要设置它,运行 首先:
cpan -g Tk
tar zxvf Tk-804.033.tar.gz
cd Tk-804.033
更自由地搜索源代码(特别是包括 *.c
文件)在文件 pTk/mTk/win/tkWinWm.c
中找到字符串 This procedure is invoked to process the "wm deiconify" Tcl command
。它在介绍 C 函数的评论中 WmDeiconifyCmd
,看起来确实是该功能的实际实现。
我没有仔细研究 Tk 模块 XS 代码如何将 C 函数暴露给 Perl 级别,但如果那是您真正感兴趣的,您现在知道端点并且只需要填写在中间:-)
一旦将函数暴露给 Perl 级别,您在上面引用的 Tk::Submethods
中的行显然是将其注入适当符号 table 的位置,因此可以通过 $tl->deiconify()
.