Как создается Perl @INC? (ака, как все это влияет на поиск модулей Perl?)

199

Какие есть способы повлиять на поиск модулей Perl? или, как устроен Perl @INC ?

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

Похоже, что в StackOverflow нет подробного поста типа «@INC», поэтому этот вопрос задуман как один.

DVK
источник
7
Да, но есть очень хороший на search.cpan.org/perldoc/… ?
моб
3
@mobrule: Я не думаю, что это будет настолько всеобъемлющим - он просто говорит о том, как добавить @INCво время выполнения, а не о полной конструкции.
Каскабель
2
@mobrule - @Jefromi угадал правильно - главная проблема с ЛЮБОЙ и всеми ссылками, которые я нашел до сих пор, была нехваткой исчерпывающей информации о скомпилированном по умолчанию в Perl двоичном файле @INC
DVK
3
Некоторые могут сделать этот ответ всеобъемлющим, отправив мне патч. Это легко, потому что perlfaq находится в Github. :)
Брайан Д. Фой
1
Что ж, «всесторонняя информация о скомпилированном по умолчанию в perl-файле @INC» заключается в том, что именно его скомпилировал тот, кто его скомпилировал. Если вы спрашиваете о различных путях, которые идут туда, то я думаю, что у вас другой вопрос, чем тот, на который вы ответили.
Брайан Д. Фой

Ответы:

254

