Como o @INC do Perl é construído? (aka Quais são as formas de afetar onde os módulos Perl são pesquisados?)

199

Quais são todas as maneiras de afetar onde os módulos Perl são pesquisados? ou Como é construído o @INC do Perl ?

Como sabemos, o Perl usa uma @INCmatriz que contém nomes de diretório para determinar onde procurar arquivos de módulo Perl .

Não parece haver uma postagem abrangente do tipo "@INC" no StackOverflow, portanto, essa pergunta deve ser uma delas.

DVK
fonte
7
Sim, mas há uma perfeitamente boa em search.cpan.org/perldoc/… ?
mob
3
@mobrule: Eu não acho que isso seja tão abrangente - é apenas como adicionar ao @INCtempo de execução, não a construção completa.
Cascabel 26/03
2
@mobrule - @Jefromi adivinhou certo - o principal problema com todas e quaisquer referências que eu encontrei até agora foi a falta de informações abrangentes sobre perl do binário compilado-in padrão @INC
DVK
3
Alguns podem tornar essa resposta tão abrangente enviando-me um patch. É fácil porque o perlfaq está no Github. :)
brian d foy
1
Bem, a "informação abrangente sobre o @INC padrão compilado do perl binary é que é a pessoa que o compilou configurou. Se você está perguntando sobre os vários caminhos que chegam lá, acho que você tem uma pergunta diferente da que você respondeu.
Brian D Foy

Respostas:

254

Veremos como o conteúdo dessa matriz é construído e pode ser manipulado para afetar onde o interpretador Perl encontrará os arquivos do módulo.

  1. Padrão @INC

    O interpretador Perl é compilado com um @INCvalor padrão específico . Para descobrir esse valor, execute o env -i perl -Vcomando ( env -iignora a PERL5LIBvariável ambiental - consulte o item 2) e na saída você verá algo como isto:

    $ 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
     .
    

Nota .no final; esse é o diretório atual (que não é necessariamente o mesmo que o diretório do script). Está faltando no Perl 5.26+ e quando o Perl é executado com -T(verificações de contaminação ativadas) .

Para alterar o caminho padrão ao configurar a compilação binária Perl, defina a opção de configuração otherlibdirs:

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

  1. Variável ambiental PERL5LIB(ou PERLLIB)

    O Perl se antecipa a @INCuma lista de diretórios (separados por dois pontos) contidos na PERL5LIB(se não definida, PERLLIBé usada) variável de ambiente do seu shell. Para ver o conteúdo das variáveis @INCafter PERL5LIBe PERLLIBenvironment entraram em vigor, execute 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 opção de linha de comando

    O Perl se antecipa a @INCuma lista de diretórios (separados por dois pontos) passados ​​como valor da -Iopção da linha de comando. Isso pode ser feito de três maneiras, como de costume nas opções Perl:

    • Passe na linha de comando:

      perl -I /my/moduledir your_script.pl
    • Passe-o pela primeira linha (shebang) do seu script Perl:

      #!/usr/local/bin/perl -w -I /my/moduledir
    • Passe-o como parte da PERL5OPT(ou PERLOPT) variável de ambiente (consulte o capítulo 19.02 em Program Perl )

  3. Passe pelo libpragma

    O Perl se antecipa a @INCuma lista de diretórios transmitidos a ele via use lib.

    Em um programa:

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

    Na linha de comando:

    perl -Mlib=/dir1,/dir2

    Você também pode remover os diretórios de @INCviano lib .

  4. Você pode manipular diretamente @INCcomo uma matriz Perl regular.

    Nota: Como @INCé usado durante a fase de compilação, isso deve ser feito dentro de um BEGIN {}bloco, que precede a use MyModuleinstrução.

    • Adicione diretórios ao início via unshift @INC, $dir.

    • Adicione diretórios ao final via push @INC, $dir.

    • Faça qualquer outra coisa que você possa fazer com uma matriz Perl.

Nota: Os diretórios são unshifted para @INCna ordem listada nesta resposta, por exemplo padrão @INCé o último na lista, precedido por PERL5LIB, precedido por -I, precedido por use libe direta @INCmanipulação, os dois últimos misturados em qualquer ordem em que estão no código Perl.

Referências:

Não parece haver uma @INCpostagem abrangente do tipo FAQ sobre Stack Overflow, portanto, essa pergunta deve ser uma delas.

