MSYS2によるWindows 10でのBash環境構築メモ

目的
========================================

今日日（2019年4月）、BashとPythonは、Windows、Linux、macOSを含む主要なOSで動作する共通の環境であり、BashとPythonで処理を書くことでOSへの依存を避けることができる。そこでWindowsでBashとPythonが動作する環境を構築する。具体的な要件は以下の通りとする。

- 64-bit Windows 10で、BashとPythonの対話およびバッチ実行を行う。
- BashからWindowsのファイルシステムを直接扱う。
- Unix/Linuxの各種ツールをWindowsで利用する。
- 文字コードはUTF8とする。

方針
========================================

現在、WindowsでのBashシェル環境で、主要なものは以下の通り。

1. Cygwin
2. MSYS2/MinGW
3. Git for Windowsの付属のBash
4. Windows Subsystem for Linux (WSL)
5. Docker等を利用した仮想的なLinux環境

BashからWindowsのファイルシステムに直接アクセスしたいので、4. WSL と 5. Docker は選択肢から外す。仮想的な環境はストレージの容量を消費することも問題だ。1. Cygwin はよく知られている。GUIのパッケージ管理ツールがあり、長年保守されている。3. Git for Windowsは導入が楽であるが、パッケージ管理の仕組みはない。

今回は、将来にWindowsネイティブアプリのフリーな開発環境を整備することを視野に入れ、2. MSYS2 を採用する。開発環境が必要なら、MSYS2からMinGWを導入する。MSYS2にはPacmanと呼ぶパッケージ管理の仕組みがある。

【参考】Windowsで使えるターミナルとシェルのまとめ
https://qiita.com/Ted-HM/items/9a60f6fcf74bbd79a904



インストールと設定
========================================

Windowsのユーザー名の確認
--------------------

まず、Windowsのユーザー名が空白文字を含まない半角英数字のみであることを確認する。空白文字や日本語文字がユーザー名やユーザーフォルダのパスに含まれると、後々トラブルを抱えることになる。その場合は、Windowsのユーザーをローカルアカウントで作り直す。

Miniconda/Anacondaのインストール
--------------------

Pythonには環境分離の仕組みが欲しい。今回はWindowsで広く採用されているMiniconda/Anacondaを採用する。Miniconda/Anacondaは、Linux版やmacOS版もあると聞く。公式サイトからMinicondaのインストーラをダウンロードして実行する。インストーラで、環境変数`PATH`を通すように指定する。
https://docs.conda.io/en/latest/miniconda.html

Miniconda/Anacondaの管理ツールであるCondaの設定を行う。Condaの古い一部のバージョン（例えば4.6.11）はMSYS2との相性が悪いので、最新版にアップグレードする（4.6.14ではfixされている）。詳細は以下のURLを参照。
https://github.com/conda/conda/issues/8486

```console:コマンドプロンプト（Windows管理者権限で）
conda upgrade conda
conda --version     # バージョン確認
```

MSYS2のインストールと設定
--------------------

続いてMSYS2に進む。公式サイトから MSYS2 のインストーラーをダウンロードして実行する。
    https://msys2.github.io/

MSYS2インストーラーのデフォルトでは、MSYS2の `/home` の実体は、`C:\msys64\home` となる。Linuxから移植された様々なWindowsネイティブのツールが、`C:\Users` 下のユーザーフォルダに設定ファイルを置くことがあり、それをシェル環境でも使いたい。そこで、MSYS2のホームディレクトリをWindowsのユーザーフォルダとするように設定を変更する。テキストエディタで以下のように編集する。

```:C&#058;\msys64\etc\nsswitch.conf
#db_home: cygwin desc   # コメントアウト
db_home: windows        # 追加
```

`C:\msys64\home` フォルダはもう不要なので削除する。

ついでに、パッケージ管理ツールPacmanの設定ファイルを編集する（任意）。

```:C&#058;\msys64\etc\pacman.conf
Color   # コメントアウト
```

