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

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

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

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

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

3 ответа

Решение

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

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

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

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

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

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

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

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

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

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

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

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

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

Тогда Perl будет искать следующее:

==========================================================================
| Модуль | Попробуйте # | Файл попробовать               
==========================================================================
| MyModule1             | Попробуйте 1 | /usr/lib/perl/MyModule1.pm
| MyModule1             | Попробуйте 2 | /opt/custom/lib/MyModule1.pm
==========================================================================
| Это:: Здесь::MyModule2 | Попробуйте 1 | /usr/lib/perl/This/Here/MyModule2.pm
| Это:: Здесь::MyModule2 | Попробуйте 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 оператор (эквивалентный запросу + импорт)
  • use base (эквивалентно + + push @ISA)
  • -M параметр командной строки

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

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

perl -V      

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

perldoc -l Carp

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

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

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

Согласно документации perlfunc наuse:

использовать модуль LIST

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

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

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

Так require делает тяжелую работу, а require документация обеспечивает

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

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

   require Foo::Bar;    # a splendid bareword

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

Другие вопросы по тегам