あーかいぶすハイディフィニション

ここはもう更新しとらんのじゃ

人類が改善した GC の恩恵を受けるために Ruby 2.2.1 を導入してインストールする時の注意点とは……!

最初に言っておきますがインストール手順記事であって GC 要素はありません(がっくり)。

ロケ地:CentOS7 64bit

とりあえずいつものようにインストールしてみる

libyaml は各自インストールしておいてください。
libffi は、libffi.x86_64 は入ってるかもしれませんが、-devel パッケージは入ってないかもしれぬので、以下のように。
( 32bit の人は .i686 パッケージかな )

[root@localhost ~]# yum install libffi.x86_64 libffi-devel.x86_64
[root@localhost ~]# cd /usr/local/src
[root@localhost src]# wget http://cache.ruby-lang.org/pub/ruby/2.2/ruby-2.2.1.tar.gz
[root@localhost src]# tar -zxvf ruby-2.2.1.tar.gz
[root@localhost src]# cd ruby-2.2.1
[root@localhost ruby-2.2.1]# ./configure --prefix=/usr/local
[root@localhost ruby-2.2.1]# make

libffi 周りでエラー出る。

LANG=C の場合
make[2]: Entering directory `/usr/local/src/ruby-2.2.1/ext/fiddle'
linking shared-object fiddle.so
/usr/bin/ld: ./libffi-3.2.1/.libs/libffi.a(raw_api.o): relocation R_X86_64_32S against `.rodata' can not be used when making a shared object; recompile with -fPIC
./libffi-3.2.1/.libs/libffi.a: could not read symbols: Bad value
collect2: error: ld returned 1 exit status
make[2]: *** [../../.ext/x86_64-linux/fiddle.so] Error 1
make[2]: Leaving directory `/usr/local/src/ruby-2.2.1/ext/fiddle'
make[1]: *** [ext/fiddle/all] Error 2
make[1]: Leaving directory `/usr/local/src/ruby-2.2.1'
make: *** [build-ext] Error 2
LANG=ja_JP.UTF-8 の場合
make[2]: ディレクトリ `/usr/local/src/ruby-2.2.1/ext/fiddle' に入ります
linking shared-object fiddle.so
/usr/bin/ld: ./libffi-3.2.1/.libs/libffi.a(raw_api.o): 再配置 R_X86_64_32S (`.rodata' に対する) は共有オブジェクト作成時には使用できません。-fPIC を付けて再コンパイルしてください。
./libffi-3.2.1/.libs/libffi.a: シンボルを読み込めませんでした: 不正な値です
collect2: エラー: ld はステータス 1 で終了しました
make[2]: *** [../../.ext/x86_64-linux/fiddle.so] エラー 1
make[2]: ディレクトリ `/usr/local/src/ruby-2.2.1/ext/fiddle' から出ます
make[1]: *** [ext/fiddle/all] エラー 2
make[1]: ディレクトリ `/usr/local/src/ruby-2.2.1' から出ます
make: *** [build-ext] エラー 2

何もせずこのまま逃げ切りたい場合

enable-shared オプションを利用することで回避できる、というお告げがあります。
Ruby 2.2.0 Released - Ruby-dev - Ruby-Forum

[root@localhost ruby-2.2.1]# ./configure --prefix=/usr/local --enable-shared
[root@localhost ruby-2.2.1]# make
[root@localhost ruby-2.2.1]# make install
[root@localhost ruby-2.2.1]# ruby -v
ruby 2.2.1p85 (2015-02-26 revision 49769) [x86_64-linux]
[root@localhost ruby-2.2.1]# which ruby
/usr/local/bin/ruby

やったぜ。

本題: ./configure そのまま通らないの小生きもちわるくてやだ!なんとかしたい!

以下のように、無事バグ認定されたようです。という訳で diff とって patch 作って修正してみましょう!ヘーキヘーキ、簡単だから!
Bug #10960: libffiのビルドの不具合? - Ruby trunk - Ruby Issue Tracking System

