WSL 最新版と新しめの Linux ディストリビューションで Wayland が正しく動作しない場合の暫定対処（2024年11月版）

:::note
この問題は 2024/4/25 リリースの WSL バージョン 2.5.7.0 で修正されました。（プレリリース版では 2.5.1.0）
様々な理由で古いバージョンを使う必要のある環境が残っている場合や今後類似の現象が発生したときのために、記事は一部修正して残しておきます。

管理者 PowerShell で以下のコマンドを実行して、WSL を最新バージョンにしてみてください。
* Windows Update によって自動でアップデートされている場合もあります

```powershell:PowerShell
wsl --update
wsl --version
```

以前に設定したサービスを削除する場合は以下の通りサービスの登録を解除し、その後サービス設定ファイルを削除してください。

```bash:bash
# 念のため登録状態を確認
systemctl --user is-enabled wsl-wayland-symlink.service
# 停止
systemctl --user stop wsl-wayland-symlink.service
# 登録解除
systemctl --user disable wsl-wayland-symlink.service
# サービス設定ファイルを削除（一例）
rm .config/systemd/user/wsl-wayland-symlink.service
```

参考: https://github.com/microsoft/WSL/releases/tag/2.5.1

:::

# はじめに
この記事は WSL (WSLg) で 2024 年 11 月現在発生中の問題についての対処を記述しています。そのため将来的にこの対処が不要になる可能性もありますし、そうなることが期待されます。

# 現象
現在（2024年11月）時点で最新の WSL (WSLg) と、Wayland をディスプレイサーバに採用している Linux ディストリビューション（例: Ubuntu 24.04）で、Wayland が正しく動作していないために一部アプリが起動できなかったり、X11 にフォールバックするなどの不具合が発生しています。

* 手元での確認では Ubuntu 24.04 では発生しましたが、Ubuntu 22.04 では発生しませんでした

# 確認バージョン
* WSL
```powershell:Host (windows) Powershell
PS> wsl --version
WSL バージョン: 2.3.24.0
カーネル バージョン: 5.15.153.1-2
WSLg バージョン: 1.0.65
MSRDC バージョン: 1.2.5620
Direct3D バージョン: 1.611.1-81528511
DXCore バージョン: 10.0.26100.1-240331-1435.ge-release
Windows バージョン: 10.0.19045.5073
```
* WSLg
```bash:Linux console (bash)
$ cat /mnt/wslg/versions.txt
WSLg ( x86_64 ): 1.0.65+Branch.main.Sha.25d8697d5049e1994baa6ba542f507347b608ad4
Built at: Wed Aug 14 21:11:14 UTC 2024
Mariner: VERSION="2.0.20240609"
DirectX-Headers:
mesa:
pulseaudio: 6f045ff0dca233a939a2aba815f84d177e294122
FreeRDP: c4030980b29322a9cb2190711a5fadeeeb8b6a33
weston: f227edd681479ec3cb2290a25d84d2d3462aebfa
```
* Linux は Ubuntu 24.04 を使用しています。他のディストリビューションでは一部コマンド等が異なる場合がありますので適宜読み替えてください

# 確認方法
簡単な方法としては、 `wl-clipboard`（Ubuntu の場合）をインストールし、`wl-copy` コマンドが動作するかどうかを確認するという方法があります。

```bash:bash
wl-copy hoge
```

Wayland が正常に動作していれば何も出力せず終了し、Wayland のクリップボードに（上記の場合は）「hoge」という文字列が格納されます。WSL ではこれは Windows クリップボードと共有されるので、Windows 側のアプリで Ctrl-V などで貼り付けると先ほどコピーした「hoge」が入力されます。
Wayland が動作していないか異常な場合はエラーが出力されます。

# 原因
本来は `XDG_RUNTIME_DIR` で指定された場所（たいていは `/run/user/<userid>`）に Wayland のソケット（`wayland-0` などのような名前）が作成されているはずです。

WSL の場合は `/mnt/wslg/runtime-dir/wayland-0` などへのシンボリックリンクとして作成されますが、比較的新しいバージョンのディストリビューションではシンボリックリンクの作成ができておらず、ソケットが見つからないという状態になってしまいます。

# 暫定対処
単純にシンボリックリンクを張れば解決するのですが、手動で張っただけでは Linux (WSL) を再起動すると消えてしまうのでその都度張らなければいけません。そのため起動時に自動で張る方法を採ります。
ひとまずの対処として、以下の2種類の方法を挙げます。

## 1: 起動時にワンショットのユーザーサービスで設定する

1. 自分のホームディレクトリに `.config/systemd/user` というディレクトリを作成し、その下に `<適切な名前>.service` というファイルを作成します
    * 拡張子は `.service` で固定です。ファイル名は後で使いますので、どのようなサービスかわかる名前を付けてください。以降では仮に `wsl-wayland-symlink.service` とします
1. 以下のようなサービス定義を記述します

    ```ini:wsl-wayland-symlink.service
    [Unit]
    Description=Create Wayland symlinks for WSL
    After=default.target
    
    [Service]
    Type=oneshot
    ExecStart=/bin/sh -c 'find /mnt/wslg/runtime-dir -name "wayland-*" -type s -exec ln -sf {} /run/user/%U/ \; '

    [Install]
    WantedBy=default.target
    ```

    * cat で一気にファイル作成と内容記述までやってしまってももちろんかまいません
    * 内容としては、対象のシンボリックリンクを作成するサービスを起動時に1回だけ実行するというものです
1. サービスに登録して実行させます

    ```bash
    systemctl --user daemon-reload
    systemctl --user enable wsl-wayland-symlink.service
    systemctl --user start wsl-wayland-symlink.service
    ```

    * 実行後に `/run/user/<user id>` 内に正しくシンボリックリンクが張られていることを確認してください
1. Linux と WSL 自体の再起動（管理者 PowerShell で `wsl --shutdown`）をおこない、再起動後でも正しくシンボリックリンクが張られていることを確認します
1. `wl-copy` を試したり、動きに異常があった GUI アプリケーションを確認します

## 2: `.bashrc` で設定する

簡易的な方法として .bashrc に追記する方法も記載しておきます。WSL のユースケースとしてターミナルは必ず起動すると思われますので、こちらもほとんどの場合は有効に動作します。

```bash:.bashrc
# いちばん簡単な記述
find /mnt/wslg/runtime-dir -name "wayland-*" -type s -exec ln -sf {} /run/user/%U/
```

```bash:.bashrc
# 念のため WSL 上で動いていることを確認してから実行する場合
if grep -qEi "(Microsoft|WSL)" /proc/version &>/dev/null; then
  find /mnt/wslg/runtime-dir -name "wayland-*" -type s -exec ln -sf {} /run/user/%U/
fi
```

# 補足

参考資料には、「systemd-tempfiles の仕組みを利用して起動時にシンボリックリンクを張る」という例も挙げられていたのですが、以下の要因より対処案から除外しました。

* そもそもその機能が正常に働かない状況に陥っているようであること
* ユーザー側で動作させれば同じようにシンボリックリンクが張れるのだが、そのためには結局ユーザーサービスの設定が必要になること
* ソケットの名称の末尾の数字が変わる可能性があること

# 参考資料

* https://github.com/microsoft/wslg/issues/1032