Creating bindings for C libraries/ja

From Free Pascal wiki
Jump to navigationJump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

English (en) español (es) français (fr) 日本語 (ja) русский (ru)

日本語版メニュー
メインページ - Lazarus Documentation日本語版 - 翻訳ノート - 日本語障害情報

Cライブラリとのバインディング

概略

このページでは Pascal から C ライブラリへのバインディングについて述べます。通常、Pascal からは C ライブラリを直接用いることができません。全ての C の関数、型、変数について Pascal への翻訳を作る必要があります。よくある C のあれこれを自動変換する H2Pas というツールがあります。自動変換には Lazarus 用の GUI もあり、H2Pas などのツールを用いています。このGUI ツールは、バインディングを修正するための規則集を作る作業を援助します。規則集を作ってしまえば、次からはずっと容易に C ライブラリからの変換ができるようになります。

作業の流れ

  • 変換しようとする C ヘッダを探し出します。
  • 作業ディレクトリを作成し、バインディングに名前をつけます。
  • h2pas ウィザードを用いて、新しい h2pas プロジェクトを作成します。
  • そのプロジェクトに .h ファイルを追加します。
  • h2pas のオプションを設定します。
  • ウィザードを走らせます。
  • text tools を追加してエラーを修正し、ウィザードを再度走らせます。
  • h2pas がエラーを出さずに走るようになったら、試しにコンパイルしてみます。きれいな出力が得られるように optional tools を追加します。
  • テストプログラムを書いて、バインディングをテストします。
  • できあがったバインディングは Lazarus-ccr や Free Pascal のウェブサイトで公開しましょう。

ツールのインストール

h2pas は FPC を普通にインストールするとついてきます。

h2paswizard パッケージを Lazarus IDE にインストールします。"Components -> Configure installed packages ..." に行き、右側の一覧から H2PasWizard パッケージを選んで 'Install selection' をクリックし、次いで 'Save and rebuild IDE' を選びます。

IDE を再起動すれば、メニュー項目に Tools -> h2pas が追加されています。

C ヘッダファイルの取得

C ヘッダファイル .h には C ライブラリのインタフェースが記述されています。通常の場合、それらはライブラリと同時には配布されません。ソースを得るか、ライブラリの開発用パッケージを入手するかする必要があります。たとえば、gtk ライブラリの C ヘッダファイルは gtk+-devel パッケージに入っています。

例: MPICH2

ファイル mpich2-1.0.3.tar.gz を http://www-unix.mcs.anl.gov/mpi/mpich2/ からダウンロードし、展開します。C ヘッダファイルは mpich2-1.0.3/src/include にあります。

作業ディレクトリの作成とバインディングの命名

使いやすい名前でディレクトリを作成します。名前には特殊文字を含んではなりません。特殊文字は空白・ウムラウト・フルストップ・コンマなどです。そこに .h ファイルを複製します。

例: MPICH2

