続 bcc32とmwccもやってみる
なんだかんだ言いつつもここまで動くようになりました。
http://hamigaki.sourceforge.jp/status/
Broken Compilerをサポートすること自体はあまり乗り気ではないのですが、Compiler StatusのFailを潰していくのが面白かったのと、その過程で別のバグが見つかったりで、それなりに意義はありました。
バグの原因ではなく、他人のデバッグの過程を聞く機会ってあまりない気がするのでまとめてみました。
というわけで、以下は読み物としてお楽しみください。
CRTPでICE
まずは、pcm_device.cppのICEから取り組みました。これが直らないとライブラリが完成しないため、Hamigaki.Audioのすべてのテストが失敗してしまいます。
ICEになるのは次のコード片の3行目です。
class pcm_sink::impl : public hamigaki::iostreams:: arbitrary_positional_facade<pcm_sink::impl, char, 4> , private boost::noncopyable {
ここで怪しいのはCRTPを使っていることです。CRTPが動かないのかとも思ったのですが、bcbboostのCompiler Statusを見ると、CRTPの代表格であるiterator_facadeのテストをpassしています。
それでもCRTP以外に怪しそうな箇所もないので、単純なCRTPのコードを書いてみます。
template<class T> class facade {}; class hoge {}; int main() { facade<hoge> f; }
予想通り、これは通ります。CRTPに「pcm_sink::impl」と「::」付きの名前を渡しているのがマズいんじゃないかと思って、次のように変えてみます。
(経験的に「::」周辺でのパースバグは多いのです。)
class hoge { class impl; }; class hoge::impl : public facade<hoge::impl> {};
ビンゴでした。いろいろ試した結果、
class hoge::impl : public facade<impl> {};
で動きました。
名前空間の終了位置でICE
direct_sound.cppとasio.cppのICEは、
} } // End namespaces audio, hamigaki.
という箇所で起きています。
また妙なところでICEになるものです。
名前空間の終了位置ということは名前空間絡みだろうと思い、名前空間の部分だけ抜き出してコンパイルしてみましたが、問題ありません。
これ以外に名前空間に関係ありそうなのは、using宣言/指令です。
探してみると、どちらのファイルにもありました。
namespace hamigaki { namespace audio { namespace { using namespace hamigaki::detail::windows;
自分の記憶では、bccでは無名名前空間とusingの組み合わせは相性が良くなかった覚えがあったので、using指令を名前空間の外に移動してみたところ、無事コンパイルできました。
asio_sink_testでアクセス違反
ようやくコンパイルが通ったと思ったら、今度はasio_sink_testでmemory access violationが発生しました。
デバッガで追わないと分からないかなぁと思って、IDEを起動、プロジェクトの設定などを行っていたところ、ASIOドライバの呼び出し規約が__thiscallだったことを思い出しました。
呼び出し規約のスタブ関数はインラインアセンブラで書いたGCC用の実装しかありません。
これのBorland版を用意する必要があります。
bccだとProfessional版以上(BDS2006はPro以上しかないけど)でないとインラインアセンブラを使用できないので、
http://www.boost.org/boost/numeric/interval/detail/bcc_rounding_control.hpp
を参考に、__emit__()を使って機械語を直接埋め込むことにしました。
inline ::ASIOError asio_start(::IASIO*) { __emit__(0x8B); __emit__(0x45); __emit__(0x08); __emit__(0x8B); __emit__(0x10); __emit__(0x8B); __emit__(0x4D); __emit__(0x08); __emit__(0x8B); __emit__(0x42); __emit__(0x1C); __emit__(0xFF); __emit__(0xD0); return _EAX; }
こんなのを延々と書いて、ようやくpassしました。