NTEmacsでexec-path-from-shellを使うと色々エラーになる対処

現象

NTEmacsでexec-path-from-shellを使ったら、以下のような症状が発生しました。

外部プログラムが見つからないと怒られる

例えば、grepとかmigemoとか。

Searching for program: no such file or directory, grep
Searching for program: no such file or directory, cmigemo

M-x shell ができない

以下のエラーが出て、シェルが起動しない。

Process shell exited abnormally with code 53

対処

原因についての考察は後述します。
とりあえず、下記のように設定を記述することでエラーが回避できました。

(require 'exec-path-from-shell)
(when (memq system-type '(windows-nt ms-dos cygwin))
  (defadvice exec-path-from-shell-setenv (around fix-for-cygwin activate)
    (cond ((string= "PATH" (ad-get-arg 0))
           (setq eshell-path-env (ad-get-arg 1))
           (setq exec-path (loop for p in (split-string (ad-get-arg 1) ":")
                                 if (not (string= p ""))
                                 collect (substitute-in-file-name (directory-file-name p)))))
          (t
           ad-do-it))))
(exec-path-from-shell-initialize)

考察

まず

私がexec-path-from-shellを使った動機は以下です。

Emacsは単独で起動していて、shell-file-nameにCygwinbashなどを使っているが、M-x shell 以外でもrcファイルの環境変数を引き継ぎたい

Windowsでexec-path-from-shellを使いたい理由が他にあるか疑問ですが。
で、同じ理由の方であれば、同じエラーが出る、または期待通りに引き継げない、ということがおきると思います。
以下の考察も、この前提の元で進めます。

何をしているのか

exec-path-from-shellは、引き継ぎたい環境変数をシェル上でechoして、その結果をsetenvしたりexec-pathに設定したりしているようです。

どのシェル上?

で、「シェル上で」は、どのシェルなのかというと、環境変数SHELLの値です。
つまり、期待通りの動作をさせるには、以下のいすれかが必要です。

  • マイコンピュータのプロパティとかで開ける環境変数の設定で、SHELLにCygwinの目的のシェルのパスを指定する
  • .emacsなどの設定ファイルでsetenvする

shell-file-nameやexplicit-shell-file-nameは適切に設定されていると思うので、 それを使って以下のようにするのが手軽かと。

(setenv "SHELL" shell-file-name)

exec-pathの上書き

環境変数SHELLのシェル上で得た環境変数PATHの値をexec-pathに設定するのですが、
exec-pathはリスト形式なので、得られた文字列を区切り文字を使ってパースしています。
で、区切り文字は変数path-separatorで決まるのですが、Windowsなので";"が設定されています。
しかし、得られる文字列はCygwinのシェル上での結果なので、":"で区切られたUNIX形式の値です。
これにより、exec-pathに正しいリストが設定されず、grepなどの外部プログラムが見つからないと怒られていると思われます。

※ちなみに、以下のように一時的にpath-separatorを変更すれば良いと思ったんですが、なぜかダメだったので上記の対処にしました。

(let ((path-separator ":"))
  (exec-path-from-shell-initialize))

環境変数PATHの上書き

環境変数SHELLのシェル上で得た環境変数の値は、同じ環境変数に上書きしています。
これにより、環境変数PATHの値は以下のように上書きされます。

(getenv "PATH") ; => "c:\\App\\cygwin\\bin; ...
(exec-path-from-shell-initialize)
(getenv "PATH") ; => "/cygdrive/c/App/cygwin/bin: ...

しかし、上書き後、M-x shell すると、エラーになってシェルが起動されません。
ソースをしっかり追っていないので、はっきりとは言えませんが、 環境変数PATHを見ており、その値がWindowsの形式でないとダメなようです。
なので、PATHは上書きしないようにしました。

※ただし、これだとPATHは引き継がれないままですが。

その他

  • Emacsは、 GNU Emacs 24.2.1 (i386-mingw-nt5.1.2600) of 2012-12-08 on GNUPACK です。
  • exec-path-from-shell自体の説明は省きます。