3 拡張モジュールについて記述する

pure Python モジュールを書くより Python 拡張モジュールを書く方が ちょっとだけ複雑なように、 Distutils での拡張モジュールに関する 記述もちょっと複雑です。pure モジュールと違い、単にモジュールや パッケージを列挙して、Distutils が正しいファイルを見つけてくれる と期待するだけでは十分ではありません; 拡張モジュールの名前、 ソースコードファイル (群) 、そして何らかのコンパイル/リンクに 関する必要事項 (include ディレクトリ、リンクすべきライブラリ、等) を指定しなければなりません。

こうした指定は全て、 setup() の別のキーワード 引数、 extensions オプションを介して行えます。 extensions は、 Extensions インスタンスから なるただのリストで、各インスタンスに一個の拡張モジュールを 記述するようになっています。仮に、foo.c で実装された 拡張モジュール foo が、配布物に一つだけ入ってるとします。 コンパイラ/リンカに他の情報を与える必要がない場合、この拡張 モジュールのための記述はきわめて単純です:

Extension('foo', ['foo.c'])

Extension クラスは、 setup() によって、 distutils.core から import されます。 従って、拡張モジュールが一つだけ入っていて、他には何も入っていない モジュール配布物を作成するための setup スクリプトは、以下のように なるでしょう:

from distutils.core import setup, Extension
setup(name='foo', 
      version='1.0',
      ext_modules=[Extension('foo', ['foo.c'])],
      )

Explained クラス (実質的には、Explained クラスの 根底にある build_ext コマンドで実装されている、拡張 モジュールをビルドする機構) は、Python 拡張モジュールをきわめて 柔軟に記述できるようなサポートを提供しています。 これについては後の節で説明します。

3.1 拡張モジュールの名前とパッケージ

Extension クラスのコンストラクタに与える最初の引数は、 常に拡張モジュールの名前にします。これにはパッケージ名も含めます。 例えば、

Extension('foo', ['src/foo1.c', 'src/foo2.c']p)

とすると、拡張モジュールをルートパッケージに置くことになります。一方、

Extension('pkg.foo', ['src/foo1.c', 'src/foo2.c'])

は、同じ拡張モジュールを pkg パッケージの下に置くよう 記述しています。ソースコードファイルと、作成されるオブジェクトコードは どちらの場合でも同じです; 作成された拡張モジュールがファイルシステム 上のどこに置かれるか (すなわち Python の名前空間上のどこに置かれるか) が違うにすぎません。

同じパッケージ内に (または、同じ基底パッケージ下に) いくつもの拡張 モジュールがある場合、ext_package キーワード引数を setup() に指定します。例えば、

setup(...
      ext_package='pkg',
      ext_modules=[Extension('foo', ['foo.c']),
                   Extension('subpkg.bar', ['bar.c'])],
     )

とすると、 foo.c をコンパイルして pkg.foo にし、 bar.c をコンパイルして pkg.subpkg.bar にします。

3.2 拡張モジュールのソースファイル

Extension コンストラクタの二番目の引数は、ソースファイルの リストです。 Distutils は現在のところ、C、C++、そして Objective-C の拡張しかサポートしていないので、引数は通常 C/C++/Objective-C ソースコードファイルになります。 (C++ソースコードファイルを区別 できるよう、正しいファイル拡張子を使ってください: .cc.cpp にすれば、 Unix と Windows 用の双方のコンパイラで 認識されるようです。)

ただし、 SWIG インタフェース (.i) ファイルはリストに含め られます; build_ext コマンドは、 SWIG で書かれた 拡張パッケージをどう扱えばよいか心得ています: build_ext は、インタフェースファイルを SWIG にかけ、得られた C/C++ ファイルをコンパイルして拡張モジュールを生成します。

3.3 プリプロセッサオプション

Extension には三種類のオプション引数: include_dirs, define_macros, そして undef_macros があり、検索対象に するインクルードディレクトリを指定したり、プリプロセッサマクロを 定義 (define)/定義解除 (undefine) したりする必要があるとき役立ちます。

例えば、拡張モジュールが配布物ルート下の include ディレクトリにあるヘッダファイルを必要とするときには、 include_dirs オプションを使います:

Extension('foo', ['foo.c'], include_dirs=['include'])

ここには絶対パスも指定できます; 例えば、自分の拡張モジュールが、 /usr の下にX11R6 をインストールした Unix システムだけで ビルドされると知っていれば、

