Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convince Devel::Trace to print the BEGIN-block statements?

Tags:

perl

Have a simple script p.pl:

use strict;
use warnings;
our $x;
BEGIN {
    $x = 42;
}
print "$x\n";

When I run it as:

perl -d:Trace p.pl

prints:

>> p.pl:3: our $x;
>> p.pl:7: print "$x\n";
42

how to get printed the BEGIN block statements too, e.g. the $x = 42;?

Because my intention isn't clear, adding the clarification:

Looking for ANY way to print statements when the perl script runs (like Devel::Trace it does) but including the statements in the BEGIN block.

like image 364
kobame Avatar asked Jul 01 '15 13:07

kobame


Video Answer


2 Answers

It's very possible. Set $DB::single in an early BEGIN block.

use strict;
use warnings;
our $x;
BEGIN { $DB::single = 1 }

BEGIN {
    $x = 42;
}
print "$x\n";

$DB::single is a debugger variable used to determine whether the DB::DB function will be invoked at each line. In compilation phase it is usually false but you can set it in compilation phase in a BEGIN block.

This trick is also helpful to set a breakpoint inside a BEGIN block when you want to debug compile-time code in the standard debugger.

like image 59
mob Avatar answered Oct 02 '22 05:10

mob


Disclaimer: This is just an attempt to explain the behaviour.


Devel::Trace hooks up to the Perl debugging API through the DB model. That is just code. It installs a sub DB::DB.

The big question is, when is that executed. According to perlmod, there are five block types that are executed at specific points during execution. One of them is BEGIN, which is the first.

Consider this program.

use strict;
use warnings;
our ($x, $y);

BEGIN { $x = '42' }
UNITCHECK { 'unitcheck' }
CHECK { 'check' }
INIT { 'init' }
END { 'end' }

print "$x\n";

This will output the following:

>> trace.pl:8: INIT { 'init' }
>> trace.pl:3: our ($x, $y);
>> trace.pl:11: print "$x\n";
42
>> trace.pl:9: END { 'end' }

So Devel::Trace sees the INIT block and the END block. But why the INIT block?

Above mentioned perlmod says:

INIT blocks are run just before the Perl runtime begins execution, in "first in, first out" (FIFO) order.

Apparently at that phase, the DB::DB has already been installed. I could not find any documentation that says when a sub definition is run exactly. However, it seems it's after BEGIN and before INIT. Hence, it does not see whatever goes on in the BEGIN.

Adding a BEGIN { $Devel::Trace::TRACE = 1 } to the beginning of the file also does not help.

I rummaged around in documentation for perldebug and the likes, but could not find an explanation of this behaviour. My guess is that the debugger interface doesn't know about BEGIN at all. They are executed very early after all (consider e.g. perl -c -E 'BEGIN{ say "foo" } say "bar"' will print foo.)

like image 28
simbabque Avatar answered Oct 02 '22 05:10

simbabque