[devel] I: perl.req vs BEGIN

Alexey Tourbin =?iso-8859-1?q?at_=CE=C1_altlinux=2Eru?=
Пт Авг 15 16:12:10 MSD 2008


On Fri, Aug 15, 2008 at 04:00:14PM +0400, Alexey Gladkov wrote:
> Пишу сюда, чтобы разметить возможную 
> граблю. Нарвался тут при сборке
> пакета с такой ошибкой:
> 
> /usr/lib/groff/groffer is not an existing directory; at 
> /tmp/groff-buildroot/usr/bin/groffer line 145.
> BEGIN failed--compilation aborted at /tmp/groff-buildroot/usr/bin/groffer 
> line 167.
> # perl(func.pl) at line 157 (depth 5) not loaded at BEGIN SKIP
> # perl(man.pl) at line 158 (depth 5) not loaded at BEGIN SKIP
> /tmp/groff-buildroot/usr/bin/groffer: deparse failed. 
> isPerl=0.0409154403404476.
> find-requires: ERROR: /usr/lib/rpm/perl.req failed
> 
> Ошибка несколько интересная. Смотрим в 
> код утилиты groffer:
> 
> BEGIN {
> ...
>    die "$groffer_libdir is not an existing directory;"
>      unless -d $groffer_libdir;
> 
>    unshift(@INC, $groffer_libdir);
> ...
>    require 'func.pl';
>    require 'man.pl';
> ...
> }
> 
> Как видно во время проверки зависимостей 
> реально отработал код скрипта и
> разумеется вышел с ошибкой, и этим 
> завалил сборку пакета.
> 
> После консультаций с at@, выяснилось, что 
> блок BEGIN отрабатывает в perl
> *всегда*... даже при syntax check.

Блок BEGIN выполняется всегда и ASAP (прямо во время чтения кода),
потому что одно из его назначений -- повлиять на синтаксис последующего
кода.  Например, в перле можно вызывать функции без скобок.  Для этого
до того, как прел начал парсить вызов функции без скобок, он уже должен
знать, какие названия функций существуют.

Директива "use" импортирует названия функций на стадии BEGIN.

$ perl -e 'use Carp qw(croak); croak "oh my"'                 
oh my at -e line 1
$

Вызов без скобок возможен только за счёт того, что когда перл парсил
croak, то он уже знал, что существует такая функция croak (которая была
импортирована с помощью use), и поэтому он "понял", что это на самом
деле вызов функции.

$ perl -e 'require Carp; Carp->import("croak"); croak "oh my"' 
String found where operator expected at -e line 1, near "croak "oh my""
        (Do you need to predeclare croak?)
syntax error at -e line 1, near "croak "oh my""
Execution of -e aborted due to compilation errors.
$ perl -e 'require Carp; Carp->import("croak"); croak("oh my")'
oh my at -e line 1
$ 

> Таким образом, хочу предостеречь всех 
> кто пакует перловые скрипты: если у вас в 
> скрипте есть блок BEGIN, то будьте готовы, 
> что он выполнится нашим rpm во время 
> сборки.
> 
> Как варианты обхода:
> 1) Заменить BEGIN на обычный блок (если в нём 
> есть проверки, как
>   в моём случае).
> 2) Отключить поиск зависимостей в перл 
> скриптах :)

Обычно не следует выполнять прикладной код в BEGIN.
BEGIN зарезервирован для всяких хитрых штук.

Одна из таких хитрых штук называется use.
Согласно 'perldoc -f use', выражение
	use Module LIST;
полностью эквивалентно
	BEGIN { require Module; Module->import( LIST ); }
----------- следующая часть -----------
Было удалено вложение не в текстовом формате...
Имя     : =?iso-8859-1?q?=CF=D4=D3=D5=D4=D3=D4=D7=D5=C5=D4?=
Тип     : application/pgp-signature
Размер  : 197 байтов
Описание: =?iso-8859-1?q?=CF=D4=D3=D5=D4=D3=D4=D7=D5=C5=D4?=
Url     : <http://lists.altlinux.org/pipermail/devel/attachments/20080815/70ea65f9/attachment-0002.bin>


Подробная информация о списке рассылки Devel