Extension('foo', ['foo.c'], include_dirs=['/usr/include/X11'])

のように書けます。

自分のコードを配布する際には、このような可搬性のない使い方は 避けるべきです: おそらく、 C のコードを

#include <X11/Xlib.h>

のように書いた方がましでしょう。

他の Python 拡張モジュール由来のヘッダを include する必要があるなら、 Distutils の install_header コマンドが一貫した方法で ヘッダファイルをインストールするという事実を活用できます。 例えば、 Numerical Python のヘッダファイルは、 (標準的な Unix が インストールされた環境では) /usr/local/include/python1.5/Numerical にインストールされます。 (実際の場所は、プラットフォームやどの Python をインストールしたかで 異なります。) Python の include ディレクトリ -- 今の例では /usr/local/include/python1.5 -- は、 Python 拡張モジュールを ビルドする際に常にヘッダファイル検索パスに取り込まれるので、 C コードを書く上でもっともよいアプローチは、

#include <Numerical/arrayobject.h>
となります。

Numerical インクルードディレクトリ自体をヘッダ検索パス に置きたいのなら、このディレクトリを Distutils の distutils.sysconfig モジュールを使って見つけさせられます:

from distutils.sysconfig import get_python_inc
incdir = os.path.join(get_python_inc(plat_specific=1), 'Numerical')
setup(...,
      Extension(..., include_dirs=[incdir]),
      )

この書き方も可搬性はあります -- プラットフォームに関わらず、 どんな Python がインストールされていても動作します -- が、 単に実践的な書き方で C コードを書く方が簡単でしょう。

define_macros および undef_macros オプションを使って、 プリプロセッサマクロを定義 (define) したり、定義解除 (undefine) したりもできます。 define_macros はタプル (name, value) からなるリストを 引数にとります。name は定義したいマクロの名前 (文字列) で、 value はその値です: value は文字列か None に なります。(マクロ FOONone にすると、C ソースコード内 で #define FOO と書いたのと同じになります: こう書くと、 ほとんどのコンパイラは FOO を文字列 1 に設定します。) undef_macros には、定義解除したいマクロ名からなるリストを 指定します。

例えば、以下の指定:

Extension(...,
          define_macros=[('NDEBUG', '1'),
                         ('HAVE_STRFTIME', None)],
          undef_macros=['HAVE_FOO', 'HAVE_BAR'])

は、全ての C ソースコードファイルの先頭に、以下のマクロ:

#define NDEBUG 1
#define HAVE_STRFTIME
#undef HAVE_FOO
#undef HAVE_BAR

があるのと同じになります。

3.4 ライブラリオプション

拡張モジュールをビルドする際にリンクするライブラリや、ライブラリを 検索するディレクトリも指定できます。 libraries はリンクするライブラリのリストで、 library_dirs はリンク時にライブラリを検索するディレクトリの リストです。また、runtime_library_dirs は、実行時に 共有ライブラリ (動的にロードされるライブラリ) を検索するディレクトリの リストです。

例えば、ビルド対象システムの標準ライブラリ検索パスにあることが分かって いるライブラリをリンクする時には、以下のようにします。

Extension(...,
          libraries=['gdbm', 'readline'])

非標準のパス上にあるライブラリをリンクしたいなら、その場所を library_dirs に入れておかなければなりません:

Extension(...,
          library_dirs=['/usr/X11R6/lib'],
          libraries=['X11', 'Xt'])

(繰り返しになりますが、この手の可搬性のない書き方は、コードを配布する のが目的なら避けるべきです。)

3.5 その他の操作

他にもいくつかオプションがあり、特殊な状況を扱うために使います。

extra_objects オプションには、リンカに渡すオブジェクトファイル のリストを指定します。ファイル名には拡張子をつけてはならず、コンパイラ で使われているデフォルトの拡張子が使われます。

extra_compile_args および extra_link_args には、 それぞれコンパイラとリンカに渡す追加のコマンドライン引数を指定します。

export_symbols は Windows でのみ意味があります。 このオプションには、公開 (export) する (関数や変数の) シンボルのリスト を入れられます。コンパイルして拡張モジュールをビルドする際には、 このオプションは不要です: Distutils は公開するシンボルを自動的に initmodule に渡すからです。

ご意見やご指摘をお寄せになりたい方は、 このドキュメントについて... をご覧ください。