きりかノート 3冊め

おあそびプログラミング

Clangでruby-1.8.7をコンパイルしてみる (3) サヨウナラ、gcc

たぶん対応できた。っていうかMacPortsはもう使用可能にしちゃった。r95753

http://d.hatena.ne.jp/kimuraw/20120628/p1 http://d.hatena.ne.jp/kimuraw/20120712/p1 のつづき。bignumの問題は解決したけど、クラッシュするケースがあるというのが宿題でした。

作業記録

まずはクラッシュするケースを絞り込みしたところ、

  1. OK: ふつうにconfigure && makeしたもの
  2. OK: MacPortsでuniversalでないもの
  3. OK: MacPortsで+universalで"i386" (32bit)
  4. NG: MacPortsで+universalで"x86_64" (64bit)

ということになった。NGってのは

   ./lib/fileutils.rb:1428: [BUG] unexpected local variable
   ruby 1.8.7 (2012-02-08 patchlevel 358) [x86_64-darwin11]

になる件。

2番目と4番目で結果がちがうのは、ちょっとおかしい。こういうときはとりあえず、Makefileとかconfig.hを比較してみるのがとっかかり。

   --- config.h-i686	2012-07-21 13:50:29.000000000 +0900
   +++ config.h-universal-x86_64	2012-07-21 13:45:50.000000000 +0900
   @@ -5,7 +5,6 @@
    #define PACKAGE_STRING ""
    #define PACKAGE_BUGREPORT ""
    #define PACKAGE_URL ""
   -#define USE_BUILTIN_FRAME_ADDRESS 1
    #define STDC_HEADERS 1
    #define HAVE_SYS_TYPES_H 1
    #define HAVE_SYS_STAT_H 1
   @@ -214,7 +213,7 @@
    #define RUBY_SITE_LIB2 "/opt/local/lib/ruby/site_ruby/1.8"
    #define RUBY_VENDOR_LIB "/opt/local/lib/ruby/vendor_ruby"
    #define RUBY_VENDOR_LIB2 "/opt/local/lib/ruby/vendor_ruby/1.8"
   -#define RUBY_PLATFORM "i686-darwin11"
   -#define RUBY_ARCHLIB "/opt/local/lib/ruby/1.8/i686-darwin11"
   -#define RUBY_SITE_ARCHLIB "/opt/local/lib/ruby/site_ruby/1.8/i686-darwin11"
   -#define RUBY_VENDOR_ARCHLIB "/opt/local/lib/ruby/vendor_ruby/1.8/i686-darwin11"
   +#define RUBY_PLATFORM "x86_64-darwin11"
   +#define RUBY_ARCHLIB "/opt/local/lib/ruby/1.8/x86_64-darwin11"
   +#define RUBY_SITE_ARCHLIB "/opt/local/lib/ruby/site_ruby/1.8/x86_64-darwin11"
   +#define RUBY_VENDOR_ARCHLIB "/opt/local/lib/ruby/vendor_ruby/1.8/x86_64-darwin11"

i686x86_64がちがってるのは良いとして、USE_BUILTIN_FRAME_ADDRESSがuniversalのほうにない。

configureを見てみると、このあたりでUSE_BUILTIN_FRAME_ADDRESSを処理してるね。

    2723 case $target_cpu in
    2724   i?86) frame_address=yes;;
    2725   *)    frame_address=no;;
    2726 esac
    2727 # Check whether --enable-frame-address was given.
    2728 if test "${enable_frame_address+set}" = set; then :
    2729   enableval=$enable_frame_address; frame_address=$enableval
    2730 fi
    2731
    2732 if test $frame_address = yes; then
    2733     $as_echo "#define USE_BUILTIN_FRAME_ADDRESS 1" >>confdefs.h

