MSYS2のRuby 2.3.0でRubygemsを利用できるようにする


**2016/03/30 Update**

「既知の問題」の項に現在未解決の問題を追記しました。

## はじめに

`pacman`からインストールできる`ruby`を利用した場合、`gem install`で以下のようなエラーが出てしまい利用できない。

```shell-session
$ gem install sequel
/usr/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require': cannot load such file -- win32/resolv (LoadError)
```

`win32`モジュールがインストールされていないため発生している。
cygwinだと[そもそも`win32`モジュールを読まない](http://srad.jp/~t-nissie/journal/599533/)という解決策もあるらしいが、私がMSYS2で試したところ動かなかったためきちんとパッチを当ててビルドしなおすことにした。

## 修正パッチ

適当にgithubのリポジトリを眺めていると、[この辺りのcommit](https://github.com/ruby/ruby/commit/9bfa5d917f8cb3e123a24c86813c191d05fcf53b)を取り込めばうまく行きそうだ。
ただし、この場合`$cygwin`しか対象にしていないため、[MSYS2-packagesの 	ruby-2.3.0-msys2.patch](https://github.com/Alexpux/MSYS2-packages/blob/master/ruby/ruby-2.3.0-msys2.patch)で増やされた`$msys`を使うよう少し手を加える。

```diff:2.3.0-add-cygwin-case.patch
--- a/ext/extmk.rb
+++ b/ext/extmk.rb
@@ -494,7 +494,10 @@ def $mflags.defined?(var)
 ext_prefix = "#{$top_srcdir}/ext"
 exts = $static_ext.sort_by {|t, i| i}.collect {|t, i| t}
 default_exclude_exts =
-  if $mswin or $mingw
+  case
+  when $cygwin, $msys
+    %w''
+  when $mswin, $mingw
     %w'pty syslog'
   else
     %w'*win32*'
```

## PKGBUILD

上記パッチを当てて、さらにデフォルトの`ruby`パッケージと同名にしていると`pacman -Syu`するときにリポジトリのバージョンに戻ってしまうため`/usr/local`にインストールするようにしてパッケージ名も変えてみた`PKGBUILD`が以下となる。
`2.3.0-add-cygwin-case.patch`以外のファイルは[MSYS2-packageの`ruby`パッケージ](https://github.com/Alexpux/MSYS2-packages/tree/master/ruby)のものであるため、そちらから適時取り出していただきたい。

```bash:PKGBUILD
# Maintainer: Koutarou Tanaka <from.kyushu.island@gmail.com>

pkgname=('ruby-local' 'ruby-local-docs')
pkgver=2.3.0
pkgrel=2
arch=('i686' 'x86_64')
url='https://www.ruby-lang.org/en/'
license=('BSD' 'custom')
makedepends=('openssl-devel' 'libffi-devel' 'doxygen' 'libcrypt-devel'  'gmp-devel' 'libyaml-devel' 'libgdbm-devel' 'libiconv-devel' 'libreadline-devel' 'zlib-devel')
options=('!emptydirs' '!makeflags' 'staticlibs')
source=("https://cache.ruby-lang.org/pub/ruby/${pkgver%.*}/ruby-${pkgver//_/-}.tar.bz2"
        1.8.7-cygwin-tcltk.patch
        2.0.0-cygwin-configure.patch
        2.0.0-cygwin-rubygems.patch
        2.2.2-cygwin-compile.patch
        2.0.0-pkgconfig-version.patch
        'gemrc'
        'ruby-2.3.0-msys2.patch'
        2.3.0-add-cygwin-case.patch)
sha256sums=('ec7579eaba2e4c402a089dbc86c98e5f1f62507880fd800b9b34ca30166bfa5e'
            '3453f6b8a77b3a3284b217264769287c29e00e5c3b0e535aeee6a17a4d898258'
            'd8a54a6c57d31411916ae115a798023115dcbca63faf8f3b5ccd91f4bdbd1215'
            '4ae2a314b2942518b48424fc93e5043776bfaf1e84519655af6ba35c3284abff'
            '5fffe4fa469721bfe271650dae142c5a0274c22705e4be01541371d74a5de23d'
            'd74c014e3b5ff848df86c071e8562e699c4488f156c22d3a76d87fab8b9c95d8'
            '4bb7eb2fe66e396ed16b589cdb656831407b39ad4e138d88536754c0448ac614'
            'e8acdc2de2a267b130f10c423e41fb3e9d4902a4e77eadaa655257b23a47a805'
            '92de14208b36387819b3d59f71ca9031d2d09f14be67d7e62e2f0b40535d8643')

prepare() {
  cd ${srcdir}/ruby-${pkgver//_/-}
  patch -p2 -i ${srcdir}/1.8.7-cygwin-tcltk.patch
  patch -p2 -i ${srcdir}/2.0.0-cygwin-configure.patch
  patch -p2 -i ${srcdir}/2.0.0-cygwin-rubygems.patch
  patch -p2 -i ${srcdir}/2.2.2-cygwin-compile.patch
  patch -p2 -i ${srcdir}/2.0.0-pkgconfig-version.patch
  patch -p1 -i ${srcdir}/2.3.0-add-cygwin-case.patch
  patch -p1 -i ${srcdir}/ruby-2.3.0-msys2.patch
  autoreconf -fi
}

build() {
  mkdir -p ${srcdir}/build-${CHOST} && cd ${srcdir}/build-${CHOST}

  CFLAGS+=" -fno-strict-aliasing "
  CXXFLAGS+=" -fno-strict-aliasing "
  ../ruby-${pkgver//_/-}/configure \
    --build=${CHOST} \
    --prefix=/usr/local \
    --exec_prefix=/usr/local \
    --sysconfdir=/usr/local/etc \
    --localstatedir=/var \
    --sharedstatedir=/var/lib \
    --libexecdir=/usr/local/lib/ruby \
    --enable-shared \
    --disable-rpath \
    --with-dbm-type=gdbm_compat \
    LDSHARED="gcc -shared" \
    DLDFLAGS="-Wl,--export-all-symbols"

  make
}

check() {
  cd ruby-${pkgver//_/-}

  make test
}

package_ruby-local() {
  pkgdesc='An object-oriented language for quick and easy programming'
  depends=('gcc-libs' 'libopenssl' 'libffi' 'libcrypt'  'gmp' 'libyaml' 'libgdbm' 'libiconv' 'libreadline' 'zlib')
  optdepends=(#'tk: for Ruby/TK'
              'ruby-local-docs: Ruby documentation')
  provides=('rubygems-local' 'rake-local')
  conflicts=('rake-local')
  backup=('etc/gemrc')
  install='ruby.install'

  cd ${srcdir}/build-${CHOST}

  make DESTDIR="${pkgdir}" install-nodoc

  install -D -m644 ${srcdir}/gemrc "${pkgdir}/usr/local/etc/gemrc"

  install -D -m644 ${srcdir}/ruby-${pkgver//_/-}/COPYING "${pkgdir}/usr/local/share/licenses/ruby/LICENSE"
  install -D -m644 ${srcdir}/ruby-${pkgver//_/-}/BSDL "${pkgdir}/usr/local/share/licenses/ruby/BSDL"
}

package_ruby-local-docs() {
  pkgdesc='Documentation files for ruby'

  cd ${srcdir}/build-${CHOST}

  make DESTDIR="${pkgdir}" install-doc install-capi

  install -D -m644 ${srcdir}/ruby-${pkgver//_/-}/COPYING "${pkgdir}/usr/local/share/licenses/ruby-docs/LICENSE"
  install -D -m644 ${srcdir}/ruby-${pkgver//_/-}/BSDL "${pkgdir}/usr/local/share/licenses/ruby-docs/BSDL"
}
```

しばらく静観しているがどうにも修正される気配がないので、近々PRを送るかもしれない。

**2016/03/31 Update**

静観していたら[当問題のIssue](https://github.com/Alexpux/MSYS2-packages/issues/515)が立てられたが、[これを解決するためのPRが斜め上](https://github.com/Alexpux/MSYS2-packages/commit/05e121b507568e9b6578de874c3604766203561e)で驚いている。
どうやら[RubyのIssue](https://bugs.ruby-lang.org/issues/12071)に添付されているpatchを参考としているようだが、このPRを投げた人はIssueのコメントを見ていないのだろうか...。

> Since Cygwin does not have its own resolv.conf file, it is not correct.
(https://bugs.ruby-lang.org/issues/12071#note-1)

githubのIssueを見ると「この日本語の記事と同じ問題が発生したよ」と当記事のURLが貼られていることに気付いた。
日本語で書いた私が悪いのだが、パッチ部分を見れば対応が異なることぐらい分かるだろうに...。
近々修正PRを投げることにする。

**2016/04/04 Update**

適用済みのパッチでは困る理由を探しているのだが、特に困ることが見当たらなくて困る。
恐らく`Resolv.getaddress`を現時点最新の`ruby-2.3.0-2`で実行すると`ResolvError`が発生するはずだが、ネットワークの都合上試せないでいる。
これで`ResolvError`が発生すればバグレポートと共にPRを投げるのだが、当てが外れればまた別の問題を探さなければならない。

## 既知の問題

これだけでは`nokogiri`や`mysql2`と言ったC拡張を含むgemを利用する際に問題が出る場合がある。

### C拡張を含むgemをコンパイルして利用する場合

- msys版とmingw/mswin版を併用
- C拡張を含むgemをプリコンパイル版ではなく通常版(`--platform=ruby`)をインストール
- gemのインストール先をユーザーディレクトリ(`--user-install`)にしている

この場合、C拡張をコンパイルして作成するバイナリがmsys版とmingw/mswin版のどちらかしか保持できないため、どちらかでしか利用できない。
インストールディレクトリをmsys版とmingw/mswin版で共有しているのが問題であるため、環境変数`GEM_HOME`にプラットフォームごとのディレクトリを別途指定するか、`--no-user-install`を付与してユーザーディレクトリを使用しないようにする等のディレクトリを分けるようにすれば解決できる。

### C拡張を含むgemのプリコンパイル版を作成する場合

例えば`nokogiri`のソースコードをgithubから持ってきてプリコンパイル版のgemを作成する場合、msys版はインストール出来たとしても実際には`require`できない状態となる。
削除しようとしたとき、末尾に`-msys`ではなく`-unknown`と付いてしまうので、Rubygemsが元々なかった`msys`を認識できていないようだ。
こちらはRubygemsが`msys`を認識するように修正しなければならないため、今のところ解決策はない。