2008-09-04

透過的なLLVM (1)

自由なUNIXに似たシステムのパッケージシステムは、Autotoolsの分厚い皮がすこし日焼けしたようなものだ。魔法の四行詩(たいていの場合、make checkは抜かすだろうけれど)を諳んじるのだ。

./configure
make
make check
make install

この四行はUNIXの範疇にある。shが実行され、makeが実行される。それらが呼び出すコマンドがUNIXの範疇にあるかどうかは保証されない。SUSv3が定義するCコンパイラはc99だけど、それが存在するかどうかは判らない(自由なUNIXに似たシステムはUNIXじゃないからね)。

目標は、畢竟、ぼくたちのC++のコードがリンクする全ての静的ライブラリをbitcodeで表現すること、最後の最後に最適化をかけることだ。実際問題、ユーザランドで動作する使い勝手の良いライブラリ、特に様々なメディアを扱うライブラリはLLVMの恩恵を受けやすい。C++のライブラリがヘッダー主体になって久しいが、それだって内部では昔ながらのCのライブラリを呼び出している。

makeと呪いを唱える。現実に即し、乱暴に述べるなら、ほとんどの場合、GNU Compiler Collectionが呼び出される。GNU Compiler Collectionは魔術的にリンカを呼び出す。

gcc -Wall -O2 -g -c foo.c
gcc -Wall -O2 -g -c bar.c
ar rc libfoobar.a foo.o bar.o
ranlib libfoobar.a
gcc -Wall -O2 -g baz.c -L. -lfoobar -lm -o baz

人工的だけど典型的で例だ(実際、bzip2のMakefileはこんな感じだ)。-vオプションを与えると、gccは内部で呼び出すコマンドを表示する。本当に呼び出しているコマンドを知るためにはdtrace(あるいは他のなにか)を使用する。Mac OS X 10.5では/usr/bin/gccは/usr/bin/gcc-4.0のシンボリックリンクだ。最後の一行を実行すると、コンパイルのためにcc1とasが、リンクのためにcollect2そしてldが呼び出される。

  • /usr/bin/gcc-4.0
    • /usr/bin/i686-apple-darwin9-gcc-4.0.1
      • /usr/libexec/gcc/i686-apple-darwin9/4.0.1/cc1
      • /usr/libexec/gcc/i686-apple-darwin9/4.0.1/as
      • /usr/libexec/gcc/i686-apple-darwin9/4.0.1/collect2
        • /usr/libexec/gcc/i686-apple-darwin9/4.0.1/ld

LLVMが透過的だとしたら、接頭辞を加えてコマンドを実行すれば全てがうまくいくだろう(もちろん、そう、-emit-llvmを忘れなければ)。そしてbitcodeが生成されるだろう。

llvm-gcc -emit-llvm -Wall -O2 -g -c foo.c
llvm-gcc -emit-llvm -Wall -O2 -g -c bar.c
llvm-ar rc libfoobar.a foo.o bar.o
llvm-ranlib libfoobar.a
llvm-gcc -emit-llvm -Wall baz.c -L. -lfoobar -lm -o baz

はかない望みである。はかなさの理由は、コンパイルとリンクを合わせて行うことがllvmの流儀に反しているからだと説明できるかもしれない。llvm-gccとllvm-ld(またはllvm-link)を別々に実行すれば問題は解決する。bitcodeとそれを実行するためのシェルスクリプトが生成される。

llvm-gcc -Wall -emit-llvm -c baz.c
llvm-ld baz.o -L. -lfoobar -lm -o baz

流儀云々は窓から投げ捨てよう。collect2は$PATHからldを決定する(実際には、もっと面倒な決定方法を経る)。特に設定していなければシステムのldを見つける。システムのldが望みを叶えてくれるわけはない。

  • $LLVM_GCC_PREFIX/bin/llvm-gcc
    • $LLVM_GCC_PREFIX/libexec/gcc/i686-apple-darwin9/4.2.1/cc1
    • $LLVM_GCC_PREFIX/libexec/gcc/i686-apple-darwin9/4.2.1/collect2
      • /usr/bin/ld

ldをllvm-ldへのシンボリックリンクに設定すれば、llvm-ldが呼び出されるようになる。しかし、collect2がldに渡す引数のなかにはllvm-ldが解釈できないものがある。典型的には-emit-llvmを扱えないし、Mac OS Xの拡張オプションや癖のあるlibc周りはうまく扱えない(なんだか間尺に合わない話だ)。厳密さを追い求めなければ、対処は難しくない。扱えない引数を削除した後、llvm-ldを呼び出せばいい。

0 件のコメント: