[TOPPERS] cfg1_out.c はなぜ必要か?
ここのところTOPPERS新世代向けコンフィギュレータの話題が続いていますが、今回もそのひとつです。ASPカーネルでは、コンフィギュレータはパス1からパス3の三段階に分けて実行されます。その最初の段階であるパス1で、cfg は cfg1_out.c という中間ファイルを生成します。中間ファイルといっても、名前からも分かるようにCのソースファイルです。今回は、この cfg1_out.c が何なのか、なぜ必要かについて説明してみます。
JSPカーネルのコンフィギュレータは、cfg と chk という二段階で構成されていました。cfg は .cfg ファイルを読み込み、kernel_id.h と kernel_cfg.c を生成します。chk はチェッカーと呼ばれるもので、全体のリンクが完了したあと、kernel_cfg.c 内の各初期化ブロックの要素が正しい値であるかどうかを、おおまかにチェックするものです。
リンク後に chk でパラメータチェックを行う方法ではいくつか問題が生じます。具体的には、静的APIに記述したパラメータの情報の一部が失われてしまうことや、make 過程の早い段階でエラーを検出できないといったことです。ASPカーネルをはじめとした新世代カーネル向けのコンフィギュレータでは、そうしたJSPカーネルのコンフィギュレータの限界を突破するための工夫を盛り込んでいます。
.cfg ファイルに記述した静的APIのパラメータチェックは大きな課題だったわけですが、コンフィギュレータでは各パラメータの字面しか知ることができません。個々の識別子の型やその他の素性(マクロなのかなど)はまったくわかりません。また、各型のサイズや内部表現など、Cコンパイラに依存する内容もやはりわからないのです。これを解決するには、実際に一度Cコンパイラを通してみるしかありません。
そこで登場したのが、cfg1_out.c です。当初の設計では、すべてのパラメータは32ビット整数型に格納できると仮定(64ビット処理系など、この仮定が通用しない場合があることはわかっていましたが...)した上で、各パラメータを詰め込んだ配列を定義していました。cfg1_out.c をコンパイルすれば(リンクまでは必要ありません)、配列の先頭からのオフセットを用いて、各パラメータの値を取り出すことができたのです。
しかし、こうした方法はすぐに限界になります。64ビット以上のプラットフォームに対応できないこともありますが、ユーザー定義の値を cfg1_out.c に潜り込ませることが困難だからです。たとえば、特定のプロセッサ向けの割り込み番号を表すマクロを cfg1_out.c に埋め込み、その値をコンフィギュレータに知らせたい場合は少なくありませんが、それが困難だったのです。
そこで、ひとつの配列に全部詰め込むことはやめ、型情報を持った個別のオブジェクトを定義する方法に設計を改めました。これにより、かなり細かな対応が可能になりましたが、リンクまで解決しなければ各オブジェクトのアドレスが定まらないため、値を取り出すことができなくなったのです。
また、cfg1_out.c をコンパイル〜リンクした上で、Sレコードと(nm が出力する形式の)シンボルテーブルが必要になります。開発ツールによっては、Sレコードやシンボルテーブルを直接生成できませんので、外部ツールを自作するなどしてこれらのファイルを生成しなければなりません。一部の統合開発環境などでは、これらに対応するために非常に面倒なポーティング作業が発生してしまいます。
特定の処理系だけを相手にするのであれば、ここまで煩雑なことをする必要はありません。おそらく、これらの処理はコンフィギュレータの内部に完全に閉じることができたでしょうし、ポーティング担当者に負担をかけることもなかったでしょう。もっとも、こうした複雑化の原因となった要望のいくつかは、(責任転嫁するわけではありませんが)ポーティング担当者から出されたものですので致し方ありません。
