Comment est construit @INC de Perl? (aka Quelles sont toutes les façons d'affecter où les modules Perl sont recherchés?)

199

Quelles sont toutes les façons d'affecter où les modules Perl sont recherchés? ou, comment est construit @INC de Perl ?

Comme nous le savons, Perl utilise un @INCtableau contenant des noms de répertoires pour déterminer où rechercher les fichiers du module Perl .

Il ne semble pas y avoir de publication de type FAQ "@INC" complète sur StackOverflow, donc cette question est conçue comme une seule.

DVK
la source
7
Oui, mais il y en a une parfaitement bonne sur search.cpan.org/perldoc/… ?
mob
3
@mobrule: Je ne pense pas que ce soit aussi complet - il s'agit simplement de dire comment ajouter @INCau moment de l'exécution, pas la construction complète.
Cascabel
2
@mobrule - @Jefromi a deviné à droite - le principal problème avec TOUT et toutes les références que j'ai trouvées jusqu'à présent était un manque d'informations complètes sur le défaut compilé de binaire perl @INC
DVK
3
Certains peuvent rendre cette réponse aussi complète en m'envoyant un patch. C'est facile car perlfaq est dans Github. :)
brian d foy
1
Eh bien, les "informations complètes sur le @INC par défaut compilé par le binaire perl" sont que c'est lui qui l'a compilé. Si vous posez des questions sur les différents chemins qui y mènent, je pense que vous avez une question différente de celle à laquelle vous avez répondu.
brian d foy

Réponses:

254

Nous verrons comment le contenu de ce tableau est construit et peut être manipulé pour affecter où l'interpréteur Perl trouvera les fichiers du module.

  1. Défaut @INC

    L'interpréteur Perl est compilé avec une @INCvaleur par défaut spécifique . Pour connaître cette valeur, exécutez la env -i perl -Vcommande ( env -iignore la PERL5LIBvariable d'environnement - voir # 2) et dans la sortie, vous verrez quelque chose comme ceci:

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

Remarque .à la fin; c'est le répertoire courant (qui n'est pas nécessairement le même que le répertoire du script). Il est manquant dans Perl 5.26+, et lorsque Perl s'exécute avec -T(vérification des taches activée) .

Pour modifier le chemin par défaut lors de la configuration de la compilation binaire Perl, définissez l'option de configuration otherlibdirs:

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

  1. Variable d'environnement PERL5LIB(ou PERLLIB)

    Perl ajoute @INCune liste de répertoires (séparés par deux-points) contenus dans la variable d'environnement PERL5LIB(si elle n'est pas définie, PERLLIButilisée) de votre shell. Pour voir le contenu des variables @INCafter PERL5LIBet PERLLIBenvironment ont pris effet, exécutez 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 option de ligne de commande

    Perl ajoute @INCune liste de répertoires (séparés par deux-points) transmis comme valeur de l' -Ioption de ligne de commande. Cela peut être fait de trois manières, comme d'habitude avec les options Perl:

    • Passez-le en ligne de commande:

      perl -I /my/moduledir your_script.pl
    • Passez-le via la première ligne (shebang) de votre script Perl:

      #!/usr/local/bin/perl -w -I /my/moduledir
    • Passez-le comme partie de la variable d'environnement PERL5OPT(ou PERLOPT) (voir le chapitre 19.02 dans Programmation de Perl )

  3. Passez-le via le libpragma

    Perl pré-suspend @INC avec une liste de répertoires qui lui sont passés viause lib .

    Dans un programme:

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

    Sur la ligne de commande:

    perl -Mlib=/dir1,/dir2

    Vous pouvez également supprimer les répertoires de @INCviano lib .

  4. Vous pouvez directement manipuler @INCcomme un tableau Perl standard.

    Remarque: Puisque @INCest utilisé pendant la phase de compilation, cela doit être fait à l'intérieur d'un BEGIN {}bloc, qui précède l' use MyModuleinstruction.

    • Ajoutez des répertoires au début via unshift @INC, $dir.

    • Ajoutez des répertoires à la fin via push @INC, $dir.

    • Faites tout ce que vous pouvez faire avec un tableau Perl.

Remarque: Les répertoires sont sans décalage sur @INCdans l'ordre indiqué dans cette réponse, par défaut , par exemple @INCest le dernier dans la liste, précédé PERL5LIB, précédé -I, précédéuse lib et directe@INC la manipulation, ces deux derniers mélangés dans l'ordre qui ils sont dans le code Perl.

Références:

Il ne semble pas y avoir de @INC publication de type FAQ sur Stack Overflow, donc cette question est conçue comme une seule.