Мы посмотрим, как сконструировано содержимое этого массива, и с его помощью можно повлиять на то, где интерпретатор Perl найдет файлы модуля.

  1. По умолчанию @INC

    Perl-интерпретатор компилируется с определенным @INCзначением по умолчанию . Чтобы узнать это значение, запустите env -i perl -Vкоманду ( env -iигнорирует PERL5LIBпеременную окружения - см. # 2) и в выходных данных вы увидите что-то вроде этого:

    $ env -i perl -V
    ...
    @INC:
     /usr/lib/perl5/site_perl/5.18.0/x86_64-linux-thread-multi-ld
     /usr/lib/perl5/site_perl/5.18.0
     /usr/lib/perl5/5.18.0/x86_64-linux-thread-multi-ld
     /usr/lib/perl5/5.18.0
     .

Примечание .в конце; это текущий каталог (который не обязательно совпадает с каталогом скрипта). Он отсутствует в Perl 5.26+ и при работе с Perl -T(проверка на заражение включена) .

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

Configure -Dotherlibdirs=/usr/lib/perl5/site_perl/5.16.3

  1. Экологическая переменная PERL5LIB(или PERLLIB)

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

    $ perl -V
    ...
    %ENV:
      PERL5LIB="/home/myuser/test"
    @INC:
     /home/myuser/test
     /usr/lib/perl5/site_perl/5.18.0/x86_64-linux-thread-multi-ld
     /usr/lib/perl5/site_perl/5.18.0
     /usr/lib/perl5/5.18.0/x86_64-linux-thread-multi-ld
     /usr/lib/perl5/5.18.0
     .
  2. -I опция командной строки

    Perl предварительно ожидает @INCсписок каталогов (разделенных двоеточиями), переданных в качестве значения параметра -Iкомандной строки. Это можно сделать тремя способами, как обычно, с помощью параметров Perl:

    • Передайте это в командной строке:

      perl -I /my/moduledir your_script.pl
    • Передайте его через первую строку (shebang) вашего скрипта Perl:

      #!/usr/local/bin/perl -w -I /my/moduledir
    • Передайте его как часть PERL5OPT(или PERLOPT) переменной окружения (см. Главу 19.02 в Программирование на Perl )

  3. Передайте это через libпрагму

    Perl предварительно ожидает @INCсписок каталогов, переданных ему черезuse lib .

    В программе:

    use lib ("/dir1", "/dir2");

    В командной строке:

    perl -Mlib=/dir1,/dir2

    Вы также можете удалить каталоги с @INCпомощьюno lib .

  4. Вы можете напрямую манипулировать @INCкак обычный массив Perl.

    Примечание: поскольку @INCиспользуется на этапе компиляции, это должно быть сделано внутри BEGIN {}блока, который предшествует use MyModuleоператору.

    • Добавить каталоги в начало через unshift @INC, $dir.

    • Добавить каталоги до конца через push @INC, $dir.

    • Сделайте что-нибудь еще, что вы можете сделать с массивом Perl.

Примечание: каталоги сдвинут на @INCв порядке , указанном в этом ответе, например , по умолчанию @INCявляется последним в списке, которым предшествуют PERL5LIB, которому предшествует -I, предшествует use libи прямой@INC манипуляции, последние два смешиваться в зависимости от того , заказать их в коде Perl.

Ссылки:

Там не кажется всеобъемлющим @INC переполнении стека нет поста типа FAQ, поэтому этот вопрос задуман как один.

Когда использовать каждый подход?

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

  • Если модули в каталоге будут использоваться исключительно конкретным пользователем для всех сценариев, которые запускает пользователь (или если перекомпиляция Perl не является опцией для изменения значения @INCпо умолчанию в предыдущем случае использования), установите пользователей PERL5LIB, обычно при входе пользователя в систему.

    Примечание: Пожалуйста, имейте в виду обычные подводные камни переменных среды Unix - например, в некоторых случаях запуск сценариев от имени конкретного пользователя не гарантирует запуск их с настройкой среды этого пользователя, например, через su.

  • Если модули в каталоге необходимо использовать только при определенных обстоятельствах (например, когда сценарии выполняются в режиме разработки / отладки, вы можете установить их PERL5LIBвручную или передать -Iпараметр perl.

  • Если модули нужно использовать только для определенных сценариев, все пользователи, использующие их, используют use lib/ no libpragmas в самой программе. Его также следует использовать, когда каталог, который необходимо найти, должен быть динамически определен во время выполнения - например, из параметров командной строки сценария или пути сценария (см. Очень хороший пример использования в модуле FindBin ).

  • Если каталогами @INCнужно манипулировать в соответствии с какой-то сложной логикой, которую невозможно или слишком громоздко реализовать с помощью комбинации use lib/ no libпрагм, то используйте прямое @INCманипулирование внутри BEGIN {}блока или внутри специальной библиотеки, предназначенной для@INC манипуляции, которая должна использоваться вашим сценарием (s) перед использованием любых других модулей.

    Примером этого является автоматическое переключение между библиотеками в каталогах prod / uat / dev, с водопадной библиотекой в ​​prod, если она отсутствует в dev и / или UAT (последнее условие усложняет стандартное решение "use lib + FindBin". A подробные иллюстрации этого сценария в Как использовать бета - модули Perl из бета - скриптов на Perl? .

  • Дополнительный вариант использования для прямого манипулирования @INC- это возможность добавлять ссылки на подпрограммы или ссылки на объекты (да, Вирджиния @INCможет содержать собственный код Perl, а не только имена каталогов, как объясняется в разделе Когда вызывается ссылка на подпрограмму в @INC? ).

DVK
источник
1
не забудьте PERLOPT, где вы можете установить -I. Кроме того, такие вещи, как base.pm и local :: lib, используют вещи, которые вы перечислили неявно.
Брайан Д. Фой
1
@brian - use :: base использует его из-за «require» внизу, IIRC. Я не знаком с local :: lib, мне нужно будет прочитать больше, чтобы понять, о чем это
DVK
3
Кроме того, чтобы сделать это действительно хорошим ответом, вы должны сказать людям, когда они должны использовать каждый из них. Просто дать им 10 вариантов того, как они могли бы, не очень полезно. :)
Брайан Д. Фой
PS Любой, пожалуйста, не стесняйтесь редактировать ответ, включив в него включение второй директории для конкретной архитектуры через -I / use lib. Я планировал сделать это позже, но сейчас мне нужно отключиться.
ДВК
@brian - добавил PERLOPT. Мне хочется упомянуть base.pm и другие элементы «когда @INC привыкнут», которые больше подходят для часто задаваемых вопросов по файлам @ INC / find module, которые я разместил здесь и на которые дал ссылки, поэтому я поместил их туда.
ДВК
18

В дополнение к местам, перечисленным выше, версия Perl для OS X также имеет еще два способа:

  1. Файл /Library/Perl/x.xx/AppendToPath. Пути, перечисленные в этом файле, добавляются к @INC во время выполнения.

  2. Файл /Library/Perl/x.xx/PrependToPath. Пути, перечисленные в этом файле, добавляются к @INC во время выполнения.

dgatwood
источник
6

Как уже было сказано, @INC - это массив, и вы можете добавлять все, что захотите.

Мой скрипт CGI REST выглядит так:

#!/usr/bin/perl
use strict;
use warnings;
BEGIN {
    push @INC, 'fully_qualified_path_to_module_wiht_our_REST.pm';
}
use Modules::Rest;
gone(@_);

Ушедшая подпрограмма экспортируется Rest.pm.

Качпер Першке
источник