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

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

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

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

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

Ответы [ 3 ]

13 голосов
/ 26 марта 2010

Интерпретатор 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 будет искать следующим образом:

==========================================================================
| 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")
  • -M параметр командной строки
5 голосов
/ 27 марта 2010

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

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

perl -V      

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

perldoc -l Carp

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

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

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

2 голосов
/ 26 марта 2010

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

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

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

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

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

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

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

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

   require Foo::Bar;    # a splendid bareword

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

...