2010-03-26 2 views
13

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

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

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

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

+0

Я не смог найти исчерпывающий ответ на этот вопрос, на который я мог ссылаться, поэтому я решил создать его. Если приведенный ниже ответ нуждается в дополнениях/исправлениях, пожалуйста, имейте это в виду :) – DVK

ответ

13

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

Каждое значение в массиве @INC - это имя каталога (, но см. Примечание ниже); Perl будет искать в этих каталогах в цикле, используя правила, указанные ниже. (См. this SO post for details of how the contents of @INC are determined).

Если файл модуля не найден после исчерпания @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. ПРИМЕЧАНИЕ: выше небольшое упрощение - @INCmay also contain subroutine references and object references, который загружает модули, как их пользовательский код указывает вместо выполнения поиск в каталоге, как указано в # 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 (эквивалент требовать + "нажмите @ISA")
+2

Возможно, стоит отметить, откуда взялось содержимое @INC. Это может быть даже ответ, который ищет OP. Краткое описание: основное содержимое по умолчанию является встроенным (очевидно, точные сведения о путях зависят от вашей установки). Первичные способы изменить его вне вашего скрипта - установить переменную среды PERL5LIB (список путей, разделенных двоеточием) или предоставить опции -I/path/to/dir для исполняемого файла во время выполнения. (Они добавляются к массиву) – Cascabel

+0

У кого-нибудь есть хороший авторитетный список того, как именно построен @INC? В perldoc perlvar отсутствует упоминание PERL5LIB, а также механизм '$ Config {sitelib}/sitecustomize.pl' (который должен быть встроен во время компиляции). – Cascabel

+0

@ DVK: Отлично! Ошибочно полагал, что вы были сделаны из-за комментария к вопросу и того факта, что это уже ужасно основательно. – Cascabel

2

Согласно perlfunc documentation on use:

использование модуля LI ST

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

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

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

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

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

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

require Foo::Bar; # a splendid bareword 

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

5

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

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

perl -V  

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

perldoc -l Carp 

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

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

Этот простой сценарий также может быть использован для Find installed Perl modules matching a regular expression и выявления повторяющихся модулей в различных каталогах.

+0

@toolic - этот ответ тесно связан с OP, но я чувствую, что он несколько от него отделен (например, «откуда пришел модуль, из которого я импортировался»). Не могли бы вы либо опубликовать его как отдельный Q + A на SO (я свяжусь с ним), либо даю вам ваше согласие спросить его как отдельный вопрос Q и опубликовать ваш ответ (или позволить мне перепечатать ваш)? – DVK

+0

сделано! http://stackoverflow.com/questions/2527990/how-do-i-find-which-file-contains-perl-module-my-script-uses – DVK

+0

@DVK - Если у меня есть две версии perl в моем пути к окну переменная среды, то как система знает, какой perl выбрать? Это первый? У меня разные настройки для разных программ, установленных на моей машине. Они были установлены вместе с программным обеспечением. – stack1