cython による C ライブラリのラップ

Last Change: 23-Oct-2015.
author : qh73xe

このページでは cython を使って C ライブラリのラッパーを書く方法をまとめます. 一般にこの手の作業では SWING, SIP, BoostPython, ctypes, cffi などのライブラリが 有名ですが, Cython でも C のラッパーを作成することはできます. もともと Cython 自身が C を python のように書きやすくするためのツールですので, 結構多くのことが python の流儀で記述できることが最大の魅力だと思います.

外部 C コードの宣言: extern ブロック文

Cython で C ライブラリをラップするには, まず Cython の中で扱いたい C コンポーネントのインターフェースを宣言する必要があります. これに使用するのが extern ブロック文です. この宣言ブロックでは ラップをしたい C コードのヘッダファイルのどの要素を使いたいのかを宣言します.

cdef extern from "header_name":

ヘッダ名は文字列として渡すようです. この宣言を行うことで以下の3つのことができます.

  1. cython コンパイラは,生成されるソースコードの中に #include "header_name" 行を生成
  2. cython コードからブロックで宣言された型, 関数, その他の言語要素にアクセスできるようにする
  3. cython はコンパイル時に C で宣言されたものが型的に正しいのかをチェックし, 正しくなければコンパイルエラーを出す
  • extern ブロック内の宣言は変数と関数については C に似た構文になっている. 1. struct, union の宣言では Cython 固有の構文を使用する.

特定のヘッダファイルに include プリプロセッサディテクティブを生成したいだけで, 宣言はいらない場合,宣言ブロックを空にしておくこともできます.

cdef extern from "header_name":
    pass

逆にヘッダファイル名が不要な場合, from * を使えば include 文は生成されません.

cdef extern from *:
    hogehoge

注釈

Cython ではしないこと

ここで注意が必要なのは, extern ブロックは 宣言された C 関数, 変数, 構造体が型であるという点で正しく使われていることを保証するに過ぎないということです. 結局, このブロックは include 文を生成することしかしませんので, 宣言された C 関数を呼び出す, def, cpdef, cdef 等は自分で書くことになります.

外部C関数と typedef 宣言

上記の説明からわかるように extern ブロックに設置される宣言は大抵 C 関数 か typedef です. これは,だいたい C の宣言と同様に作成できます.

cython と c との差異を以下にまとめます.

extern ブロックに宣言する際の主な変更点
C cython
typedef ctypedef
restrict, volatile などサポートされていないキーワード 取り除く
関数の戻り値の型と名前 一行で宣言する
行末のセミコロン 取り除く

宣言が長い場合, python の 引数リストなどと同様, 開き括弧の後で複数行に記述ができます.

具体例

例えば以下のヘッダファイルに含まれている C 宣言とマクロをみてみます.

header.h
#define M_PI 3.141592
#define MAX(a, b) ((a) >= (b) ? (a) : (b))

double hypot(doublem double);

typedef int integral;
typedef double real;

void func(integral[], integral[][10], real **);
real *func_arrays(integral[], integral[][10], real **);

これを Cython 宣言に直すと以下のようになります.

cdef extern from "header.h":
    double M_PI
    float MAX(float a, float b)

    double hypot(double x, double y)

    ctypedef int integral
    ctypedef double real

    void func(integral a, integral b, real c);

    real *func_arrays(integral[], integral[][10], real **k);

C の構造体,共用体,列挙型の宣言とラップ C関数のラップ 拡張子を使ったC構造体のラップ const, その他の修飾子, Cython が生成するコードの制御 エラーチェックと例外の生成 コールバック コールバックと例外の伝搬 まとめ