npt amalgamationを作り直す
開発のメモです。
npt amalgamationとは、sqliteのamalgamationの考え方をまねて作ったものであり、
nptのソースを1つのファイルに結合するというものです。
現時点でnptのソースは770個くらいですが、amalgamationを使えば
lisp.c
lisp.h
shell.c
の3つになるというもの。
これはこれで良かったのですが、実際に開発に使ってみると、
ソースファイルが大きすぎてデバッグ時にまともに動かなくなりました。
gdb
でソースを参照するときにものすごく時間がかかります。
こんな感じ。
$ cc -g -DLISP_FREEBSD -DLISP_DEBUG lisp.c shell.c -lm $ gdb a.out (gdb) b lispd_invoke_handler_control_ Breakpoint 1 at 0x3b0b70: file lisp.c, line 120648. (gdb) r Starting program: npt/develop/amalgamation/a.out (error "Hello") ★★★ここから Breakpoint 1, lispd_invoke_handler_control_ (ptr=0x800a83140, instance=0x80127efd0 "\003\003") at lisp.c:120648 120648 next = ptr->control; ★★★ここまで15秒
うちのパソコンが遅いだけだとか、 nptのデバッグなんて全世界探しても製作者一人しかやらねえよとか、 そう言う正論もあると思いますが、これを何とかしたかった。
解決方法としてはソースファイルを複数に分割することです。
ということで、amalgamation.lisp
を作りなおしました。
使い方を説明します。
singleモード
今まで通り単一のファイルを作成したい場合は次のようにします。
$ cd develop/amalgamation/ $ sbcl --script amalgamation-single.lisp Name: npt Output: lisp.c Output: lisp.h Output: shell.c
せっかくなんでnptでやろうよという場合は次のようになりますが、 非常に遅いので自分はsbclでやっています。
$ npt --script amalgamation-single.lisp
ファイルサイズを確認します。
$ wc lisp.c 292601 764366 7459280 lisp.c
29万行というとても大きなソースファイルができています。
multpleモード
複数のファイルを生成したい場合は次の通り。
$ cd develop/amalgamation/ $ sbcl --script amalgamation-multiple.lisp Name: npt Output: lisp_file_01.c Output: lisp_file_02.c Output: lisp_file_03.c Output: lisp_file_04.c Output: lisp_file_05.c Output: lisp_file_06.c Output: lisp_file_07.c Output: lisp_file_08.c Output: lisp_file_09.c Output: lisp.h Output: shell.c
見てわかる通り、lisp.c
の代わりに、lisp_file_01~09.c
というファイルが生成されました。
コンパイルは次の通りとなります。
$ cc -g -DLISP_FREEBSD -DLISP_DEBUG lisp_file*.c shell.c -lm
gdbの時間を確かめてみます。
$ gdb a.out (gdb) b lispd_invoke_handler_control_ Breakpoint 1 at 0x3bf4c0: file lisp_file_03.c, line 48019. (gdb) r Starting program: npt/develop/amalgamation/a.out (error "Hello") ★★★ここから Breakpoint 1, lispd_invoke_handler_control_ (ptr=0x800a83140, instance=0x80127efd0 "\003\003") at lisp_file_03.c:48019 48019 next = ptr->control; ★★★ここまで3秒
まあまあですね。
実はひどい欠点があり、ファイルサイズが恐ろしく膨れ上がっています。
$ wc lisp_file_*.c 51060 138673 1419576 lisp_file_01.c 52655 137592 1512174 lisp_file_02.c 51280 126202 1460601 lisp_file_03.c 51516 137111 1485953 lisp_file_04.c 52211 164221 1680275 lisp_file_05.c 51081 132727 1494255 lisp_file_06.c 51924 135576 1473222 lisp_file_07.c 52005 132025 1471599 lisp_file_08.c 23583 61900 717012 lisp_file_09.c 437315 1166027 12714667 total
29万行→43万行になっています。
個別のファイルは5万行くらいで収まっているのですが、
元々のソースよりはるかに多くなっています。
なぜこんなことが起きているかというと、
コンパイル用のヘッダーファイルを出力しないようにしているため、
必要な情報を全て*.c
ファイルに埋め込んでいるからです。
lisp.h
はコンパイル用のヘッダーファイルではなく、
ユーザーが開発に使うためのものなのです。
これはちょっと許容できないなということで、 開発用のヘッダーファイルを生成するモードも作成しました。
headerモード
本モードは開発用のヘッダーファイルも出力します。
$ cd develop/amalgamation/ $ sbcl --script amalgamation-header.lisp Name: npt Output: lisp_file.h Output: lisp_file_01.c Output: lisp_file_02.c Output: lisp_file_03.c Output: lisp_file_04.c Output: lisp_file_05.c Output: lisp_file_06.c Output: lisp_file_07.c Output: lisp_file_08.c Output: lisp_file_09.c Output: lisp.h Output: shell.c
multipleとは違い、lisp_file.h
というファイルが作成されています。
それぞれの行数を見てみましょう。
$ wc lisp_file* 30602 81184 679396 lisp_file_01.c 30355 74714 715103 lisp_file_02.c 30542 69511 721342 lisp_file_03.c 30446 74189 681212 lisp_file_04.c 30192 106862 950764 lisp_file_05.c 30656 73963 726365 lisp_file_06.c 30993 75485 710006 lisp_file_07.c 30287 72128 709222 lisp_file_08.c 19986 51134 474525 lisp_file_09.c 28907 85953 1098544 lisp_file.h 292966 765123 7466479 total
個別のファイルはおよそ3万行で収まっており、
全ファイルの合計はlisp.c
とほぼ同じになっています。
ソースファイルは3万行で区切っているのですが、
lisp_file.h
は分割せず全部結合して出力しています。
lisp_file.h
も3万行に近いのはただの偶然です。
コンパイルの方法はmultipleと同じです。
$ cc -g -DLISP_FREEBSD -DLISP_DEBUG lisp_file*.c shell.c -lm
ではgdbはどうなっているのか?
gdbの時間確認は次の通り。
・・・ (error "Hello") ★★★ここから Breakpoint 1, lispd_invoke_handler_control_ (ptr=0x800a84140, instance=0x80127ed10 "\003\003") at lisp_file_04.c:400 400 next = ptr->control; ★★★ここまで1秒
いいですね。
個人的にはheaderモードを使って行こうと思います。
multipleモードなんて作る必要なかったかもしれない。
まとめ
headerモードを使おう。
やり方は次の通り。
$ cd develop/amalgamation/ $ sbcl --script amalgamation-header.lisp $ cc -g -DLISP_FREEBSD -DLISP_DEBUG lisp_file*.c shell.c -lm $ ./a.out