Pascal ファイルには h2p ディレクトリを用意します。h2p/c_sources ディレクトリを .h ファイルに用います。

 mkdir -p h2p/c_sources
 cp mpich2-1.0.3/src/include/*.h h2p/c_sources/

(訳注: mkdir を -p オプション付きで呼んでいるので、h2p ディレクトリも同時に作成されます)

ウィザードによる新しいh2pasプロジェクトの作成

"Tools -> h2pas" として h2pas ウィザードを起動します。新しいウィンドウが開きます。このウィンドウと IDE ウィンドウの間は行ったり来たりすることができます。最後に用いた h2pas プロジェクトが自動的にロードされます。新しいプロジェクトを作成するには、"Settings -> New/Clear settings" をクリックし、一番下のボタン "Save settings" を押し、ファイル名を選んでください。

例: MPICH2

"Settings -> New/Clear settings" をクリック、次に最下部の "Save settings" をクリック、h2p/mpi2.h2p として保存します。

プロジェクトへの.hファイルの追加

"C header files" のページで .h ファイルを追加/削除できます。また、一部のファイルだけを変換できるよう、イネーブル/ディセーブル enable/disable もできます。

例: MPICH2

"C header files -> Add .h files ..." をクリック、"mpi.h" を選択。自動的にイネーブルされます。

h2pasオプションの設定

"h2pas Options" で h2pas のパラメタを設定することができます。

例: MPICH2

  • イネーブルするものは -e, -D, -p, -w これら以外は全てディセーブルします。
  • -l library path は "mpich"。
  • 出力拡張子は ".pas"。
  • 出力ディレクトリは h2pas/ (デフォルト)なので、空白のままとします。

ウィザードの実行

最下部のボタン "Run h2pas" を押します。これで、<example>.h ファイルが一時ファイル <example>.tmp.h にコピーされ、"Before h2pas" にリストされているツールが走行します。その後 h2pas が実行され、<example>.tmp.h が <example>.inc や <example>.pas あるいはなんであれ h2pas ページで設定した拡張子がつくファイルに変換されます。

h2pas が文法エラーを見つけると、IDE が example.tmp.h ファイルを開き、エラーを起こしている行に飛びます。エラー行が特定できない場合は単に 'syntax error' を表示するだけのこともあります。よくある問題とありうる解決については後述します。

例: MPICH2

h2pas ウィザードは既にこのヘッダの変換に必要な特殊ツールを全て含んでいます。よって、h2pas はエラーなしに走ります。ですが、この時作成されるユニットはまだそのままでは使えません。先をお読みください。

h2pasがエラーを吐く場合

よくあるC の構造で h2pas が認識しないものの一覧と、修正法を示します。

h2pas problem: extern "C"

ヘッダファイルによっては、C++の名前空間ブロックを持っていることがあります:

 #if defined(__cplusplus)
 extern "C" {
 #endif
 ...
 #if defined(__cplusplus)
 }
 #endif

対策: before h2pas ツールに Remove C++ 'extern "C"' lines を加えます。

h2pas problem: 空のマクロ

将来の拡張のため、空のマクロを含んだヘッダファイルがあります:

 #define MPI_FILE_DEFINED

対策: before h2pas ツールに Remove empty C macros を加えます。

h2pas problem: 暗黙の配列型

C は暗黙の配列 implicit array を引数として許しています。例えば:

 int MPI_Group_range_incl(MPI_Group, int, int [][3], MPI_Group *);

ここで int [][3] が暗黙の配列型であり、Pascal では許されません。h2pas はポインタ型を加えるようサポートしますので、全ての [] を * に変換すればよいのです。

対策: before h2pas ツールに Replace [] with * を加えます。

h2pas problem: ヌルポインタのマクロ

型付きのヌルポインタを含むヘッダファイルがあります:

 #define MPI_BOTTOM      (void *)0

対策: before h2pas ツールに Replace macro values 0 pointer like (char *)0 with NULL を加えます。

コンパイルの試行と出力の整形

エラーなしに h2pas の走行が終了すると、Pascal ファイルが生成されます。ユニットファイルかインクルードファイル (.inc) かは -i スイッチで決められます。次のステップは試しにコンパイルしてみることです。今できた Pascal ソースを利用するよう、テスト用のプロジェクトを設定します。次いで、ウィザードの 'Run h2pas and compile' ボタンを押してください。

例: MPICH2

Project -> New Project -> Program で新しいプロジェクトを作り、mpihelloworld として保存します。コードを次のように変えます。

program MPIHelloWorld;

{$mode objfpc}{$H+}
{$linklib mpich}
{$linklib rt}

uses
  {$IFDEF UNIX}pthreads{$ENDIF}, MPI;

begin
  MPI_Init(@argc, @argv);
  writeln('Hello, world.');
  MPI_Finalize;
end.

プロジェクトに h2p/mpi.pas を加えます。Project -> Add editor file to project を利用します。

h2pasの出力によくあるコンパイラエラー

h2pas が有効な Pascal コードを生成しないことがあります。よくある問題と修正法を挙げます。

ファイルパスを含んだユニット名

h2pas はユニット名に全パス名を含めてしまうことがあります。

対策: After h2pas ツールに Replace "unit filename;" with "unit name;" を加えます。

インクルードファイルが見当たらない

h2pas は #include 命令を Pascal の {$i } 命令に変換します。wach ヘッダファイルからユニットを生成する場合は、Remove includes ツールを用いて全ての include 命令を除去することができます。

先に宣言された型名が解決しない

例: mpi.pas(26,16) Error: Forward type not resolved "PMPI_Aint"

エラーを起こす行はしばしばレコード型へのポインタ型を含んでいます:

 PMPI_Aint = ^MPI_Aint;

h2pas は無名の C ポインタ( *MPI_Aint のような)に PMPI_Aint のように名前をつけます。これらのポインタはファイルの先頭に加えられますが、Pascal はこのような宣言が同一の type 宣言部にあることを要求します(*)。また h2pas は既に存在するポインタ型を更に加えてしまうこともあります。

(訳注: 一般に Pascal では識別子は利用する前に宣言しておかなければなりません。下の例で、PARecord が宣言された時点では ARecord は宣言されていませんが、ポインタ型に限っては標準Pascal以来このような例外的な宣言が許されています。そうしないとリスト構造が構築できませんから。標準Pascalでは type 節は唯一でした。FPC では言語仕様が拡張され、複数の type 節が許容されますが、ここで言っているのは PARecord と ARecord の二つの型名が同一の type 節になければならないという点です。

type
  PARecord = ^ARecord;
  ARecord = record
    data : integer;
    next : PARecord
  end;

#定義の順序の問題参照)

対策: After h2pas ツールに Remove redefined pointer types を加えます。

system typeの除去

h2pas が加える system types の一部(例えば PLongint)は現在では system ユニットに含まれています。

対策: After h2pas ツールに Remove type redefinitons like PLongint を加えます。

空のtype/var/const節

上記のツールを利用すると、変数・型・定数がいくたりか削除されます。その結果空の節ができることがありますが、これは Pascal では許容されません。

対策: After h2pas ツールに Remove empty type/var/const sections を加えます。

暗黙の型

C は引数として例えば int [][3] のような暗黙の型 implicit type を許容します。Pascal はこれを許しませんので、それに名前を与えて型として宣言しなければなりません。h2pas はそこまでの処理を自動的に行うことができず、その代わりに Pascal もどきの構文に置き換えます。例えば:

 int some_func(int [][3]);

は、こうなります

 function some_func(_para1:array[0..2] of Plongint):longint;cdecl;external;

対策: 幸いなことに、この種の暗黙の型を除去し明示的な型を加える新たなツールができました。Replace implicit typesafter ツールに組み込んでください。

Array of 無

時として、h2pas は C の引数省略 '...' を誤って 'array of )' に変換してしまいます。これは 'array of const)' でなければなりません。

対策: After h2pas ツールに Fix open arrays を加えます。

識別子が見つからない

Identifier not found というエラーが起きるのは次の三つの場合です:

定義の順序の問題

先に型を宣言する場合、それは同一の type 節の中である必要があります。例えば:

 type
   TMyRecord = record
     Next: PMyRecord; // using the forward definition
   end;
   PMyRecord = ^TMyRecord;

下の例は許されません。異なる type 節に分かれているからです:

 type
   TMyRecord = record
     Next: PMyRecord; // using the forward definition
   end;
 type
   PMyRecord = ^TMyRecord;

対策: コードの順序を入れ替えなければなりません。自動的にこれを行うツールはまだありません。

他のファイルで宣言された識別子

対策: uses 節にそのユニットを追加する。

追加するユニットが既にこのユニットを uses している場合、循環参照に陥ります。これは .h ファイルでは許されていますが、Pascal ユニットでは許されません。このような場合、コードをユニット間で移動するか、gtk2 バインディングのように IFDEF を用いる必要があります。自動的にこれらを行うツールはまだありません。

提案

次のようなツールを作れば、以上の問題はほとんど解決されます: バインディングに含まれる全ユニットの全ての定数を抽出し、一つの大きな constant 節に押し込む。型名についても同様にして、constant 節の後に置く。

不利な点: どの識別子がどの .h ファイルに含まれているのかわからなくなってしまいます。最低限コメントを加える必要があるでしょう。

未定義の識別子

不足しているヘッダファイルがあるか、ヴァージョンが違うと思われます。

対策: ヘッダファイルを探すか、その識別子をコメントにします。自動的にこれらを行うツールはまだありません。

Publish your bindings on lazarus-ccr or Free Pascal

ToDo

自分の変換ツールを書く

"Search and replace"ツールを使う

変数名の変更のような作業は Search and replace ツールで可能です。'Before h2pas' や 'After h2pas' ページにある Add new tool ボタンでツールを追加することができます。その後、SearchForReplaceWithOptionsCaption といったプロパティを設定します。

例: 識別子 Tguint を guint に変更する

Property Value
Caption Rename Tguint to guint
SearchFor Tguint
ReplaceWith guint
Options [trtMatchCase,trtWholeWord]

例: 複数の識別子を改名する

Tguint を guint、Tgulong を gulong、Tgint を gintに改名する:

Property Value
Caption Rename Tguint to guint
SearchFor gint|gulong)
ReplaceWith $1
Options [trtMatchCase,trtWholeWord,trtRegExpr]

今あるツールの改善

見つけたバグを修正したい、上記のツールを拡張したい、そいつは素晴らしい!

上記のツールのほとんどは h2pasconvert ユニットに定義されています。これは h2paswizard パッケージの一部です。こういったツールはクラス名、クラスの記述、Execute メソッドを必要とします。ツールを IDE の外でテスト/デバグすると、コンパイル時間を大いに短縮することができますが、その方法については components/simpleideintf/examples/testh2pastool.lpi プロジェクトをご覧ください。これをコンパイルしてコンソール/ターミナルで走らせます。最初のコマンドライン引数に .h ファイルの名前を与えます。例えば:

 ./testh2pastool files/h2pastest.pas

カスタムツールを書く

自分で変換ツールを書いて、容易に IDE に追加することができます。パッケージを開き新しいユニット(ここでは unit1 とします)を追加し、そのユニットに新しいクラスを書きます。既存のツールを参考にし、これまでのセクションをお読みください。新しいツールを書いて上記の simpleideintf プロジェクトでテストしたら、IDE に登録します: 追加したいユニット(ここでは unit1)に register 手続きを加えます。次に疑似コードを示します:

uses
  Classes, ..., IDETextConverter;

type
  TYourToolClass = class(TCustomTextConverterTool)
  public
    class function ClassDescription: string; override;
    function Execute(aText: TIDETextConverter): TModalResult; override;
  end;

procedure Register;

implementation

procedure Register;
begin
  TextConverterToolClasses.RegisterClass(TYourToolClass);
end;

忘れずにパッケージエディタの register チェックボックスをイネーブルしてください。さもないと Register 手続きは IDE から呼び出されません。次いで新しいパッケージを IDE にインストールします。

これからの作業/あるといいもの

  • 複数の .h ファイルを一つのユニットに変換できるようにウィザードを拡張すること。循環参照の多くが自動的に解決されます。
  • 未定義の識別子を見つけ出し、どれをコメントにするかチェックできるようにすること。
  • 半ば翻訳されたマクロのリストを生成すること。