WSL2環境での手軽なpyenv導入 - Windows側のpyenvとの衝突回避

WSL2環境でpyenvのPython動かせるようにしようとしたときに少しハマったので解決するまでの手順を紹介します。

# 前提
- Windows11
- Windows側にpyenv導入済み
- WSL2未導入

# WSL2をインストールする

公式サイトを参考にしました。

https://learn.microsoft.com/ja-jp/windows/wsl/install

一昔前まではあれやこれややる必要があった気がしたのですが、今は`wsl --install`一発でインストールできるようになっているんですね。

```shell
PS > wsl --install
インストール中: Linux 用 Windows サブシステム
Linux 用 Windows サブシステム はインストールされました。
インストール中: Ubuntu
Ubuntu はインストールされました。
要求された操作は正常に終了しました。変更を有効にするには、システムを再起動する必要があります。
```

再起動しろと言われたので再起動したところ、勝手にUbuntuが立ち上がってusernameとかの設定をさせられました。

```shell
Ubuntu は既にインストールされています。
Ubuntu を起動しています...
Installing, this may take a few minutes...
Please create a default UNIX user account. The username does not need to match your Windows username.
For more information visit: https://aka.ms/wslusers
Enter new UNIX username: ubuntu
New password:
Retype new password:
passwd: password updated successfully
この操作を正しく終了しました。
Installation successful!
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

Welcome to Ubuntu 22.04.3 LTS (GNU/Linux 5.15.133.1-microsoft-standard-WSL2 x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage


This message is shown once a day. To disable it please create the
/home/ubuntu/.hushlogin file.
ubuntu@vivobook16x:~$
```

usernameとパスワードを設定するとubuntuが立ち上がりました。
現時点ではデフォルトでUbuntu22.04が選択されるようです。

一度Ubuntuからログアウトして、PSからWSLのバージョンを確認します。
```shell
PS > wsl --version
WSL バージョン: 2.0.9.0
カーネル バージョン: 5.15.133.1-1
WSLg バージョン: 1.0.59
MSRDC バージョン: 1.2.4677
Direct3D バージョン: 1.611.1-81528511
DXCore バージョン: 10.0.25131.1002-220531-1700.rs-onecore-base2-hyp
Windows バージョン: 10.0.22621.3007
```

インストールするのがWSL1なのかWSL2なのかを特に指定していないのですが、WSL2がデフォルトでインストールされるみたいですね。
一応WSLのアップデートをしておきます。
```shell
PS > wsl --update
更新プログラムを確認しています。
Linux 用 Windows サブシステムをバージョンに更新しています: 2.0.14。
要求された操作には管理者特権が必要です。
更新プログラムを確認しています。
Linux 用 Windows サブシステムをバージョンに更新しています: 2.0.14。
PS > wsl --version
WSL バージョン: 2.0.14.0
カーネル バージョン: 5.15.133.1-1
WSLg バージョン: 1.0.59
MSRDC バージョン: 1.2.4677
Direct3D バージョン: 1.611.1-81528511
DXCore バージョン: 10.0.25131.1002-220531-1700.rs-onecore-base2-hyp
Windows バージョン: 10.0.22621.3007
```

これでWSLの準備は完了です。

# pyenvのインストール

こちらも公式Githubを参照しました。

https://github.com/pyenv/pyenv

まず`wsl`コマンドでUbuntuへログインします。
そのあとホームディレクトリへ移動して、aptのアップデートとアップグレードをしておきます。
```shell
PS > wsl
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

$ cd ~
$ sudo apt update
$ sudo apt upgrade -y
```

このUbuntuにはPython3.10.12がプリインストールされているようです。参照先もWindowsではなくUbuntu内ですね。
```shell
$ python3 -V
Python 3.10.12
$ which python3
/usr/bin/python3
```

pyenvの公式GithubによるとUbuntuへのインストールは↓の4行でできるようです。
```shell
$ curl https://pyenv.run | bash
$ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
$ echo 'command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
$ echo 'eval "$(pyenv init -)"' >> ~/.bashrc
```

この後、.bashrcへ書き込んだ内容を有効化するために`source ~/.bashrc`を打ち込みますが、ここでエラーが発生します。
```shell
$ source .bashrc
/mnt/c/Users/***/.pyenv/pyenv-win/bin/pyenv: 3: cygpath: not found
/mnt/c/Users/***/.pyenv/pyenv-win/bin/pyenv: 3: exec: cmd: not found
```

見た感じ`pyenv`コマンドがWindows側のpyenvを見に行ってしまっているようです。
`which pyenv`で調べるとやはりWindowsにインストールされたpyenvを参照していますね。
`$PATH`の中身を確認しますと、どうやらUbuntuの環境変数にはWindowsの環境変数も設定されているみたいです。
```shell
$ which pyenv
/mnt/c/Users/***/.pyenv/pyenv-win/bin/pyenv
$ echo $PATH
(略):/mnt/c/Users/***/.pyenv/pyenv-win/bin:/mnt/c/Users/***/.pyenv/pyenv-win/shims:(略)
```

これが今回の不具合にどのような影響を及ぼしているのかというと、Ubuntuへpyenvをインストールした際に`.bashrc`へ追記した
```
command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"
```
が正しく動かなくなることにつながります。

この行がざっくり何をしているのかというと、「`pyenv`コマンドを参照できない場合に今回インストールしたpyenvのPATHを環境変数に追加する」です。
通常は`pyenv`コマンドはまだ参照できないはずなので、インストールされたpyenvのPATHが環境変数に追加されることになります。
しかし、今回すでにWindows側にpyenvが導入されていてUbuntuがWindowsの環境変数を見ているとなりますと「`pyenv`コマンドを参照できる」と判断されてしまい、Ubuntu用にインストールされたpyenvのPATHが環境変数へ追加されないことになってしまっていたのです。
したがって今回は↓のように、`~/.bashrc`内の記述を変更して四の五の言わずにUbuntu用のpyenvのPATHを追加するようにしました。

```:~/.bashrc(変更前)
(略)
command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"
(略)
```

```:~/.bashrc(変更後)
(略)
export PATH="$PYENV_ROOT/bin:$PATH"
(略)
```

その後、設定を反映するために`source ~/.bashrc`を打ち込めばインストール完了です。

```shell
$ source ~/.bashrc
$ which pyenv
/home/ubuntu/.pyenv/bin/pyenv
$ pyenv --version
pyenv 2.3.35
```

ちなみにWindows側もバグりません。
```shell
$ exit
logout
PS > pyenv --version
pyenv 3.1.1
```

これで、WindowsとWSL2それぞれにpyenvが存在したときの衝突回避が無事に完了しました。