さて、Windowsのスタートメニューで MSYS2 64-bit のフォルダを見ると、以下の3つのアイコンを確認できる。

- スタートメニュー
    - MSYS2 64-bit
        - MSYS2 MinGW 32-bit
        - MSYS2 MinGW 64-bit
        - MSYS2 MSYS

これらはそれぞれ独立した環境を指しており、パッケージも別に管理される。以降、使用するのは MSYS2 MinGW 64-bit とする。他の環境は使用しない。（間違って起動しないように、使わないアイコンを削除しても良いかもしれない。）

MSYS2のパッケージを整備する。スタートメニューから MSYS2 MinGW 64-bit を起動し、以下を実行する。

```bash:Bashコンソール
### Download fresh package databases from the server
pacman --sync --refresh

### Upgrade installed packages
pacman --sync --sysupgrade

### Install GNU toolchain, including a MinGW-version of Git (Optional)
pacman --sync base-devel
#pacman --sync mingw-w64-x86_64-toolchain # もし必要なら

### Install Git
pacman --sync ca-certificates
pacman --sync git
git --version # バージョン確認

### Remove old packages from cache directory
pacman --sync --clean
```

なお、MSYS2 64-bitパッケージの一覧は、以下で確認できる。
http://repo.msys2.org/msys/x86_64/

些末な話だが、util-linuxパッケージの最新版（2.26.2-1）には、`script` コマンドが移植されていない。経緯は以下のURLを参照。
https://github.com/Alexpux/MINGW-packages/issues/4497
どうしても欲しければ、以下のように`script` コマンドを含む過去の版から取得する方法がある。なお、完全な動作確認はしていない。

```bash:Bashコンソール
wget http://repo.msys2.org/msys/x86_64/util-linux-2.26.2-1-x86_64.pkg.tar.xz 
pacman --upgrade util-linux-2.26.2-1-x86_64.pkg.tar.xz 
mkdir -p /usr/local/bin
cp /usr/bin/script.exe /usr/local/bin/
pacman --sync --sysupgrade
```

Bashの設定を行う。以下を追記した。

```bash:~/.bash_profile
# 自分好みのコマンドエイリアス
alias ls='ls --color=auto --show-control-chars --time-style=long-iso --human-readable --classify'
alias ll='ls -l'                        # long list
alias la='ls -A'                        # all but . and ..
alias grep='grep --color'               # show differences in colour
alias less='less --raw-control-chars'   # raw control characters
alias whence='type -a'                  # where, of a sort

# Miniconda/Anacondaの設定
#. 'C:/ProgramData/Anaconda3/etc/profile.d/conda.sh' # Anaconda3ならこちら
. '/c/ProgramData/Miniconda3/etc/profile.d/conda.sh' # Miniconda3ならこちら
```

利用方法
========================================

Bashの起動
--------------------

Windowsと他の環境（Linux、macOS等）との差があれば、`~/.bash_profile` 等の設定で吸収する。

対話的にBashを利用するには、コマンドプロンプトで以下を実行する。コードページをUTF8としている点に注意。環境変数`MSYS`の意味は後述。

```console:コマンドプロンプト
CHCP 65001
SET MSYS=winsymlinks:lnk
CALL "C:\msys64\msys2_shell.cmd" -mingw64 -defterm -here -full-path -no-start
```

WindowsのバッチファイルからBashスクリプトを実行するには、以下のようにする。

```:バッチファイル
CHCP 65001
SET MSYS=winsymlinks:lnk
CALL "C:\msys64\msys2_shell.cmd" -mingw64 -defterm -here -full-path -no-start TARGET_SCRIPT.bash
EXIT /B %ERRORLEVEL%
```

Windowsのバッチファイルから単独のMSYS2のコマンドを実行するには、以下のようにする。

```:バッチファイル
CHCP 65001
SET MSYS=winsymlinks:lnk
CALL "C:\msys64\msys2_shell.cmd" -mingw64 -defterm -here -full-path -no-start -c TARGET_COMMAND
EXIT /B %ERRORLEVEL%
```