Quando usar cada abordagem?

  • Se os módulos em um diretório precisarem ser usados ​​por muitos / todos os scripts em seu site, especialmente executados por vários usuários, esse diretório deverá ser incluído no padrão @INCcompilado no binário Perl.

  • Se os módulos no diretório forem usados ​​exclusivamente por um usuário específico para todos os scripts executados pelo usuário (ou se a recompilação do Perl não for uma opção para alterar o padrão @INCno caso de uso anterior), defina os usuários PERL5LIB, geralmente durante o login do usuário.

    Nota: Esteja ciente das armadilhas comuns para variáveis ​​de ambiente Unix - por exemplo, em certos casos, a execução dos scripts como um usuário específico não garante a execução com o ambiente do usuário configurado, por exemplo, via su.

  • Se os módulos no diretório precisarem ser usados ​​apenas em circunstâncias específicas (por exemplo, quando os scripts forem executados no modo de desenvolvimento / depuração, você poderá configurar PERL5LIBmanualmente ou passar a -Iopção para perl.

  • Se os módulos precisarem ser usados ​​apenas para scripts específicos, por todos os usuários, use use lib/ no libpragmas no próprio programa. Também deve ser usado quando o diretório a ser pesquisado precisar ser determinado dinamicamente durante o tempo de execução - por exemplo, a partir dos parâmetros da linha de comando ou do caminho do script (consulte o módulo FindBin para obter um ótimo caso de uso).

  • Se os diretórios @INCprecisarem ser manipulados de acordo com alguma lógica complicada, impossível de ser implementada com a combinação de use lib/ no libpragmas, use @INCmanipulação direta dentro do BEGIN {}bloco ou dentro de uma biblioteca de finalidade especial designada para @INCmanipulação, que deve ser usada pelo seu script antes de qualquer outro módulo ser usado.

    Um exemplo disso é alternar automaticamente entre bibliotecas nos diretórios prod / uat / dev, com a retirada da biblioteca em cascata no prod se ela estiver ausente do dev e / ou UAT (a última condição torna a solução padrão "use lib + FindBin" bastante complicada. ilustração detalhada desse cenário está em Como faço para usar módulos beta Perl a partir de scripts beta Perl? .

  • Um caso de uso adicional para manipulação direta @INCé poder adicionar referências de sub-rotina ou referências a objetos (sim, Virginia, @INCpode conter código Perl personalizado e não apenas nomes de diretório, conforme explicado em Quando é chamada uma referência de sub-rotina no @INC? ).

DVK
fonte
1
não esqueça PERLOPT, onde você pode definir -I. Além disso, coisas como base.pm e local :: lib usam as coisas que você listou implicitamente.
Brian d foy
1
@brian - use :: base usa-o devido a "require" abaixo, IIRC. Eu não estou familiarizado com o local :: lib, precisará ler mais para entender do que se trata
DVK
3
Além disso, para fazer desta uma resposta realmente boa, você precisa dizer às pessoas quando elas devem usar cada uma delas. Dar a eles 10 opções de como eles poderiam não ajuda muito. :)
brian d foy
PS Qualquer pessoa, sinta-se à vontade para editar a resposta para incluir uma segunda inclusão de diretório específica da arquitetura via -I / use lib. Planejei fazer isso sozinho mais tarde, mas preciso ficar offline por enquanto.
DVK
@brian - adicionada PERLOPT. Sinto vontade de mencionar base.pm e outros itens "quando o @INC é usado" é mais adequado às perguntas frequentes dos arquivos do módulo @ INC / localizando que publiquei e vinculei a partir daqui, então coloquei lá.
DVK 26/03
18

Além dos locais listados acima, a versão do Perl para OS X também tem mais duas maneiras:

  1. O arquivo /Library/Perl/x.xx/AppendToPath. Os caminhos listados neste arquivo são anexados ao @INC em tempo de execução.

  2. O arquivo /Library/Perl/x.xx/PrependToPath. Os caminhos listados neste arquivo são anexados ao @INC no tempo de execução.

dgatwood
fonte
6

Como já foi dito, o @INC é uma matriz e você pode adicionar o que quiser.

Meu script CGI REST se parece com:

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

A sub-rotina eliminada é exportada pelo Rest.pm.

Kacper Perschke
fonte