3 setup スクリプトを書く

setup スクリプトは、Distutils を使ってモジュールをビルドし、配布し、 インストールする際の全ての動作の中心になります。 setup スクリプトの主な目的は、モジュール配布物について Distutils に 伝え、モジュール配布を操作するための様々なコマンドを正しく動作させる ことにあります。 上の 2.1 の節で見てきたように、 setup スクリプトは主に setup() の呼び出しからなり、 開発者が distuils に対して与えるほとんどの情報は setup() のキーワード引数として指定されます。

ここではもう少しだけ複雑な例: Distutils 自体の setup スクリプト、を 示します。これについては、以降の二つの節でフォローします。 (Distutils が入っているのは Python 1.6 以降であり、 Python 1.5.2 ユーザが他のモジュール配布物をインストールできるようにするための 独立したパッケージがあることを思い出してください。 ここで示した、Distutils 自身の setup スクリプトは、Python 1.5.2 に Distutils パッケージをインストールする際に使います。)

#!/usr/bin/env python

from distutils.core import setup

setup(name="Distutils",
      version="1.0",
      description="Python Distribution Utilities",
      author="Greg Ward",
      author_email="gward@python.net",
      url="http://www.python.org/sigs/distutils-sig/",
      packages=['distutils', 'distutils.command'],
     )

上の例と、 2.1 で示したファイル一つからなる小さな 配布物とは、違うところは二つしかありません: メタデータの追加と、 モジュールではなくパッケージとして pure Python モジュール群を 指定しているという点です。この点は重要です。というのも、 Distutils は 2 ダースものモジュールが (今のところ) 二つのパッケージに分かれて入って いるからです; 各モジュールについていちいち明示的に記述したリストは、 作成するのが面倒だし、維持するのも難しくなるでしょう。 その他のメタデータについては、 3.7 を参照してください。

setup スクリプトに与えるパス名 (ファイルまたはディレクトリ) は、 Unix におけるファイル名規約、つまりスラッシュ ('/') 区切りで 書かねばなりません。Distutils はこのプラットフォーム中立の表記を、 実際にパス名として使う前に、現在のプラットフォームに適した表記に 注意深く変換します。この機能のおかげで、setup スクリプトを異なる オペレーティングシステム間にわたって可搬性があるものにできます。 言うまでもなく、これは Distutils の大きな目標の一つです。 この精神に従って、このドキュメントでは全てのパス名をスラッシュ区切り にしています。 (MacOS プログラマは、先頭にスラッシュが ない 場合は、 相対パス を表すということを心に留めておかねば なりません。この規約は、コロンを使った MacOS での規約と逆だからです。)

もちろん、この取り決めは Distutils に渡すパス名だけに適用されます。 もし、例えば glob.glob()os.listdir() の ような、標準の Python 関数を使ってファイル群を指定するのなら、 パス区切り文字 (path separator) をハードコーディングせず、 以下のように可搬性のあるコードを書くよう注意すべきです:

    glob.glob(os.path.join('mydir', 'subdir', '*.html'))
    os.listdir(os.path.join('mydir', 'subdir'))


3.1 パッケージを全て列挙する

packages オプションは、 packages リスト中で 指定されている各々のパッケージについて、パッケージ内に見つかった 全ての pure Python モジュールを処理 (ビルド、配布、インストール、等) するよう Distutils に指示します。このオプションを指定するためには、 当然のことながら各パッケージ名はファイルシステム上のディレクトリ名と 何らかの対応付けができなければなりません。デフォルトで使われる 対応関係はきわめてはっきりしたものです。すなわち、パッケージ distutils が配布物ルートディレクトリからの相対パス distutils で表されるディレクトリ中にあるというものです。 つまり、setup スクリプト中で packages = ['foo'] と指定したら、 スクリプトの置かれたディレクトリからの相対パスで foo/__init__.py を探し出せると Distutils に確約した ことになります。この約束を裏切ると Distutils は警告を出しますが、 そのまま壊れたパッケージの処理を継続します。

ソースコードディレクトリの配置について違った規約を使っていても、 まったく問題はありません: 単に package_dir オプションを 指定して、 Distutils に自分の規約を教えればよいのです。 例えば、全ての Python ソースコードを lib 下に置いて、 ``ルートパッケージ'' 内のモジュール (つまり、どのパッケージ にも入っていないモジュール) を lib 内に入れ、 foo パッケージを lib/foo に入れる、といった 具合にしたいのなら、

package_dir = {'': 'lib'}
を setup スクリプト内に入れます。辞書内のキーはパッケージ名で、 空のパッケージ名はルートパッケージを表します。キーに対応する値は ルートパッケージからの相対ディレクトリ名です、この場合、 packages = ['foo'] を指定すれば、 lib/foo/__init__.py が存在すると Distutils に 確約したことになります。