Quand utiliser chaque approche?

  • Si les modules d'un répertoire doivent être utilisés par de nombreux / tous les scripts de votre site, en particulier exécutés par plusieurs utilisateurs, ce répertoire doit être inclus dans le répertoire par défaut. @INC compilé dans le binaire Perl.

  • Si les modules du répertoire seront utilisés exclusivement par un utilisateur spécifique pour tous les scripts exécutés par l'utilisateur (ou si la recompilation de Perl n'est pas une option pour modifier la valeur @INCpar défaut dans le cas d'utilisation précédent), définissezPERL5LIB , généralement lors de la connexion de l'utilisateur.

    Remarque: veuillez tenir compte des pièges habituels des variables d'environnement Unix - par exemple, dans certains cas, l'exécution des scripts en tant qu'utilisateur particulier ne garantit pas leur exécution avec l'environnement de cet utilisateur configuré, par exemple via su.

  • Si les modules du répertoire ne doivent être utilisés que dans des circonstances spécifiques (par exemple lorsque le ou les scripts sont exécutés en mode développement / débogage, vous pouvez soit définir PERL5LIBmanuellement, soit passer l' -Ioption à perl.

  • Si les modules doivent être utilisés uniquement pour des scripts spécifiques, par tous les utilisateurs qui les utilisent, utilisez use lib/ no libpragmas dans le programme lui-même. Il doit également être utilisé lorsque le répertoire à rechercher doit être déterminé dynamiquement pendant l'exécution - par exemple à partir des paramètres de ligne de commande du script ou du chemin du script (voir le module FindBin pour un très bon cas d'utilisation).

  • Si les répertoires @INCdoivent être manipulés selon une logique compliquée, impossible à trop compliquée à implémenter par la combinaison de use lib/ no libpragmas, alors utilisez la @INCmanipulation directe à l' intérieur du BEGIN {}bloc ou à l'intérieur d'une bibliothèque à usage spécial désignée pour@INC manipulation, qui doit être utilisée par votre script (s) avant d'utiliser tout autre module.

    Un exemple de ceci est le basculement automatique entre les bibliothèques dans les répertoires prod / uat / dev, avec la collecte de bibliothèque en cascade dans prod si elle manque dans dev et / ou UAT (la dernière condition rend la solution standard "use lib + FindBin" assez compliquée. illustration détaillée de ce scénario est en Comment puis-je utiliser des modules Perl bêta à partir de scripts Perl bêta? .

  • Un cas d'utilisation supplémentaire pour la manipulation directe @INCconsiste à pouvoir ajouter des références de sous-programme ou des références d'objet (oui, Virginia, @INCpeut contenir du code Perl personnalisé et pas seulement des noms de répertoire, comme expliqué dans Quand une référence de sous-programme dans @INC est-elle appelée? ).

DVK
la source
1
n'oubliez pas PERLOPT, où vous pouvez définir -I. En outre, des éléments tels que base.pm et local :: lib utilisent implicitement les éléments que vous avez répertoriés.
brian d foy
1
@brian - use :: base l'utilise en raison de "require" en dessous, IIRC. Je ne connais pas local :: lib, j'aurai besoin de lire plus pour comprendre de quoi il s'agit
DVK
3
De plus, pour en faire une très bonne réponse, vous devez dire aux gens quand ils doivent utiliser chacun d'eux. Leur donner 10 options sur la façon dont ils pourraient ne pas être très utile. :)
brian d foy
PS N'importe qui, n'hésitez pas à modifier la réponse pour inclure une seconde inclusion de répertoire spécifique à l'architecture via -I / use lib. J'ai prévu de le faire moi-même plus tard, mais je dois me déconnecter pour l'instant.
DVK
@brian - a ajouté PERLOPT. J'ai envie de mentionner base.pm et d'autres éléments "quand @INC s'utilise-t-il" est plus adapté à la FAQ sur les fichiers du module @ INC / recherche que j'ai posté et lié à partir d'ici, donc je le mets là.
DVK
18

En plus des emplacements répertoriés ci-dessus, la version OS X de Perl a également deux autres façons:

  1. Le fichier /Library/Perl/x.xx/AppendToPath. Les chemins d'accès répertoriés dans ce fichier sont ajoutés à @INC lors de l'exécution.

  2. Le fichier /Library/Perl/x.xx/PrependToPath. Les chemins d'accès répertoriés dans ce fichier sont ajoutés à @INC lors de l'exécution.

dgatwood
la source
6

Comme il a déjà été dit, @INC est un tableau et vous êtes libre d'ajouter tout ce que vous voulez.

Mon script CGI REST ressemble à:

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

Le sous-programme disparu est exporté par Rest.pm.

Kacper Perschke
la source