Как убедить Devel:: Trace распечатать инструкции BEGIN-блока?

У вас есть простой script p.pl:

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

Когда я запускаю его как:

perl -d:Trace p.pl

печатает:

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

как печатать также инструкции BEGIN block, например. $x = 42;?

Поскольку мое намерение не ясно, добавив пояснение:

Ищете ЛЮБОЙ способ распечатывать утверждения при запуске perl script (например, Devel:: Trace), но включая инструкции в блоке BEGIN.

Ответ 1

Это очень возможно. Установите $DB::single в раннем блоке BEGIN.

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

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

$DB::single - это отладочная переменная, используемая для определения того, будет ли функция DB::DB вызываться в каждой строке. На этапе компиляции это обычно неверно, но вы можете установить его на этапе компиляции в блоке BEGIN.

Этот трюк также полезен для установки точки останова внутри блока BEGIN, когда вы хотите отлаживать код времени компиляции в стандартном отладчике.

Ответ 2

Отказ от ответственности: это всего лишь попытка объяснить поведение.


Devel:: Trace подключается к API отладки Perl через модель DB. Это всего лишь код. Он устанавливает суб DB::DB.

Большой вопрос: когда это выполняется. Согласно perlmod, существует пять типов блоков, которые выполняются в определенных точках во время выполнения. Один из них BEGIN, который является первым.

Рассмотрим эту программу.

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

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

print "$x\n";

В результате вы получите следующее:

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

Итак, Devel:: Trace видит блок INIT и блок END. Но почему блок INIT?

Вышеупомянутый perlmod говорит:

Блоки INIT запускаются непосредственно перед началом выполнения Perl, в порядке "первый вход, первый выход" (FIFO).

По-видимому, на этой фазе DB::DB уже установлен. Я не мог найти документацию, которая говорит, когда определение sub выполняется точно. Однако, кажется, это после BEGIN и до INIT. Следовательно, он не видит, что происходит в BEGIN.

Добавление BEGIN { $Devel::Trace::TRACE = 1 } в начало файла также не помогает.

Я порылся в документации для perldebug и подобных, но не смог найти объяснения этого поведения. Я предполагаю, что интерфейс отладчика вообще не знает о BEGIN. Они выполняются очень рано в конце (рассмотрите, например, perl -c -E 'BEGIN{ say "foo" } say "bar"', напечатает foo.)