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

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

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

В StackOverflow не существует подробного сообщения типа "@INC" для часто задаваемых вопросов, поэтому этот вопрос предназначен как один.

Ответ 1

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

  • По умолчанию @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 запускается с -T (проверки проверки taint).

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

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

  • Экологическая переменная 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
     .
    
  • -I опция командной строки

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

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

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

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

  • Передайте его через lib прагма

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

    В программе:

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

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

    perl -Mlib=/dir1,/dir2
    

    Вы также можете удалить каталоги из @INC через no lib.

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

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

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

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

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

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

Ссылки:

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

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

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

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

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

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

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

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

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

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

Ответ 2

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

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

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

Ответ 3

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

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

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

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