もう一つの規約のあり方は foo パッケージを lib に 置き換え、foo.bar パッケージが lib/bar にある、 などとするものです。このような規約は、 setup スクリプトでは

package_dir = {'foo': 'lib'}
のように書きます。 package_dir 辞書に package: dir のようなエントリがあると、 package の下にある全てのパッケージに対してこの規則が 暗黙のうちに適用され、その結果 foo.bar の場合が自動的に 処理されます。 この例では、 packages = ['foo', 'foo.bar'] は、 Distutils に lib/__init__.pylib/bar/__init__.py を探すように指示します。 (package_dir は再帰的に適用されますが、この場合 packages の下にある全てのパッケージを明示的に指定 しなければならないことを心に留めておいてください: Distutils は __init__.py を持つディレクトリを ソースツリーから再帰的にさがしたりは しません 。)


3.2 個々のモジュールを列挙する

小さなモジュール配布物の場合、パッケージを列挙するよりも、 全てのモジュールを列挙するほうがよいと思うかもしれません -- 特に、単一のモジュールが ``ルートパッケージ'' にインストール される (すなわち、パッケージは全くない) ような場合がそうです。 この最も単純なケースは 2.1 で示しました; ここではもうちょっと入り組んだ例を示します:

py_modules = ['mod1', 'pkg.mod2']
ここでは二つのモジュールについて述べていて、一方は ``ルート'' パッケージに入り、他方は pkg パッケージに入ります。 ここでも、デフォルトのパッケージ/ディレクトリのレイアウトは、 二つのモジュールが mod1.pypkg/mod2.py にあり、pkg/__init__.py が存在することを暗示して います。また、パッケージ/ディレクトリの対応関係は package_dir オプションでも上書きできます。


3.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.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.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.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 の 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.3.4 ライブラリオプション

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

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

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

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

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

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

3.3.5 その他の操作

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

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

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

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

3.4 スクリプトをインストールする

ここまでは、スクリプトから import され、それ自体では実行されない ような pure Python モジュールおよび非 pure Python モジュール について扱ってきました。

スクリプトとは、Python ソースコードを含むファイルで、コマンドライン から実行できるよう作られているものです。スクリプトは Distutils に 複雑なことを一切させません。唯一の気の利いた機能は、スクリプトの 最初の行が #! で始まっていて、 ``python'' という単語が 入っていた場合、Distutils は最初の行を現在使っているインタプリタを 参照するよう置き換えます。

scripts オプションには、単に上で述べた方法で取り扱うべき ファイルのリストを指定するだけです。PyXML の setup スクリプトを 例に示します:

setup (... 
       scripts = ['scripts/xmlproc_parse', 'scripts/xmlproc_val']
      )

3.5 追加のファイルをインストールする

data_files オプションを使うと、モジュール配布物で必要な 追加のファイル: 設定ファイル、メッセージカタログ、データファイル、 その他これまで述べてきたカテゴリに収まらない全てのファイルを指定 できます。

data_files には、(directory, files) の ペアを以下のように指定します:

setup(...
      data_files=[('bitmaps', ['bm/b1.gif', 'bm/b2.gif']),
                  ('config', ['cfg/data.cfg']),
                  ('/etc/init.d', ['init-script'])]
     )

データファイルのインストール先ディレクトリ名は指定できますが、 データファイル自体の名前の変更はできないので注意してください。

各々の (directory, files) ペアには、インストール先の ディレクトリ名と、そのディレクトリにインストールしたいファイルを 指定します。directory が相対パスの場合、インストール プレフィクス (installation prefix、 pure Python パッケージなら sys.prefix 、拡張モジュールの入ったパッケージなら sys.exec_prefix) からの相対パスと解釈されます。 files 内の各ファイル名は、パッケージソースコード配布物 の最上階層の、 setup.py のあるディレクトリからの相対パスと 解釈されます。files に書かれたディレクトリ情報は、 ファイルを最終的にどこにインストールするかを決めるときには使われ ません; ファイルの名前だけが使われます。

data_files オプションは、ターゲットディレクトリを指定せずに、 単にファイルの列を指定できます。しかし、このやり方は推奨されておらず、 指定すると install コマンドが警告を出力します。 ターゲットディレクトリにデータファイルを直接インストールしたいなら、 ディレクトリ名として空文字列を指定してください。


3.6 追加のメタデータ

setup スクリプトには、名前やバージョンにとどまらず、その他の メタデータを含められます。以下のような情報を含められます:

