4. C および C++ 拡張のビルド
****************************

CPython の C 拡張は *初期化関数* をエクスポートした共有ライブラリ (例
、 Linux の ".so" ファイルや Windows の ".pyd" ファイル) です。

インポートできるように、共有ライブラリは使える状態で "PYTHONPATH" 上に
なければならず、ファイル名をモジュール名に揃え、適切な拡張子になってい
なければいけません。 distutils を使っているときは、自動的に正しいファ
イル名が生成されます。

初期化関数のシグネチャは次のとおりです:

PyObject *PyInit_modulename(void)

この関数は完全に初期化されたモジュールか、 "PyModuleDef" インスタンス
を返します。 詳しいことは Cモジュールの初期化 を参照してください。

名前にASCIIしか使っていないモジュールの場合、関数名は
"PyInit_<modulename>" の "<modulename>" をモジュール名で置き換えたもの
でなければなりません。 多段階初期化 を使っているときは、モジュール名に
ASCII以外の文字も使えます。 この場合、初期化関数の名前は
"PyInitU_<modulename>" で、 "<modulename>" はハイフンをアンダースコア
で置き換えて Python の *punycode* エンコーディングでエンコードしたもの
になります。 Python で書くと次のような処理になります:

   def initfunc_name(name):
       try:
           suffix = b'_' + name.encode('ascii')
       except UnicodeEncodeError:
           suffix = b'U_' + name.encode('punycode').replace(b'-', b'_')
       return b'PyInit' + suffix

1つの共有ライブラリに複数の初期化関数を定義することで、複数のモジュー
ルをエクスポートすることは可能です。 しかし、デフォルトではファイル名
に対応した関数しか見付けようとしないので、複数のモジュールをインポート
させるにはシンボリックリンクか独自のインポーターを使う必要があります。
詳しいことは **PEP 489** の *"Multiple modules in one library"* 節を参
照してください。


4.1. distutils による C および C++ 拡張モジュールのビルド
=========================================================

拡張モジュールは Python に含まれる distutils を使ってビルドできます。
distutils はバイナリパッケージの作成もサポートしているので、ユーザが拡
張モジュールをインストールする際に、必ずしもコンパイラや distutils が
必要というわけではありません。

distutils ベースのパッケージには、駆動スクリプト (driver script) とな
る "setup.py" が入っています。 "setup.py" は普通の Python プログラムフ
ァイルで、ほとんどの場合以下のような内容になっています:

   from distutils.core import setup, Extension

   module1 = Extension('demo',
                       sources = ['demo.c'])

   setup (name = 'PackageName',
          version = '1.0',
          description = 'This is a demo package',
          ext_modules = [module1])

この "setup.py" とファイル "demo.c" があるとき、以下のコマンド

   python setup.py build

を実行すると、 "demo.c" をコンパイルして、 "demo" という名前の拡張モジ
ュールを "build" ディレクトリ内に生成します。システムによってはモジュ
ールファイルは "build/lib.system" サブディレクトリに生成され、
"demo.so" や "demo.pyd" といった名前になることがあります。

"setup.py" 内では、コマンドの実行はすべて "setup" 関数を呼び出して行い
ます。 この関数は可変個のキーワード引数を取ります。上の例ではその一部
を使っているにすぎません。 もっと具体的にいうと、この例の中ではパッケ
ージをビルドするためのメタ情報と、パッケージの内容を指定しています。
通常、パッケージには Python ソースモジュールやドキュメント、サブパッケ
ージ等といった別のモジュールも入ります。 distutils の機能に関する詳細
は、 Python モジュールの配布 (レガシーバージョン) に書かれている
distutils のドキュメントを参照してください;  この節では拡張モジュール
のビルドについてのみ説明します。

駆動スクリプトの構成をよりよくするために、 "setup()" への引数を前もっ
て計算しておくことがよくあります。 上の例では、 "setup()" の
"ext_modules" は拡張モジュールのリストで、リストの各々の要素は
"Extension" クラスのインスタンスになっています。 上の例では、 "demo"
という名の拡張モジュールを定義していて、単一のソースファイル "demo.c"
をコンパイルしてビルドするよう定義しています。

多くの場合、拡張モジュールのビルドはもっと複雑になります。 というのは
、プリプロセッサ定義やライブラリの追加指定が必要になることがあるからで
す。 例えば以下のファイルがその実例です。

   from distutils.core import setup, Extension

   module1 = Extension('demo',
                       define_macros = [('MAJOR_VERSION', '1'),
                                        ('MINOR_VERSION', '0')],
                       include_dirs = ['/usr/local/include'],
                       libraries = ['tcl83'],
                       library_dirs = ['/usr/local/lib'],
                       sources = ['demo.c'])

   setup (name = 'PackageName',
          version = '1.0',
          description = 'This is a demo package',
          author = 'Martin v. Loewis',
          author_email = 'martin@v.loewis.de',
          url = 'https://docs.python.org/extending/building',
          long_description = '''
   This is really just a demo package.
   ''',
          ext_modules = [module1])

この例では、メタ情報が追加された状態で "setup()" が呼び出されています
が、配布パッケージを構築するにあたっては、メタ情報を付けておくことが推
奨されます。 拡張モジュール自体についてのメタ情報には、プリプロセッサ
定義、インクルードファイルのディレクトリ、ライブラリのディレクトリ、ラ
イブラリといった指定があります。 distutils はこの情報をコンパイラに応
じて異なるやり方で引渡します。 例えば Unix では、上の設定は以下のよう
なコンパイルコマンドになるかもしれません

   gcc -DNDEBUG -g -O3 -Wall -Wstrict-prototypes -fPIC -DMAJOR_VERSION=1 -DMINOR_VERSION=0 -I/usr/local/include -I/usr/local/include/python2.2 -c demo.c -o build/temp.linux-i686-2.2/demo.o

   gcc -shared build/temp.linux-i686-2.2/demo.o -L/usr/local/lib -ltcl83 -o build/lib.linux-i686-2.2/demo.so

これらのコマンドラインは実演目的で書かれたものです; distutils のユーザ
は distutils が正しくコマンドを実行すると信用してください。


4.2. 拡張モジュールの配布
=========================

拡張モジュールをうまくビルドできたら、三通りの使い方があります。

エンドユーザは普通モジュールをインストールしようと考えます; これには、
次を実行します

   python setup.py install

モジュールメンテナはソースパッケージを作成します; これには、次を実行し
ます

   python setup.py sdist

場合によってはソース配布物に追加のファイルを含める必要があります; これ
には "MANIFEST.in" ファイルを使います; 詳しくは 配布するファイルを指定
する を参照してください。

ソースコード配布物をうまく構築できたら、メンテナはバイナリ配布物も作成
できます。プラットフォームに応じて、以下のコマンドのいずれかを使います
。

   python setup.py bdist_rpm
   python setup.py bdist_dumb