うん。+universalのときac_cv_buildでx86_64渡してるのが原因ですね。--enable_frame_addressをconfigureに渡すようにしてもよかったんだけど、いつ渡すべきかをPortfile側で制御するのがけっこうめんどうだったので、configure側にパッチいれることに。

今度は別のシステムでSEGVが起きた。同様にconfig.hを比べてみる(これは32/64での比較)。

   --- config.h-i386@u	2012-07-21 15:51:31.000000000 +0900
   +++ config.h-x86_64@u	2012-07-21 15:51:00.000000000 +0900
   @@ -25,14 +25,14 @@
    #define HAVE_OFF_T 1
    #define SIZEOF_INT 4
    #define SIZEOF_SHORT 2
   -#define SIZEOF_LONG 4
   +#define SIZEOF_LONG 8
    #define SIZEOF_LONG_LONG 8
     :
    #define rb_uid_t uid_t
   @@ -198,9 +198,8 @@
    #define FILE_COUNT _r
    #define FILE_READPTR _p
    #define NEED_IO_SEEK_BETWEEN_RW 1
   -#define HUGE_ST_INO 1
    #define HAVE__SC_CLK_TCK 1
   -#define STACK_GROW_DIRECTION -1
   +#define STACK_GROW_DIRECTION +1
    #define _REENTRANT 1
     :

STACK_GROW_DIRECTION +1はおかしいような。同じように$target_cpuかな?

    9845 case "$target_cpu" in
    9846 m68*|i?86|ia64|sparc*|alpha*) rb_cv_stack_grow_dir=-1;;
    9847 hppa*) rb_cv_stack_grow_dir=+1;;
    9848 esac
    9849 { $as_echo "$as_me:${as_lineno-$LINENO}: checking stack growing direction" >&5
    9850 $as_echo_n "checking stack growing direction... " >&6; }
    9851 if test "${rb_cv_stack_grow_dir+set}" = set; then :
    9852   $as_echo_n "(cached) " >&6
    9853 else
    9854   if test "$cross_compiling" = yes; then :
    9855   rb_cv_stack_grow_dir=0
    9856 else

ビンゴ!

他に$target_cpuが/i.86/的な処理をしているところがないか、ざっと見たところはなさそう。で、結果的にconfigureに以下のパッチを当てることに。

   --- configure.orig  2012-06-29 22:18:24.000000000 +0900
   +++ configure       2012-07-21 16:32:51.000000000 +0900
   @@ -2722,6 +2722,7 @@

    case $target_cpu in
      i?86) frame_address=yes;;
   +  x86_64) frame_address=yes;;
      *)    frame_address=no;;
    esac
    # Check whether --enable-frame-address was given.
   @@ -9843,7 +9844,7 @@
    fi

    case "$target_cpu" in
   -m68*|i?86|ia64|sparc*|alpha*) rb_cv_stack_grow_dir=-1;;
   +m68*|i?86|x86_64|ia64|sparc*|alpha*) rb_cv_stack_grow_dir=-1;;
    hppa*) rb_cv_stack_grow_dir=+1;;
    esac
    { $as_echo "$as_me:${as_lineno-$LINENO}: checking stack growing direction" >&5

今回の成果

  • CFLAGS=-Os
  • bignumパッチ
  • configureで$target_cpu=x86_64をi686と同様に扱う

という対処をすることで、clangでtest-allが(gccの時と同程度に)通るようになったよ!テストしたのは以下のパターン。

これで自分持ちのMacPortsはMountain Lionの準備ができた、はず。apple-gcc42とか、いつ使えなくなってもおかしくないしね。それによって「ビルドできない」とかのレポートに対応するのはイヤなのです。

長かった…ようやくRubyCocoaに取りかかれる。

パッチどうしようか?

そりゃもちろん本家に取り込んでほしいけど、そもそもclangはサポート範囲じゃないからねえ。$target_cpu=x86_64とか完全にこっちの都合だし。

FreeBSDもclang化を進めてると思うのだけど、どうなってんだろか。