htod
D は C のコードとのバイナリ互換性はありますが、 CのコードをコンパイルしたりCのヘッダを読み込むことはできません。 DとCのコードをリンクするためには、ヘッダにあるCの宣言を、 Dのモジュールへと変換する必要があります。 htod は、 Cのヘッダからの変換をサポートする手助けとなるツールです。
htod は Digital Mars C/C++ コンパイラのフロントエンドを元に作成されています。 出力がオブジェクトコードではなくDのモジュールであることを除けば、 あたかもC/C++コンパイラであるかのように動作します。
マクロ __HTOD__ があらかじめ 1 に定義されています。 このマクロを使うことで、D へ変換しやすい C のヘッダを書くのが簡単になります。
ダウンロード
使い方
htod cheader.h [dimport.d] [-cpp] [-hc] [-hi] [-hs] [-ht] { C compiler switches }
それぞれのオプションの意味は以下の通りです。
- cheader.h
- C/C++ のヘッダファイル (入力)
- dimport.d
- D のソースコードファイル (出力) (デフォルトは cheader.d)
- -cpp
- ヘッダが C++ で書かれていることを示す
- -hc
- デフォルトでは、htod はC/C++での宣言をそのまま //C でコメントアウトした形でファイルに付け加えます。 -hc はこの動作を抑制します。 htod が正しい結果を出力していることに確信が持てるときだけ このオプションを使ってください。 (例えば __HTOD__ を使ったヘッダを変換しているときなど)
- -hi
- デフォルトでは、htod は#include "file" を 対応する import 文に置き換えます。 -hi を指定すると、 #include先の宣言も含めて全てをDの宣言に変換して出力するようになります。 #include先の内容の解析はこのオプション指定にかかわらず行われます。 -hi は、#include階層全体を ひとつのDのインポートモジュールに変換したいときに役に立ちます。 #include <file> のようなシステム#includeについては、 -hi は影響しません。 -hs も参照のこと。
- -ht
- デフォルトでは、htod はtypedefされた型名はそのまま使うようにして 変換します。 -ht を指定すると、対応する元の型に置き換えて出力が 行われます。これは、マクロやtypedef、#includeの層を掘り下げて 元々の型を探り当てるときに役立ちます。
- -hs
- -hi と似ていますが、こちらは更にシステム#includeについても 同様に変換出力を行います。
- Cコンパイラ スイッチ
- C/C++ コンパイラに対するスイッチ指定(-D や -I など)は dmc のドキュメントを参照してください。
例
C の test.h ファイルを
unsigned u; #define MYINT int void bar(int x, long y, long long z);
次のコマンドで変換すると
htod test.h
test.d というファイルが生成されます。
/* Converted to D from test.h by htod */ module test; //C unsigned u; extern (C): uint u; //C #define MYINT int //C void bar(int x, long y, long long z); alias int MYINT; void bar(int x, int y, long z);
Cでの対応する宣言が "//C " コメントで残されています。
型の対応関係
C の型は以下の表の通り変換されます。これらの対応は Digital Mars C/C++ に関しては正確ですが、他のCコンパイラにとっては不適切かもしれません。 Dの基本型のサイズは規格で固定されていますが、 Cの型のサイズは処理系依存となっているのが原因です。
Cの型 | Dの型 |
---|---|
void | void |
_Bool | bool |
wchar_t | wchar |
char | char |
signed char | byte |
unsigned char | ubyte |
short | short |
unsigned short | ushort |
int | int |
unsigned | uint |
long | int |
unsigned long | uint |
long long | long |
unsigned long long | ulong |
float | float |
double | double |
long double | real |
_Imaginary float | ifloat |
_Imaginary double | idouble |
_Imaginary long double | ireal |
_Complex float | cfloat |
_Complex double | cdouble |
_Complex long double | creal |
制限事項
Cの宣言とDの宣言の間には、厳密な1対1対応は存在しません。 必ず、出力されたDモジュールの内容を見て、 正しく解釈されているか確認してから使うようにしてください。 他にもいくつか制限があります。
- 実用的な観点から言えば、 C のヘッダはマクロではなく typedef と enum を使って記述されているべきです。 htod は単純な #define マクロについては、alias や const 宣言への変換を試みます。 とはいえ、ヘッダ内でのマクロ使用については解析前に全て展開されます。
- C の条件コンパイルを D の version や static if 宣言へと変換することは一切ありません。
- 条件コンパイル条件が偽となっている部分については、 なにも出力されません。
- htod は宣言のみを変換します。 Cのコードは変換しません。
- C++リンケージを持つ宣言は変換できません。 C++コードについては、まずCインターフェイスの作成が必要です。
- C のヘッダファイル中で使われた言語拡張については、 認識されない可能性があります。
- pragma は変換されません。
- タグ名は通常の名前空間と衝突しないことが 仮定されています。
- ASCII外の文字データは、 必要ならばUTFに変換しておく必要があります。
- C の char は D の char 型に対応すると仮定されています。しかしながら、 これについては個別にチェックして、byte や ubyte 型の方が適切ではないかチェックした方がよいでしょう。C の char 型がsignedかunsignedかは実装依存ですが、D の char 型はunsignedです。
- C の名前付き列挙体のメンバーは、Cでそうであるのと同様に、 周囲のスコープへと挿入されます。
- D のモジュールはそれぞれ個別の名前空間を持ちますが、 Cのヘッダファイルは全て共通のグローバル名前空間に置かれます。これは、 他のDのモジュールで宣言された名前への参照については、 修飾が必要となることを意味しています。
バグ
- デフォルトの構造体アラインメント以外は 考慮されていません。
- Linux版はありません。