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

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

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

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

где это будет смотреться?


person DVK    schedule 26.03.2010    source источник
comment
Я не смог найти исчерпывающий ответ на этот вопрос о SO, на который я мог бы ссылаться, поэтому решил создать его. Если приведенный ниже ответ требует дополнений / исправлений, просьба иметь при себе :)   -  person DVK    schedule 26.03.2010


Ответы (3)


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

Каждое значение в массиве @INC - это имя каталога (, но см. Примечание ниже); Perl будет искать в этих каталогах в цикле, используя правила, указанные ниже. (См. это сообщение SO для получения подробной информации о том, как определяется содержимое @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 инструкция (эквивалентно запросу + импорт)
  • use base (эквивалентно require + "push @ISA")
  • -M параметр командной строки
person Community    schedule 26.03.2010
comment
Наверное, стоит отметить, откуда взялось содержимое @INC. Это может быть даже ответ, который искал OP. Краткое резюме: основное содержимое по умолчанию является встроенным (точные сведения о путях, очевидно, зависят от вашей установки). Основные способы изменить его вне сценария - установить переменную среды PERL5LIB (список путей, разделенных двоеточиями) или предоставить -I/path/to/dir параметры исполняемому файлу во время выполнения. (Они добавляются к массиву) - person Cascabel; 26.03.2010
comment
У кого-нибудь есть хороший авторитетный список того, как именно устроен @INC? В perldoc perlvar, похоже, отсутствует какое-либо упоминание о PERL5LIB, а также о механизме $Config{sitelib}/sitecustomize.pl (который должен быть встроен во время компиляции). - person Cascabel; 26.03.2010
comment
@DVK: Отлично! Ошибочно предположили, что вы закончили, из-за комментария к вопросу и того факта, что это уже потрясающе тщательно. - person Cascabel; 26.03.2010
comment
не могли бы вы отметить этот CW, чтобы пользователи с низким уровнем репутации также могли редактировать свои ответы? - person Ether; 27.03.2010
comment
@Ether - Готово. У меня лавина репутации :(;) - person DVK; 27.03.2010
comment
@Jefromi - добавил ссылку на этот новый FAQ - person DVK; 27.03.2010
comment
Я также добавил ссылку на возможность иметь ссылки на подпрограммы и объекты в @INC - person DVK; 30.03.2010

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

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

perl -V      

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

perldoc -l Carp

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

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

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

person toolic    schedule 26.03.2010
comment
@toolic - этот ответ тесно связан с вопросом OP, но я считаю, что он несколько отличается от него (например, откуда взялся импортированный мной модуль). Не могли бы вы опубликовать его как отдельный вопрос + ответ на SO (я сделаю ссылку на него), или дать мне свое согласие задать его как отдельный вопрос и опубликовать свой ответ (или разрешить мне репостить ваш)? - person DVK; 27.03.2010
comment
Выполнено! stackoverflow.com/questions/2527990/ - person DVK; 27.03.2010
comment
@DVK - Если у меня есть две версии perl в переменной окружения пути Windows, то как система узнает, какой Perl выбрать? Это первая? У меня на машине установлены разные perl для разного программного обеспечения. Они были установлены вместе с программным обеспечением. - person stack1; 24.02.2015

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

использовать СПИСОК модулей

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

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

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

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

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

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

   require Foo::Bar;    # a splendid bareword

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

person Greg Bacon    schedule 26.03.2010