メタデータ  説明    注記 
name パッケージの名前 短い文字列 (1)
version リリースのバージョン 短い文字列 (1)(2)
author パッケージ作者の名前 短い文字列 (3)
author_email パッケージ作者の電子メールアドレス 電子メールアドレス (3)
maintainer パッケージメンテナンス担当者の名前 短い文字列 (3)
maintainer_email パッケージメンテナンス担当者の 電子メールアドレス 電子メールアドレス (3)
url パッケージのホームページ URL (1)
description パッケージについての簡潔な概要説明 短い文字列  
long_description パッケージについての詳細な説明 長い文字列  
download_url パッケージをダウンロードできる場所 URL (4)
classifiers Trove 分類語 文字列からなるリスト (4)

注記:

(1)
必須のフィールドです。
(2)
バージョン番号は major.minor[.patch[.sub]] の形式をとるよう奨めます。
(3)
作者かメンテナのどちらかは必ず区別してください。
(4)
これらのフィールドは、2.2.3 および 2.3 より以前の バージョンの Python でも互換性を持たせたい場合には指定しては なりません。 リストは PyPI ウェブサイト にあります。

「短い文字列」
200 文字以内の一行のテキスト。
「長い文字列」
複数行からなり、ReStructuredText 形式で書かれた プレーンテキスト (http://docutils.sf.net/ を参照してください)。
「文字列のリスト」
下記を参照してください。

これらの文字列はいずれも Unicode であってはなりません。

バージョン情報のコード化は、それ自体が一つのアートです。 Python のパッケージは一般的に、 major.minor[.patch][sub] という バージョン表記に従います。 メジャー (major) 番号は最初は 0 で、これはソフトウェアが実験的リリース にあることを示します。メジャー番号は、パッケージが主要な開発目標を 達成したとき、それを示すために加算されてゆきます。マイナー (minor) 番号は、パッケージに重要な新機能が追加されたときに加算されてゆきます。 パッチ (patch) 番号は、バグフィクス版のリリースが作成されたときに 加算されます。末尾にバージョン情報が追加され、サブリリースを示す こともあります。これは "a1,a2,...,aN" (アルファリリースの場合で、 機能や API が変更されているとき)、 "b1,b2,...,bN" (ベータリリース の場合で、バグフィクスのみのとき) 、そして "pr1,pr2,...,prN" (プレリリースの最終段階で、リリーステストのとき) になります。 以下に例を示します:

0.1.0
パッケージの最初の実験的なリリース
1.0.1a2
1.0 の最初のパッチバージョンに対する、2 回目のアルファ リリース

classifiers は、 Python のリスト型で指定します:

setup(...
      classifiers = [
          'Development Status :: 4 - Beta',
          'Environment :: Console',
          'Environment :: Web Environment',
          'Intended Audience :: End Users/Desktop',
          'Intended Audience :: Developers',
          'Intended Audience :: System Administrators',
          'License :: OSI Approved :: Python Software Foundation License',
          'Operating System :: MacOS :: MacOS X',
          'Operating System :: Microsoft :: Windows',
          'Operating System :: POSIX',
          'Programming Language :: Python',
          'Topic :: Communications :: Email',
          'Topic :: Office/Business',
          'Topic :: Software Development :: Bug Tracking',
          ],
      )

setup.pyclassifiers を入れておき、なおかつ 2.2.3 よりも以前のバージョンの Python と後方互換性を保ちたいなら、 setup.py 中で setup() を呼び出す前に、以下のコードを 入れます。

# patch distutils if it can't cope with the "classifiers" or
# "download_url" keywords
if sys.version < '2.2.3':
    from distutils.dist import DistributionMetadata
    DistributionMetadata.classifiers = None
    DistributionMetadata.download_url = None


3.7 setup スクリプトをデバッグする

setup スクリプトのどこかがまずいと、開発者の思い通りに動作 してくれません。

Distutils は setup 実行時の全ての例外を捉えて、簡単なエラーメッセージ を出力してからスクリプトを終了します。このような仕様にしているのは、 Python にあまり詳しくない管理者がパッケージをインストールする際に 混乱しなくてすむようにするためです。 もし Distutils のはらわた深くからトレースバックした長大な メッセージを見たら、管理者はきっと Python のインストール自体が おかしくなっているのだと勘違いして、トレースバックを最後まで読み進んで 実はファイルパーミッションの問題だったと気づいたりはしないでしょう。

しかし逆に、この仕様は開発者にとってはうまくいかない理由を見つける 役には立ちません。そこで、 DISTUTILS_DEBUG 環境変数を空文字以外の 何らかの値に設定しておけば、 Distutils が何を実行しているか詳しい 情報を出力し、例外が発生した場合には完全なトレースバックを出力 するようにできます。

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