テストステ論

高テス協会会長が, テストステロンに関する情報をお届けします.

(macro-of-inline report) pycparserを騙すための一時的なincludeを行うオプションの検討

一応, Issueを書いておいたんだけど, 英語がいい加減なのと, そもそも英語で説明する能力がないので無理と匙を投げた感じなので, 日本語でもまとめておく.

Additional fake include · Issue #30 · akiradeveloper/macro-of-inline · GitHub

rubyテストを通すことがほぼ絶望的となって困ってるわけだが, その原因は, pycparserが型を見つけられないことにある. 例えば__buitin_va_listだとか__int128などというものが見つからない.

rubyテストでは, mcppを使ったトリックを使わずに,

  1. gcc -Eでプリプロセスする. この時点でコンパイル可能
  2. AST->AST
  3. 吐き出す

というコードを書いてるんだけど, 2でこける. 理由は, 型が見つからないから.

なぜ2でこけるかというと, gcc embeddedな型がないから. ヘッダに書いてあるものはすでにgcc -Eで取り込まれているが, 組込なものは存在しない.

ところで, mcppを使ったトリックというのは何かというと,

  1. 偽のインクルードをする. (マクロは存在しない. 型のみを追加して, コード書換えはさせない. この点に関しては, https://github.com/eliben/pycparser/issues/50で議論している)
  2. AST->AST
  3. 変換したあとに, 偽インクルード成分を取り除き, includeディレクティブのみを復活させる.

という1,3サンドイッチであり, この実装はcppwrap.pyにある. この方法は, 3が正しく動作する場合が条件つきだ. rubyのコードはトリッキーなため, うまくいかない場合がある. このトリックは何に役立つかというと, クロスビルドに役立つ. Linux上でマクロ化を行ったコードを, 他のマシンに持っていくことが出来る.

このため, rubyテストでは, gccプリプロセスをして, 動作させるコードを生成し, その上で直接AST変形を行うことにしている.

しかし, pycparserがパース出来ないというわけである. 超辛い.

そこで, 2段階目のfake注入を設ける. すなわち, rubyテストの場合であれば,

  1. gcc -E
  2. gcc -E -include
  3. AST->AST
  4. 2の成分を除去
  5. 1の成分を除去

のうち, 2,4サンドイッチを新しく挿入する. こうすることで, pycparserを騙すためだけの一時的な型情報を注入することが出来る. そして以上の設計は, もともとあったコードに影響を与えることがないし, AST->AST変形の直前直後にあるから, どのオプションでやっても効果を発揮させることが出来る. いわば, もっともぴゅあぴゅあなAST->AST変形に, その変形と同等にぴゅあぴゅあな皮を一枚被せることになる.

なぜrubyテストにここまでこだわるかというと, 今まで書いたスクリプトが惜しいということではなく, マクロオブインラインはその正しさを証明することが出来ないので, よく知られたソフトウェアに対する実証でしか正しさを訴求出来ないからだ. rubyのようなでかくてトリッキーなソフトウェアの70%近くをマクロ化して正しく動作しているならば, これは相当な確証となる. すなわち, rubyテストがあるかないかでは, マクロオブインラインの価値が天地となる. rubyテストが通るならば, マクロオブインラインはプロダクションのビルドチェーンに入れられるレベルになると, 私は思う. しかし, tinyなコードに対して動きました程度では, それにはほど遠い. つまり, このテストには相当な労力をかける価値がある. inlineはANSIには存在しない. 従って, もしこのソフトウェアが完全に動作するならば, 世界に対して訴えていく価値のあるものになる.