きりかノート 3冊め

おあそびプログラミング

MacPorts で port install ruby +universal が失敗する理由

rabbit-shockers で追求されたので記憶をたどりながら調べてみた。

MacPorts の +universal

TN2137 にあるように、CFLAGS と LDFLAGS に作成するアーキテクチャを -arch オプションで列挙していけばよい。これによって、それぞれのアーキテクチャをビルドして、lipo でファットバイナリ化するという手続きをコンパイラがやってくれる。

MacPorts では、configure && make && make install スタイルのソフトウェアには、あらかじめ universal バリアントが用意されている。universal バリアントを追加したときは、configure オプションが設定される。くわしくは、portconfigure.tclportmain.tcl を参照のこと。

universal ruby はどこで失敗するか

簡単に実験。ターゲットは素の ruby-1.8.6-p111

 % CFLAGS="-arch ppc -arch i386" LDFLAGS="-arch ppc -arch i386" \
./configure --enable-shared && make
:
:
making ruby
gcc -arch ppc -arch i386 -fno-common -pipe -fno-common -DRUBY_EXPORT -L.
-arch ppc -arch i386 main.o -lruby -ldl -lobjc -o ruby
ld: warning in ./libruby.dylib, file is not of required architecture
Undefined symbols for architecture ppc:
"_ruby_options", referenced from:
_main in main.o
"_ruby_run", referenced from:
_main in main.o
"_ruby_init", referenced from:
_main in main.o
"_ruby_init_stack", referenced from:
_main in main.o
ld: symbol(s) not found for architecture ppc
collect2: ld returned 1 exit status
lipo: can't open input file: /var/folders/5T/5TkNBDNhGRyDkhxmhrRcOU+++TM/-T
mp-//cca2jxgL.out (No such file or directory)
make[1]: *** [ruby] Error 1
make: *** [all] Error 2

となりました。libruby に ppc アーキテクチャのコードがないために ruby (コマンド)のビルドに失敗する。

原因は libruby.dylib のビルドに利用されるコンパイラフラグの LDSHARED に適切な値が設定されないため。

configure.in

 1055         darwin*)        : ${LDSHARED='cc -dynamic -bundle -undefined suppre     ss -flat_namespace'}

ちなみに --enable-shared しなければ、libruby.a および rubyユニバーサルバイナリで正常にビルドできる。

じゃ Apple はどうしているのか

原因は LDSHARED にリンカオプションを渡せないことはわかった。じゃ、MacOSX に含まれる ruby ではどうしているのって話になるよな。

簡単なこと、configure を変更しているのだ patch-configure

ここでは、RC_CFLAGS という値を追加して LDSHARED および LIBRUBY_LDSHARED で利用するようになっている。この RC_CFLAGS が -arch オプションを含んでいる。RC_CFLAGS はMakefile(rubyソースの上階層のほう)

 22 include $(MAKEFILEPATH)/CoreOS/ReleaseControl/GNUSource.make

で、/Developer/Makefiles/CoreOS/ReleaseControl/Common.make

 48 RC_ARCHS   = $(shell for i in `file /usr/lib/libSystem.B.dylib | grep 'share    
d library ' | sed 's|.*shared library ||'`; do $(CC) -arch $$i -E -x c /dev/
null > /dev/null 2>&1 && echo $$i; done)

から来ているっぽいのだけど、RC_ARCHS -> RC_CFLAGS の経路が見つけられず。

(2008/1/30 追記:Tiger 10.4.11 についてもざっと確認。同じように RC_CFLAGS を追加している)

けつろん

LDSHARED をどうにかすれば、ユニバーサルバイナリruby を configure のオプションだけで作ることができるようになるはず。じゃ、どう解決するかがこれから考えるところ。

darwin のとき、LDFLAGS を追加するようにするだけでよいかなあ。