この広告は、90日以上更新していないブログに表示しています。
clangというのはllvm向けのC/C++/Obj-Cのためのフロントエンドで、最近はGoogle ChromeとかFirefoxもコンパイルできるレベルにまで成熟してきているらしい。
いくつかのブログで紹介されているのを見ても、ふーん、ぐらいにしか思っていなかったのだが、あんな大規模なソフトウェアがコンパイルできるというのは、考えてみるとすごいことである。大事なことなので強調しておくが、すごいことである。十分に実用的なレベルに到達していることだ。ビルドも早いし生成されたコードもg++と同程度には速いというし、試してみる必要がある。
という訳で、いくつか実際にソフトウェアをビルドしてみた。試してみた限りでは、
といった問題があったが、割とどれもすんなりとコンパイルが通った。ビルドが通らなかったり、通ってもちゃんと動かなかったりする場合もあるが、私が遭遇した範囲ではどれもコード側の問題で、clangの問題ではなかった。
ChromeやFirefoxがビルドできるのだから当たり前とも言えるが、自分が書いたプログラムがいつもと違うコンパイラでビルドできると、驚いてしまう。clangはAppleがスポンサーについて開発が進んでいるプロジェクトなわけで、然るべき金額をどこかの会社が払って然るべき人間が開発を進めれば実用的なC++コンパイラは作れるのだ、という話でしかないのかもしれないが、それでも驚きである。
clangはVisualC++やg++と比べてC++の規格への準拠度が高く、大きなソフトウェアになればなるほど、規格上は許されないコードが微妙に混入してしまっており、コンパイルできない場合が多い。以下では、clangを使ったときにハマるであろう典型的な例(というか、私が遭遇した例)をいくつか紹介したい。
clangはg++とコマンドラインオプションの互換性があるので、gcc,g++を呼び出しているところをclang, clang++を呼び出すように変えれば良い。
だいたいのビルドシステムの場合、export CC=clang ; export CXX=clang++とした上でconfigureからやり直すとビルドできるようになるはずである。
これはエラーメッセージを見ただけで修正ができる問題であるが、C++の規格上このような制限があるということ自体、知らない人も多いのではないか。私はもちろん知らなかった。
default initialization of an object of const type 'const foo' requires a user-provided default constructor
規格の文言では、"if the object is of const-qualified type, the underlying class type shall have a user-declared default constructor." と書いてあるみたいだ。
これはclangのエラーメッセージが親切であるということをありがたく感じると同時に、C++の規格を理解することは(素人には)難しい、と思わされるエラーである。エラー自体は、以下のように非常にシンプルなのだが、その下の方に"note:"としてわざわざ注意書きをつけてくれる。
error: use of undeclared identifier 'foo'
これに対して以下のようなnoteがつく。
note: must qualify identifier to find this declaration in dependent base class
エラーメッセージだけでは途方にくれるが、このnoteのおかげでなにをやらないといけないかが分かりやすい。要するに、foo()と書いてあるところをthis->foo()にすればいい。もしくは呼びたいメソッドが定義されている親クラスの名前を明示してもよいが、親クラスが変わった際(ということはさすがに考えにくいが…)に変更しなくて済むので、thisを使った方が良いように思う。
これは、C++でシンボルからその定義を探す際に、two phase name lookupという名前の解決方法が規格として定められているのが原因であるそうだ。これは以下のような仕組みである。
私が見つけられたわかりやすい情報源は、結局Standard Features Missing From VC++ 7.1. Part III: Two-Phase Name Lookup だけであった。他のページではそもそもdependent nameが具体的にどのようなものなのかを書いているところがなかった。もっとも、分かりやすく説明しているページはきっと他にもあるだろうし、そもそも規格にはdependent nameの定義は絶対に書いてあるはずである。
関わった中で出てきたエラーとして、
error: use of undeclared identifier 'make_pair'
というのがあった。g++だとこのままで通るのだが、clangだとstd::make_pairとしなければならない。undeclared identifierと言われたら、stdをつけないといけないか、もしくは一つ前の問題を疑うべきである。
プロトタイプ宣言と関数の宣言の二回でデフォルト引数を定義していると以下のようなコンパイルエラーになる。これもエラーメッセージからすぐにわかる。以下のようなエラーになった。
error: redefinition of default argument
g++だと顕在化しなかったバグがclangによって実際に問題になったケースがあった。参照してはいけないオブジェクトを参照しちゃっていて、clangだと落ちるとか。ここら辺はたぶんケースバイケースで、最適化レベルによっても変わったりするだろうし、g++でバグが顕在化する場合もあるだろうから、複数のコンパイラで試すことが望ましいのだと思う。ちょっとの手間で試せるなら、複数のコンパイラでビルドしてユニットテストが通るかぐらいまでは確認しておくと、ソフトウェアの信頼性を上げられるのではないかと感じた。
その他、現在のところ、wstringをリテラルで書くのが面倒であるという問題があった。gccだとUTF-8でL"あいうえお"とか書けるのだが、clangでは今のところそのような書き方はできない。
clangは実際にいろいろなソフトウェアをビルドできるし、ビルドできない場合にもclangではなくソフトウェア側の問題がほとんどであった。完成度はかなり高い。
ビルド時間への影響の面では、自分が試した範囲だと、clangとg++では、clangの方がコンパイル速度は早いのだが、1〜2割ぐらいの差しかないようだ。どうも、デバッグビルドだとあんまり差がつかないみたい。もちろん、2割早くなれば嬉しいのは嬉しいのだが、乗り換えるための決定打になるほど速くはなかった。それよりは、エラーメッセージがg++より親切であるとか、規格への準拠度が高いので書いているコードのポータビリティを上げられる、といった点の方が嬉しさは大きい。
引用をストックしました
引用するにはまずログインしてください
引用をストックできませんでした。再度お試しください
限定公開記事のため引用できません。