调试复杂的CPAN发行版时,如何定位子程序调用的源文件?



我正在尝试调试一个Tk程序一段时间了。问题似乎出在来自顶级窗口的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();
}

我首先尝试对子名称1的分布进行 grep:

  • 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步入匿名子例程时,它只是跨过它并返回到第 32 行test.pl.

我怀疑该方法必须以某种方式定义Tk::wm(因为它与窗口管理器有关),也许是通过自动加载机制或动态加载器?

脚注

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行显然是它被注入到相应符号表中的位置,因此可以通过$tl->deiconify()调用它。

最新更新