MSYS2のZSHで履歴ファイルが扱えない不具合を修復する

##【はじめに】
MSYS2ではzshパッケージが提供されているので簡単にzsh環境を構築できます。
→  [[MSYS2でWindowsにzsh環境を導入する]](http://qiita.com/magichan/items/7702d7865deaaca2ad44)

しかし、残念ながらMSYS2で提供されているzshはバグがあって履歴ファイルを扱うことが出来ません。

調べてみるとヒストリファイルのロック部に問題があるようで、[本家](https://github.com/Alexpux/MSYS2-packages/issues/129)でも問題が指摘されております。

zshで履歴ファイルが使えないのは個人的に**「ありえない」**ので対策を行いたいとおもいます。


## 【原因解明＆対策方針】
zshのソースコードを追ってみると、履歴ファイルのロック部は*hist.c*ファイル内に記述さている*lockhistfile()*関数で行っています。
この関数をみてみると履歴ファイルのロックファイルを作成する方法として、**symlink()関数**を使っているようで、これが要因となってロックファイルの作成に失敗しているようです　－　結果として履歴ファイルが開けません。

そこで、今回はロックファイルの作成に*symlink()*関数を使用しないようにコードを修正することで対策したいと思います。（幸いなことに*symlink()*関数を使わずに*link()*関数で実装しているコードも`#ifdef`で記述されていますのでこちらを使います）

> **【補足】**
> *symlink()*関数は第一引数に「リンク元のパス」、第二引数に「リンク先（作成するシンボリックリンク）のパス」を渡すのですが、MSYS以外のシステム　－ファイルシステムでシンボリックリンクが扱えるシステム－　では、第一引数のリンク元に存在しないパスを入れてもエラーとして扱わずリンク先が無効なシンボリックリンクを作成し正常終了します。
> zshでは上記のような*symlink()*関数の仕様を利用して、第一引数にロックを保持しているプロセスID等の情報を入力したリンク先が無効なシンボリックリンクを作成してロックファイルとして利用しているのです。
> ところがMSYSではシンボリックリンクが扱えないため、*symlink()*関数は特殊な仕様になっており、内部的に単なるファイルコピーが実行されます。その為、第一引数に入力したリンク元が無効な場合はコピーが出来ずにエラーを返します。zshはこのエラーに当然対応していないため失敗するようです。


##【zshをビルドする環境の準備】 
それではMSYS2上でzshをビルドするためのコンパイル環境の構築から開始します。

まず、コンパイラ（gcc）がインストールされていない場合はインストールします。

```
$ pacman -S gcc gcc-libs
...
$ gcc --version
gcc (GCC) 4.9.2
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
```
次にヘッダファイル・ライブラリ郡をインストールします。

```
$ pacman -S base-devel
$ pacman -S base-devel
:: There are 52 members in group base-devel:
:: リポジトリ msys
   1) asciidoc  2) autoconf  3) autoconf2.13  4) autogen  5) automake-wrapper
   6) automake1.10  7) automake1.11  8) automake1.12  9) automake1.13
   10) automake1.14  11) automake1.6  12) automake1.7  13) automake1.8
   14) automake1.9  15) bison  16) diffstat  17) diffutils  18) dos2unix
   19) file  20) flex  21) gawk  22) gdb  23) gettext  24) gperf  25) grep
   26) groff  27) help2man  28) intltool  29) lemon  30) libtool  31) libunrar
   32) m4  33) make  34) man-db  35) nasm  36) pacman  37) patch
   38) patchutils  39) perl  40) pkg-config  41) pkgfile  42) rcs  43) scons
   44) sed  45) swig  46) texinfo  47) texinfo-tex  48) unrar  49) wget
   50) xmlto  51) yasm  52) yasm-devel

選択して下さい (デフォルト=all):                      <-特に問題ない場合はそのまま[Enter]

...
```
大量のパッケージがインストールされますので、しばらく待つと、MSYS2上にコンパイル環境一式が構築されます。

## 【MSYS2パッケージを作成環境の構築】
次にzshをビルドするためにMSYS2パッケージの[リポジトリ](https://github.com/Alexpux/MSYS2-packages)からMSYS2のパッケージ開発の環境一式を取得します。

リポジトリからの環境取得は**git**を使用しますので、もしインストールしていない場合はインストールします。

```
$ pacman -S git
...
$ git --version
git version 2.2.0
```

次に適当な作業エリアを作成して

```
$ mkdir workspace

$ cd workspace
```
MSYS2のパッケージ開発の環境一式を取得します

```
$ git clone https://github.com/Alexpux/MSYS2-packages.git
...

$ cd MSYS2-packages

$ ls
apr                                       mpfr
apr-util                                  msys2-installer
asciidoc                                  msys2-keyring
aspell                                    msys2-runtime
aspell-en                                 msys2-unlocker
autoconf                                  msys2-w32api-headers
autoconf2.13                              msys2-w32api-runtime
autogen                                   nano
automake1.10                              nano-syntax-highlighting-git
automake1.11                              nasm
automake1.12                              ncurses
...
```
これzshをビルドする為の環境がすべてそろいました。

## 【zshをビルドする】
今回はzshを作るので*/zsh*ディレクトリに移動します。

```
$ cd zsh

$ ls
add-pwd-W-option.patch  msysize.patch  zprofile     zsh-doc.install
Makefile.in.patch       PKGBUILD       zsh.install
```

今回の「ロックファイルの作成に*symlink()*関数を使用しないようにする」為のソースコード修正は単純に*hist.c* の`#ifdef SYMLINK` の行を全て`#if 0` に置き換えるだけです。
今回はpatchファイルを作らずに単純に**sed**を使って書き換えることにします。

これは*zsh*ディレクトリ以下にある*PKGBUILD*ファイルを編集して

```PKGBUILD.
    ...
    patch -p0 -i "${srcdir}/Makefile.in.patch"
    patch -p1 -i "${srcdir}/add-pwd-W-option.patch"
    patch -p1 -i "${srcdir}/msysize.patch"
    sed -i -e 's/ifdef HAVE_SYMLINK/if 0/g' Src/hist.c         <------この行を追加
    ...
```
と一行追加するだけでＯＫです。
早速パッケージを作成してみます。パッケージの作成は**makepkg**コマンドを使用します。

```
$ makepkg -s
==> パッケージを作成: zsh 5.0.7-3 (2014年 11月 30日 日曜日 18:05:20    )
==> ランタイムの依存関係を確認...
==> ビルドタイムの依存関係を確認...
==> ソースを取得...
...
（中略）
...
==> エラー: ファイルが整合性チェックをパスしませんでした！
```

？？？
私の環境でばなぜかエラーがでましたので、とりあえずチェックサム検証をスキップすることで対応します。

```
$ makepkg -s --skipchecksums
==> パッケージを作成: zsh 5.0.7-3 (2014年 11月 30日 日曜日 18:05:20    )
==> ランタイムの依存関係を確認...
==> ビルドタイムの依存関係を確認...
==> ソースを取得...
...
(中略)
...
==> インストールを整理...
  -> 不要なファイルを削除...
  -> libtool ファイルを削除...
  -> man と info ページを圧縮...
  -> バイナリとライブラリから不要なシンボルを削除...
==> パッケージを作成 "zsh-doc"...
  -> .PKGINFO ファイルを生成...
  -> install ファイルを追加...
  -> .MTREE ファイルを生成...
  -> パッケージの圧縮...
==> 作成完了: zsh 5.0.7-3 (2014年 11月 30日 日曜日 18:11:49    )
```
このように表示されると完成です。再度*zsh*ディレクトリを見ると、

```
$ ls
add-pwd-W-option.patch  pkg          zsh-5.0.7.tar.bz2
config.guess            PKGBUILD     zsh-5.0.7-3-x86_64.pkg.tar.xz
config.sub              src          zsh-5.0.7-doc.tar.bz2
Makefile.in.patch       zprofile     zsh-doc.install
msysize.patch           zsh.install  zsh-doc-5.0.7-3-x86_64.pkg.tar.xz
```

パッケージファイル *zsh-5.0.7-3-x86_64.pkg.tar.xz* が作成されているのがわかります。
早速パッケージファイルをインストールしてみます。

```
$ pacman -U zsh-5.0.7-3-x86_64.pkg.tar.xz
パッケージをロード...
警告: zsh-5.0.7-3 は最新です -- 再インストール
...
...
```

##【動作確認】
今回の修正で履歴ファイルが扱えるかを確認をします。

~/.zshrcに

```.zshrc.
HISTFILE=~/.zsh_history
HISTSIZE=10000
SAVEHIST=10000
```
を追加してzshを起動してみます。

```
% ls -a
.   .bash_history  .bashrc   .minttyrc   .zcompdump    .zshrc
..  .bash_profile  .inputrc  .tmux.conf  .zsh_history  work
```
問題なく履歴ファイルが作成されているようです。
中身を確認してみると・・

```
% cat .zsh_history
: 1417167947:0;ls -a
: 1417167964:0;cat .zsh_history

$
```
問題無く履歴が書き込まれているようです。