patch つくる
[root@localhost src]# tar -zxvf ruby-2.2.1.tar.gz
[root@localhost src]# vi fiddle_extconf.rb
->
上記の URL から rev 49957 の ext/fiddle/extconf.rb をコピペなりでもってきてファイルを保存する
[root@localhost src]# diff -u /usr/local/src/ruby-2.2.1/ext/fiddle/extconf.rb /usr/local/src/fiddle_extconf.rb > fiddle_extconf.patch
patch 適用して導入してみる
[root@localhost src]# patch -u /usr/local/src/ruby-2.2.1/ext/fiddle/extconf.rb < /usr/local/src/fiddle_extconf.patch
patching file /usr/local/src/ruby-2.2.1/ext/fiddle/extconf.rb
[root@localhost src]# cd ruby-2.2.1
[root@localhost ruby-2.2.1]# ./configure --prefix=/usr/local
[root@localhost ruby-2.2.1]# make
[root@localhost ruby-2.2.1]# make install
[root@localhost ruby-2.2.1]# ruby -v
ruby 2.2.1p85 (2015-02-26 revision 49769) [x86_64-linux]
[root@localhost ruby-2.2.1]# which ruby
/usr/local/bin/ruby

や、やったー!

まとめ

    • enable-shared オプションつけるか、patch 作って適用するか、来るべき ruby.2.2.2 か 2.2.1 のアップデートを待つと解決できます。

おまけ

うちの環境で作った diff おいとくんで、こいつをパッチファイルとして使ってもなんとかなると思います、使うときは自己責任でね?

--- /usr/local/src/ruby-2.2.1/ext/fiddle/extconf.rb	2015-04-06 18:49:49.000000000 +0900
+++ /usr/local/src/fiddle_extconf.rb	2015-04-06 18:51:33.000000000 +0900
@@ -2,7 +2,8 @@
 
 # :stopdoc:
 
-if ! enable_config('bundled-libffi', false)
+bundle = enable_config('bundled-libffi')
+if ! bundle
   dir_config 'libffi'
 
   pkg_config("libffi") and
@@ -16,7 +17,8 @@
   end and (have_library('ffi') || have_library('libffi'))
 end or
 begin
-  ver = Dir.glob("#{$srcdir}/libffi-*/")
+  ver = bundle != false &&
+        Dir.glob("#{$srcdir}/libffi-*/")
         .map {|n| File.basename(n)}
         .max_by {|n| n.scan(/\d+/).map(&:to_i)}
   unless ver
@@ -36,7 +38,7 @@
   end
   libffi.include = "#{libffi.builddir}/include"
   libffi.lib = "#{libffi.builddir}/.libs"
-  libffi.a = "#{libffi.lib}/libffi.#{$LIBEXT}"
+  libffi.a = "#{libffi.lib}/libffi_convenience.#{$LIBEXT}"
   nowarn = CONFIG.merge("warnflags"=>"")
   libffi.cflags = RbConfig.expand("$(CFLAGS)", nowarn)
   ver = ver[/libffi-(.*)/, 1]
@@ -46,6 +48,9 @@
   libffi.ldflags = RbConfig.expand("$(LDFLAGS) #{libpathflag([relative_from($topdir, "..")])} #{$LIBRUBYARG}")
   libffi.arch = RbConfig::CONFIG['host']
   if $mswin
+    unless find_executable(as = /x64/ =~ libffi.arch ? "ml64" : "ml")
+      raise "missing #{as} command."
+    end
     $defs << "-DFFI_BUILDING"
     libffi_config = "#{relative_from($srcdir, '..')}/win32/libffi-config.rb"
     config = CONFIG.merge("top_srcdir" => $top_srcdir)
@@ -64,9 +69,10 @@
   ld = RbConfig::CONFIG['LD']
   args.concat %W[
     --srcdir=#{libffi.srcdir}
-    --disable-shared --host=#{libffi.arch}
+    --host=#{libffi.arch}
     --enable-builddir=#{RUBY_PLATFORM}
   ]
+  args << ($enable_shared || !$static ? '--enable-shared' : '--enable-static')
   args << libffi.opt if libffi.opt
   args.concat %W[
       CC=#{cc} CFLAGS=#{libffi.cflags}
@@ -77,8 +83,14 @@
   FileUtils.rm_f("#{libffi.include}/ffitarget.h")
   Logging::open do
     Logging.message("%p in %p\n", args, opts)
-    system(*args, **opts) or
+    unless system(*args, **opts)
+      begin
+        IO.copy_stream(libffi.dir + "/config.log", Logging.instance_variable_get(:@logfile))
+      rescue SystemCallError => e
+        Logfile.message("%s\n", e.message)
+      end
       raise "failed to configure libffi. Please install libffi."
+    end
   end
   if $mswin && File.file?("#{libffi.include}/ffitarget.h")
     FileUtils.rm_f("#{libffi.include}/ffitarget.h")