■ Windows Subsystem for Linux の Emacs で利用できる設定


【お知らせ】


<2021/02/05 追記>
本ページの内容は WSL2 でも動作します。DrvFs や VolFs の記載がある場合には、Windows 側のファイルシステム、WSL2 側のファイルシステムと読み替えてください。

<2019/05/13 追記>
次の設定の見直しにより、Windows ショートカットを作成した際、g で dired の再表示を行わなくともリンク先の表示が行われるようになりました。

<2019/05/08 追記>
5) で数引数(C-u)をつけて実行した場合は、常に(C-u が一つの場合でも)「.」や「..」の展開を行うようにしました。これでカレントディレクトリのシンボリックリンクを別のフォルダに作成することも容易となったと思います。
この対策には次のリポジトリのコマンドの更新も必要となりますので、併せて対応ください。

<2018/08/03 追記>
. や .. へのショートカット作成時の対策を行いました。この対応で、. や .. を直接指定してショートカットを作成できるようになりました。5) で紹介してる次の機能を C-u C-u s として利用する場合に便利かと思います。

【本題】


Windows Subsystem for Linux(WSL) で NTFS シンボクックリンクや Windows ショートカットを作成するための設定です。

Windows 10 1709 では、WSL で NTFS シンボリックリンクを参照できるようになりました。ただし、WSL から NTFS シンボリックリンクを簡単に作成する方法が存在しません。また、Windows ショートカットを作成することもできません。本設定は、NTFS シンボリックリンクや Windows ショートカットを作成するコマンドを提供すると共に、Emacs から容易にこれらのリンクやファイルを作成できるようにするための設定です。

1) 次の設定を参考とし、Windows Subsystem for Linux で Emacs を動かす環境を整備する。

2) NTFS シンボリックリンクを管理者権限なしで作成できるようにするために、以下のどちらかの対応を実施する。
  • 開発モードにする

 ※ 具体的には、シンボリックリンクを作成するプログラムから呼ばれる CreateSymbolicLink 関数が、dwFlags の SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE フラグを立てた状態で実行される必要があります。Windows の mklink や Cygwin は対応されているようですが、MinGW(MSYS2)は未対応のようです。
  • SeCreateSymbolicLinkPrivilege 権限を付加する(再ログインが必要)

 ※ Cygwin を使っている場合は、Cygwin のコンソールを管理権限で開き、次のコマンドを実行してください。(「Cygwin で sudo 的コマンドを使うための設定」で紹介している sudo を使って管理権限を与える方法もあります。)上記のリンクのコメントにある MSYS2 での利用方法を参考としています。
$ editrights -u $USER -l
$ editrights -u $USER -a SeCreateSymbolicLinkPrivilege
 administrators のメンバーは UAC により特権が削除されるという次のページのような情報もあるのですが、なぜか私の環境では発生していません。

3) 次のリポジトリにある wslln、wslsc、wslcommon の3つのスクリプトをコマンドパスが通ったフォルダ(/usr/local/bin や ~/bin 等)に作成し、chmod +x wslln wslsc することにより実行可能とする。

4) 以下の設定を有効にする。

