Как программа Perl знает, где найти файл, содержащий модуль Perl, который он использует?

Если моя программа Perl использует модули Perl, как определить, где найти файл, содержащий код модуля?

Например, если программа содержит:

use MyModule1;              # Example 1
use This::Here::MyModule2;  # Example 2

где он будет выглядеть?

Ответ 1

Perl-интерпретатор (который запускает вашу программу perl) будет использовать специальный массив с именем @INC для поиска файла, содержащего модуль.

Каждое значение в массиве @INC - это имя каталога (но см. примечание ниже); Perl будет искать в этих каталогах в цикле, используя правила, указанные ниже. (Обратитесь к этому сообщению SO, чтобы узнать, как определяется содержимое @INC).

Если файл модуля не найден после исчерпания @INC, компиляция программы будет прервана с ошибкой. Если файл модуля находится в одном из каталогов, указанных в @INC, поиск завершен, не глядя на остальную часть @INC.

Как Perl ищет файл модуля в каждом из каталогов, перечисленных в @INC, выглядит следующим образом:

  • Сначала он будет разделять иерархические компоненты имени модуля (слова, разделенные символом ::), в последний компонент, который будет использоваться для формирования имени файла, и путь иерархии (все компоненты, предшествующие последний ::).

    Если имя модуля имеет только один компонент (нет ::, например MyModule1 выше), путь иерархии пуст, а имя файла - это имя модуля. Во втором примере в этом вопросе последний компонент MyModule2, а путь иерархии будет This::Here.

  • Ожидаемое имя файла будет определено путем добавления последнего компонента имени модуля с расширением .pm. Например. MyModule1.pm и MyModule2.pm в наших примерах.

    ПРИМЕЧАНИЕ. Имена модулей, очевидно, чувствительны к регистру в Unix и других операционных системах, где имена файлов/каталогов чувствительны к регистру.

  • Каталог модулей будет определяться:

    • Взяв следующий каталог из @INC - скажем /usr/lib/perl в качестве примера

    • Формирование подкаталога этого каталога путем выбора пути иерархии имени модуля (если есть) и замены "::" на / или любого другого символа, который операционная система использует как разделитель каталога. В наших двух примерах первый модуль будет искать в /usr/lib/perl (без подкаталога), а второй в /usr/lib/perl/This/Here.

    • ПРИМЕЧАНИЕ: приведенное выше небольшое упрощение - @INC может также содержать ссылки на подпрограммы и ссылки на объекты, которые загружают модули, поскольку их пользовательский код указывает вместо выполнения поиска в каталоге, как указано в логике № 2 выше. Эта функциональность очень редко используется, и в этой статье предполагается, что целые @INC содержат только каталоги.

Перейдите к конкретному примеру, предположив, что ваш @INC содержит два подкаталога: ("/usr/lib/perl", "/opt/custom/lib").

Затем Perl будет искать следующее:

==========================================================================
| Module                | Try # | File to try               
==========================================================================
| MyModule1             | Try 1 | /usr/lib/perl/MyModule1.pm
| MyModule1             | Try 2 | /opt/custom/lib/MyModule1.pm
==========================================================================
| This::Here::MyModule2 | Try 1 | /usr/lib/perl/This/Here/MyModule2.pm
| This::Here::MyModule2 | Try 2 | /opt/custom/lib/This/Here/MyModule2.pm
==========================================================================

Напомним, что интерпретатор Perl будет пытаться выполнить поиск, как только он найдет файл в одном из мест, не пытаясь определить, находится ли файл в последующих местах. Например. если /usr/lib/perl/This/Here/MyModule2.pm существует, то Perl не будет искать и не заботится о существовании /opt/custom/lib/This/Here/MyModule2.pm.

ПРИМЕЧАНИЕ. @INC используется всякий раз, когда интерпретатор Perl использует require -подобный механизм для импорта модулей Perl. Это включает в себя:

  • require сама директива
  • use MyModule (эквивалент require + import)
  • use base (эквивалентно запросу + "push @ISA" )

Ответ 2

Хотя это прямо не отвечает на вопрос, вот несколько простых методов для определения полного пути к файлу модуля, который вы хотите использовать.

Чтобы просмотреть содержимое по умолчанию массива @INC вместе с большим количеством другой информации из командной строки:

perl -V      

Если вы хотите узнать расположение модуля Carp:

perldoc -l Carp

Внутри script печать содержимого %INC хеша полезна для определения фактического модуля, который вы используете, особенно если вы изменили @INC по умолчанию:

use Carp;
print $INC{'Carp.pm'};

Этот простой script также можно использовать для Найти установленные модули Perl, соответствующие регулярному выражению, и идентифицировать любые дублирующие модули в разных каталогах.

Ответ 3

В соответствии с документацией perlfunc на use:

использовать LIST

Импортирует некоторую семантику в текущий пакет из именованного модуля, как правило, путем наложения определенных подпрограмм или имен переменных в ваш пакет. Это в точности эквивалентно

BEGIN { require Module; Module->import( LIST ); }

за исключением того, что модуль должен быть дельным.

Итак, require делает тяжелый подъем, а require документации предоставляет

Если EXPR - это годовое слово, требуется принять расширение ".pm" и заменяет "::" на "/" в имени файла для вас, чтобы упростить загрузку стандартных модулей. Эта форма загрузки модулей не подвержена изменению вашего пространства имен.

Другими словами, если вы попробуете это:

   require Foo::Bar;    # a splendid bareword

Функция require фактически ищет файл "Foo/Bar.pm" в каталогах, указанных в массиве @INC.