C/C++ 関係のツールを自作する際,cpp が頭痛の種になるケースはけっこう多いと思います.
http://d.hatena.ne.jp/shinichiro_h/20070521#1179728233
koguro koguro 『> 実行時に GCC 呼んだり Scheme でパースしたりするのはこうなんかイクないと思ったとか思わなかったとか ひー、すみません、すみません、2度とこんなことやりません!! (>_<) (って、直すつもりはないですけど)。まあ、個人的にはlibcppもなんかお近づきになりたくないライブラリという感じなので、mcpp (http://sourceforge.net/projects/mcpp/)を使うのがきれいかなと思ったりしています(さすがにプリプロセッサは作れないので)。』
koguro koguro 『”/usr/lib/gcc/.../include”のディレクトリは、gcc -print-search-dirs の結果を使えば得られるかと思います。あと、最近Ubuntuの新しいのを入れて気付いたのですが int16_t みたいな型は__attribute__を使って定義されているので、__atribute__は無視しないでがんばって解釈した方がよいかも(でも、c -wrapperでは手抜きしてあらかじめ int*_t 系の型は定義してしまうようにしてしまいました)。』
shinichiro_h shinichiro_h 『 libcpp なんか近付きたくない、は同意するところです。 mcpp はそういえば昔えらい標準準拠率高いんだと雑誌に書いてあるのを見た覚えがあります。プリプロセッサは頑張ればできないこともなさそうなやっぱり難しそうな、と微妙なところですね。 TCC 見るとできそうな気がしてくるのですがいざはじめると手が止まります。
-print-search-dirs の方はありがとうございます。あと、 __attribute__ の方はいざとなれば GCC 関係のマクロをオフにすると標準ヘッダに関しては拡張使わなくなるのかな、という理解だったのですが、なんか最近はそうでもないんですかね。ちょっと手元に環境無いのでしばらく確認が難しげです。』
Boost C++ labyrinth プログラミング 第2版を読んでいたら,wave なんていうライブラリがあることを知りました.
# しっかし,この本,面白そうなライブラリに限って 2 〜 3 ページしか解説が無かったりするんだよな… boost/python とか.signals とかも素敵過ぎる気がするんだけど.むう,この本を書いたのは誰だ ! 女将を呼べ ! (嘘です k.inaba さんごめんなさい)
これを使うと,C/C++ の文字列をプリプロセス (前処理) できるそうです.GCC とかの独自拡張にも対応しているらしい.とりあえず,インストール
# apt-get install libboost-wave-dev パッケージリストを読み込んでいます... 完了 依存関係ツリーを作成しています... 完了 以下の特別パッケージがインストールされます: libboost-filesystem-dev 以下のパッケージが新たにインストールされます: libboost-filesystem-dev libboost-wave-dev
k.inaba さんとこのサンプルコードを,うちの環境に合わせたもの.とりあえず C のヘッダだけ include できるように.
#include <iostream> #include <fstream> #include <string> #include <boost/wave.hpp> #include <boost/wave/cpplexer/cpp_lex_token.hpp> #include <boost/wave/cpplexer/cpp_lex_iterator.hpp> using namespace std; using namespace boost::wave;
int main(int argc, const char* argv[]) { try { // ファイル argv[1] の内容を全部 text に読み込む ifstream fin(argv[1]); string text(istreambuf_iterator<char>(fin.rdbuf()), istreambuf_iterator<char>());
// プリプロセッサを用意 typedef context< string::iterator, cpplexer::lex_iterator< cpplexer::lex_token<> > > context_t; context_t ctx(text.begin(), text.end(), argv[1]);
// オプションやマクロを設定 ctx.set_language(language_support(support_cpp | support_c99)); ctx.add_sysinclude_path("/usr/include"); ctx.add_sysinclude_path("/usr/lib/gcc/i486-linux-gnu/4.1.2/include"); // イテレータを取得して context_t::iterator_type it = ctx.begin(); context_t::iterator_type end = ctx.end();
// トークンを順番に表示 for(; it!=end; ++it) cout << it->get_position() << " :: " << it->get_value() << endl; }
catch(cpp_exception& e) { cerr << e.file_name() << "(" << e.line_no() << "):" << e.description() << endl; } }
コンパイル & 実行 (stdio.h をプリプロセス)
$ g++ wave.cpp -o wave -lboost_wave -lboost_filesystem $ ./wave /usr/include/stdio.h /usr/include/sys/cdefs.h(29) :: #line /usr/include/sys/cdefs.h(29) :: /usr/include/sys/cdefs.h(29) :: 30 /usr/include/sys/cdefs.h(29) :: /usr/include/sys/cdefs.h(29) :: "/usr/include/stdio.h" /usr/include/sys/cdefs.h(29) ::
/usr/include/sys/cdefs.h(89) :: extern /usr/include/sys/cdefs.h(89) :: /usr/include/sys/cdefs.h(89) :: "C" /usr/include/sys/cdefs.h(89) :: /usr/include/sys/cdefs.h(89) :: { /usr/include/stdio.h(30) ::
/usr/lib/gcc/i486-linux-gnu/4.1.2/include/stddef.h(213) :: #line /usr/lib/gcc/i486-linux-gnu/4.1.2/include/stddef.h(213) :: /usr/lib/gcc/i486-linux-gnu/4.1.2/include/stddef.h(213) :: 214 /usr/lib/gcc/i486-linux-gnu/4.1.2/include/stddef.h(213) :: /usr/lib/gcc/i486-linux-gnu/4.1.2/include/stddef.h(213) :: "/usr/lib/gcc/i486-linux-gnu/4.1.2/include/stddef.h" /usr/lib/gcc/i486-linux-gnu/4.1.2/include/stddef.h(213) ::
/usr/lib/gcc/i486-linux-gnu/4.1.2/include/stddef.h(214) :: typedef /usr/lib/gcc/i486-linux-gnu/4.1.2/include/stddef.h(214) :: /usr/lib/gcc/i486-linux-gnu/4.1.2/include/stddef.h(211) :: long /usr/lib/gcc/i486-linux-gnu/4.1.2/include/stddef.h(211) :: /usr/lib/gcc/i486-linux-gnu/4.1.2/include/stddef.h(211) :: unsigned /usr/lib/gcc/i486-linux-gnu/4.1.2/include/stddef.h(211) :: /usr/lib/gcc/i486-linux-gnu/4.1.2/include/stddef.h(211) :: int /usr/lib/gcc/i486-linux-gnu/4.1.2/include/stddef.h(214) :: /usr/lib/gcc/i486-linux-gnu/4.1.2/include/stddef.h(214) :: size_t /usr/lib/gcc/i486-linux-gnu/4.1.2/include/stddef.h(214) :: ; /usr/lib/gcc/i486-linux-gnu/4.1.2/include/stddef.h(214) ::
/usr/include/bits/types.h(33) :: #line /usr/include/bits/types.h(33) :: /usr/include/bits/types.h(33) :: 34 /usr/include/bits/types.h(33) :: /usr/include/bits/types.h(33) :: "/usr/include/bits/types.h" /usr/include/bits/types.h(33) ::
...
せっかく boost/spirit でフルスクラッチされているのに,なんでテンプレートライブラリじゃないんだよー と最初は思ったのですが,上のサンプルコードを一回コンパイルしてみればすぐわかります.ライブラリ化されているにもかかわらず,かなりコンパイル時間が長い…
う〜ん,boost は,ドキュメント読んでる間は面白いんだけどねぇ.実際に使おうとすると,このコンパイル時間の長さは致命的なような.まぁ,速い PC 買えって話なんでしょうが.
|