この設定は、w32-symlinks.el の内容を参考としています。noflet package は melpa からインストールしてください。
(require 'dired)
(require 'cl-lib)
(require 'noflet)

(defun make-symbolic-link-for-wsl (target linkname &optional ok-if-already-exists)
  (interactive "fMake symbolic link to file: \nFName for link to %s: \np")
  (if (or (not (file-exists-p linkname))
          (if (numberp ok-if-already-exists)
              (yes-or-no-p (format "File %s already exists; make it a symlink anyway? " linkname))
            ok-if-already-exists)
          (signal 'file-already-exists
                  (list "File already exists" linkname)))
      (cond ((equal current-prefix-arg '(16))
             (dired-check-process "Making shortcut" "wslsc" "-f" target linkname))
            (t
             (dired-check-process "Making symlink" "wslln" "-s" "-f" "-a" target linkname)))))

(defun ad-make-symbolic-link (orig-fun &rest args)
  (if (or (not current-prefix-arg)
          (file-remote-p (nth 0 args))
          (file-remote-p (nth 1 args)))
      (apply orig-fun args)
    (apply 'make-symbolic-link-for-wsl args)))

(advice-add 'make-symbolic-link :around #'ad-make-symbolic-link)

(defun ad-dired-do-symlink (orig-fun &rest args)
  (cond (current-prefix-arg
         (noflet ((dired-create-files (file-creator operation fn-list name-constructor
                                                    &optional marker-char)
                                      (lexical-let ((name-const name-constructor))
                                        (funcall this-fn file-creator operation fn-list
                                                 (function (lambda (from)
                                                             (concat (funcall name-const
                                                                              (expand-file-name from))
                                                                     (when (equal current-prefix-arg '(16))
                                                                       ".lnk"))))
                                                 marker-char))))
           (apply orig-fun args)))
        (t
         (apply orig-fun args))))

(advice-add 'dired-do-symlink :around #'ad-dired-do-symlink)
※ 上記設定で利用している wslln コマンドでは、DrvFs ファイルシステム配下以外にあるファイル(or ディレクトリ)を DrvFs ファイルシステム配下の場所にリンクすることはできないようにしています。このような場合でも、make-symbolic-link は正常に完了したように振る舞いますのでご留意ください。また、リンク元のファイル(or ディレクトリ)のパスの途中にシンボリックリンク存在する場合は、それを実体のパスに変換します。これは、リンク元のパスに WSL のシンボリックリンクが含まれていた場合、そのパスを指す NTFS シンボリックリンクが作成されないようにするためです。Windows からでも使える NTFS シンボリックリンクを作成するためにこの対策を行っています。

5) 以下の設定を有効にする。
この設定により、dired の対象ファイル上で以下のキーを押下することにより、other-windows にシンボリックリンクや Windows ショートカットを作成可能となります。
  • s キーを押下: WSL シンボリックリンクを作成する。(Emacs デフォルトの動作)
  • C-u s キーを押下: 可能であれば NTFS シンボリックリンクを作成する。さもなくば、WSL シンボリックリンクを作成する。(作成のルールは、https://github.com/smzht/wsl-utils#-wslln の -s オプションの説明を参照のこと。)
  • C-u C-u s キーの押下: Windows ショートカットを作成する。(作成のルールは、https://github.com/smzht/wsl-utils#-wslsc の説明を参照のこと。)
※ 数引数(C-u)をつけて実行した場合は、「.」や「..」を展開してシンボリックリンクやショートカットを作成します。
※ NTFS シンボリックリンクや Windows ショートカット のファイル名を wdired-change-to-wdired-mode で変更する場合は、リンク元のファイル名のみの変更としてください。リンク先のファイル名を変更すると、作成されているリンクが WSL シンボリックリンクに変更されてしまいます。ご注意ください。

6) 作成した Windows ショートカットを dired でシンボリックリンクの様に参照可能とするために、次の設定を行う。

7) 以下の設定を有効にする。(「WSL で Emacs を使うための設定」にも同じ説明を記述しています。)

Windows 10 1703 or 1709 の WSL の Emacs では、dired でパスの途中に NTFS シンボリックリンクを含むファイルを削除しようとするとフリーズするようです。
Emacs バージョン 24.5.1 と 25.3.2 の delete-file 関数で発生することを確認しています。Windows 10 1803 では発生しないようです。

以下の設定はこれを対策する方法です。二とおりの方法を紹介しています。できれば Emacs の標準機能である(方法1)をご利用ください。

(setq-default find-file-visit-truename t)
(方法2)delete-file 関数へのアドバイスで対策
(defun ad-delete-file (orig-fun &rest args)
  (setf (nth 0 args)
        (concat (file-truename (file-name-directory (nth 0 args)))
                (file-name-nondirectory (nth 0 args))))
  (apply orig-fun args))

(advice-add 'delete-file :around #'ad-delete-file)


<変更履歴>
  • 2017/11/01 このページを作成した。
  • 2017/11/04 パスの途中に NTFS シンボリックリンクを含むファイルを削除しようとするとフリーズする問題の対策を追加した。
  • 2018/03/14 Windows ショートカットの作成にも対応するように見直した。
  • 2018/03/15 キーの割当てを見直した。
  • 2018/03/17 wslshortcut コマンドの名称を wslsc に変更した。
  • 2018/03/23 wsl コマンドの見直しにより、高速化対策を行った。
  • 2018/08/03 . や .. へのショットカット作成時の対策を行った。
  • 2019/05/08 5) で数引数(C-u)をつけて実行した場合は常に「.」や「..」の展開を行うようにした。


最終更新:2021年02月05日 09:32