exec-path et $ PATH

28

J'ai vu des exemples en ligne où les gens ajoutent des chemins au chemin par défaut dans Emacs avec:

(add-to-list 'exec-path "/usr/local/bin/")

Je suis nouveau chez Elisp, et je pense que je comprends ce que fait la déclaration ci-dessus, mais j'ai quelques questions:

  • Dans quel ordre Emacs recherche-t-il les chemins d'exécution? Par exemple, prend-il en compte la valeur de $PATH(variable env.) (Et si oui, avant ou après exec-path?)

  • Comment puis-je ajouter plusieurs de ces chemins? Puis-je continuer à les concaténer? par exemple

    (add-to-list 'exec-path "PATH1", "PATH2")
    

    ou devrais-je faire:

    (add-to-list 'exec-path "PATH1:PATH2:PATH3") 
    

J'ai également trouvé ce package intéressant sur GitHub: exec-path-from-shell . Pourquoi a-t-on besoin d'un package pour cela?

Motivation

Avez-vous déjà constaté qu'une commande fonctionne dans votre shell, mais pas dans Emacs?

Cela se produit souvent sous OS X, où une instance Emacs démarrée à partir de l'interface graphique hérite d'un ensemble par défaut de variables d'environnement.

Cette bibliothèque fonctionne résout ce problème en copiant les variables d'environnement importantes du shell de l'utilisateur: elle fonctionne en demandant à votre shell d'imprimer les variables d'intérêt, puis en les copiant dans l'environnement Emacs.

Amelio Vazquez-Reina
la source
3
Bienvenue chez Emacs et Elisp! Je suis encore assez frais avec le sujet moi-même et je ne connais pas les réponses à vos questions, mais je pensais que je mentionnerais quelque chose qui a rendu la vie beaucoup plus facile: les fonctions de description. eg (describe-function 'add-to-list)( C-h f) vous donnera le document pour la add-to-listfonction, ainsi que des liens vers la source. Il y a aussi (describe-variable 'exec-path)( C-h v). Ce n'est pas censé être un commentaire RTFM - ces documents ne répondent pas à toutes les questions que vous avez énumérées, juste quelque chose d'utile.
jtmoulia
Merci @jtmoulia! Je garderai certainement cela à l'esprit pour les questions futures.
Amelio Vazquez-Reina
De plus C-h v exec-path, utilisez le ou les manuels (Emacs et Elisp). Dans un manuel, i exec-pathvous dirige vers une explication utile. Demandez d'abord à Emacs - vous ne le regretterez pas.
Drew

Réponses:

23

1) PATHetexec-path

Emacs est défini à exec-pathpartir de la valeur de PATHau démarrage, mais ne le réexaminera pas plus tard. Mais si vous exécutez une commande, elle héritera PATH, non exec-path, donc les sous-processus peuvent trouver des commandes différentes d'Emacs.

Comme Francesco le dit, cela peut être particulièrement déroutant shell-command, car cela n'exécute pas directement un processus, mais appelle un shell pour l'exécuter, qui l'utilisera PATH, non exec-path.

2) Ajout de plusieurs chemins à exec-path

Appelez simplement à add-to-listplusieurs reprises:

(add-to-list 'exec-path "PATH1")
(add-to-list 'exec-path "PATH2")

Notez que cela add-to-lists'ajoute au début de la liste, donc cela finira par "PATH2"être dans l' exec-pathavant "PATH1".

Vous pouvez également utiliser un accès plus "bas niveau" aux listes:

(setq exec-path (append '("PATH1" "PATH2")
                        exec-path))

Cela ajoutera "PATH1"et "PATH2"à votre exec-path, dans cet ordre.

3) CHEMIN DE Mac OS

Le problème sur Mac OS X est que Mac OS ne définit pas l'environnement de la même manière lorsque vous appelez un programme à partir de l'interface utilisateur globale ou lorsque vous l'appelez à partir d'un shell. Cela signifie que l'exécution d'Emacs à partir d'un shell entraînera la définition de différentes variables d'environnement que lorsque vous l'exécutez à partir du Finder. Ceci est particulièrement gênant si vous définissez des variables d'environnement dans .bashrcou similaire, car cela n'affectera pas les Emacs "globaux".

Le paquet démarre apparemment un shell et importe des variables d'environnement à partir de là, imitant l'environnement que vous obtenez à partir d'un shell dans un Emacs lancé à l'échelle mondiale.

Jorgen Schäfer
la source
Merci Jorgen. Concernant Q3: Savez-vous par hasard où la valeur par défaut PATHest définie pour les programmes démarrés à partir de l'interface utilisateur globale (environnement de bureau)? Je suis le même problème avec PYTHONPATHdans elpy:). Lorsque je démarre Emacs à partir du bureau, Emacs n'a pas connaissance de mes PYTHONPATHdéfinitions dans mon .zshenvfichier (un fichier init pour zsh), ce qui est très frustrant, car elpyil ne sait pas alors où trouver mes packages Python. Je suis heureux de déplacer ces PYTHONPATHdéfinitions vers un autre initfichier shell (bien que, dans l'idéal, j'aimerais qu'Emacs utilise les définitions de mon .zshenv)
Amelio Vazquez-Reina
Je crains de ne pas en savoir grand-chose sur Mac OS X. Un rapide google m'a amené à stackoverflow.com/questions/135688/… qui semble indiquer que launchd.conf est le bon endroit. Si vous n'avez besoin que d'Emacs, vous pouvez bien sûr simplement définir les deux exec-pathet PATHdans votre .emacs. Vous pouvez définir à l' PATHaide de (setenv "PATH" (format "%s:%s" "/new/path/element" (getenv "PATH"))).
Jorgen Schäfer
Merci. Je sais que le Q suivant diverge un peu de l'OP, mais existe-t-il un moyen de spécifier dans Emacs celui PYTHONPATHqui elpydevrait être utilisé?
Amelio Vazquez-Reina
Vous pouvez modifier process-environment, par exemple en utilisant setenv. Vous pouvez le faire dans elpy-mode-hook, mais c'est une variable globsl et la rendre locale au tampon peut facilement conduire à un comportement déroutant.
Jorgen Schäfer
9

Quand emacs démarre un nouveau processus externe en utilisant des fonctions primitives telles que call-processou start-process, l'exécutable est recherché dans exec-path(et non $PATH)

Cependant, une fonction telle que shell-commanddémarre le shell en tant que sous-processus et lui transmet la commande que vous souhaitez exécuter. Afin d'exécuter cette commande, le shell essaiera alors de trouver l'exécutable dans $PATH(et non dans exec-path).

Par conséquent, exec-pathc'est ce qui compte le plus pour les processus externes qui sont démarrés par emacs lui-même, alors que $PATHc'est ce qui compte pour les commandes que vous exécutez vous-même avec une fonction de niveau supérieur (en utilisant M-!par exemple)


Si vous souhaitez ajouter plusieurs répertoires à exec-path, vous devez utiliser add-to-listplusieurs fois.

Vous pouvez le faire soit manuellement

(add-to-list 'exec-path "dir1")
(add-to-list 'exec-path "dir2")

ou en utilisant une boucle

(dolist (dir '("dir1" "dir2"))
  (add-to-list 'exec-path dir))

Concernant votre troisième question, si emacs a été lancé à partir de l'environnement de bureau, il en hérite, ce qui pourrait être moins complet que celui d'un shell complet.

Cela signifie qu'il peut parfois être nécessaire de compléter la valeur d'Emacs pour $PATHutiliser ce que voit un shell standard. C'est le but de la exec-path-from-shellbibliothèque que vous mentionnez.

ffevotte
la source