上記で使用したものを含め、MSYS2関連の主な環境変数には以下がある。細かい挙動については、`msys2_shell.cmd`（これはバッチファイルである）の内容を参考のこと。

- `MSYS`
    - `ls -s` 等のリンクに関する挙動を決める。
    ここの設定は、`msys-2.0.dll` を利用するすべてのプログラムに影響する。
    `winsymlinks:lnk` を指定すると、シンボリックリンクの作成は、Windowsショートカットの作成となる。
    この環境変数が存在しないと、シンボリックリンクを作成しようとすると、ファイルがコピーされるようになる。
- `MSYSTEM`
    - `MINGW64` を指定すると、MSYS2 MinGW 64-bit 環境向けの環境変数`PATH`を構成する。
    `msys2_shell.cmd` の `-mingw64` オプションに対応。
    詳細は `/etc/profile` を参照。
- `MSYS2_PATH_TYPE`
    - `inherit`とすると、シェル環境変数`PATH`の末尾にWindows環境変数`PATH`の項目を追加する。
    `msys2_shell.cmd` の `-full-path` オプションに対応。
    AnacondaのPython含め、Windowsネイティブのコマンドを利用するには、これを使うのが便利である。
    `strict`とすると、Windowsの環境変数`PATH`を継承しない。
    詳細は `/etc/profile` を参照。
- `CHERE_INVOKING`
    - `1` とすると、Bashログイン時に現在のディレクトリを変更しない（つまり、`HOME`環境変数の場所に移動しない）。
    `msys2_shell.cmd` の `-here` オプションに対応。
- `MSYS2_ARG_CONV_EXCL`
    - 親切なことに、MSYS2は、Windowsネイティブなコマンドを実行するとき、
    コマンド自身のパスとその引数に見つかった絶対パスを
    Windows形式（ドライブ文字付き）の絶対パスに変換する。
    コマンド引数に指定したパスがこの値と前方一致する場合、この変換処理の対象から除外する。
    複数指定する場合は、セミコロンで区切る。

MSYS2では、ルートディレクトリにWindowsのドライブが、ドライブレターの小文字でマウントされている。例えば`C:\Users`を指定するには、`/c/Users`とする。

参考までに、MSYS2コンソールからWindowsのプログラムを別ウィンドウで開くには、`START` コマンドを使う。以下に例を示す。

```console:Bashプロンプト
START CMD                       # 別画面でコマンドプロンプトを開く
START CHROME                    # Chromeを起動する
START https://www.google.com/   # Windows既定のWebブラウザでURLを開く
START EXPLORER .                # カレントディレクトリをWindows Explorerで開く
```

Pythonの起動
--------------------

PythonはBash上で使用する。BashでMiniconda/AnacondaのPython環境を切り替えるには、良く知られているように、`conda`コマンドを使う。

```bash:Bashプロンプト
conda activate base
```

参考までに、コマンドプロンプトでMiniconda/AnacondaのPython環境を切り替えるには、（これもWindowsユーザーにはよく知られていることと思うが、）`conda.exe`でなく`conda.bat`を使う。

```console:コマンドプロンプト
call conda.bat activate base
```

今後の調査
========================================

Proxy環境での設定を要確認。以下らしいが、今後検証する。

```:~/.curlrc
# 以下を追記
proxy-user = "user:passwd"
proxy = "http://proxy.com:8080"
```

```:/etc/pacman.conf
# 以下の行コメントを解除
XferCommand = /usr/bin/curl -C - -f %u > %o
```

```:/etc/pacman.d/gnupg/gpg.conf
# 以下を追記
keyserver-options http-proxy=http://user:passwd@proxy.com:8080/
```

```bash:~/.bash_profile
# 以下を追記
export HTTP_PROXY=http://user:passwd@proxy.com:8080/
export HTTPS_PROXY=http://user:passwd@proxy.com:8080/
export FTP_PROXY=http://user:passwd@proxy.com:8080/
```

おわり。