setup スクリプトは、Distutils を使ってモジュールをビルドし、配布し、インストールする際の全ての動作の中心になります。 setup スクリプトの主な目的は、モジュール配布物について Distutils に伝え、モジュール配布を操作するための様々なコマンドを正しく動作させることにあります。上の 簡単な例 の節で見てきたように、 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'],
)
上の例と、 簡単な例 で示したファイル一つからなる小さな配布物とは、違うところは二つしかありません: メタデータの追加と、モジュールではなくパッケージとして pure Python モジュール群を指定しているという点です。この点は重要です。というのも、 Distutils は 2 ダースものモジュールが (今のところ) 二つのパッケージに分かれて入っているからです; 各モジュールについていちいち明示的に記述したリストは、作成するのが面倒だし、維持するのも難しくなるでしょう。その他のメタデータについては、 追加のメタデータ を参照してください。
setup スクリプトに与えるパス名 (ファイルまたはディレクトリ) は、 Unix におけるファイル名規約、つまりスラッシュ (‘/’) 区切りで書かねばなりません。Distutils はこのプラットフォーム中立の表記を、実際にパス名として使う前に、現在のプラットフォームに適した表記に注意深く変換します。この機能のおかげで、setup スクリプトを異なるオペレーティングシステム間にわたって可搬性があるものにできます。言うまでもなく、これは Distutils の大きな目標の一つです。この精神に従って、このドキュメントでは全てのパス名をスラッシュ区切りにしています。
もちろん、この取り決めは Distutils に渡すパス名だけに適用されます。もし、例えば glob.glob() や os.listdir() のような、標準の Python 関数を使ってファイル群を指定するのなら、パス区切り文字 (path separator) をハードコーディングせず、以下のように可搬性のあるコードを書くよう注意すべきです:
glob.glob(os.path.join('mydir', 'subdir', '*.html'))
os.listdir(os.path.join('mydir', 'subdir'))
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__.py と lib/bar/__init__.py を探すように指示します。 (package_dir は再帰的に適用されますが、この場合 packages の下にある全てのパッケージを明示的に指定しなければならないことを心に留めておいてください: Distutils は __init__.py を持つディレクトリをソースツリーから再帰的にさがしたりは しません 。)
小さなモジュール配布物の場合、パッケージを列挙するよりも、全てのモジュールを列挙するほうがよいと思うかもしれません — 特に、単一のモジュールが “ルートパッケージ” にインストールされる (すなわち、パッケージは全くない) ような場合がそうです。この最も単純なケースは 簡単な例 で示しました; ここではもうちょっと入り組んだ例を示します:
py_modules = ['mod1', 'pkg.mod2']
ここでは二つのモジュールについて述べていて、一方は “ルート” パッケージに入り、他方は pkg パッケージに入ります。ここでも、デフォルトのパッケージ/ディレクトリのレイアウトは、二つのモジュールが mod1.py と pkg/mod2.py にあり、 pkg/__init__.py が存在することを暗示しています。また、パッケージ/ディレクトリの対応関係は package_dir オプションでも上書きできます。
pure Python モジュールを書くより Python 拡張モジュールを書く方がちょっとだけ複雑なように、 Distutils での拡張モジュールに関する記述もちょっと複雑です。pure モジュールと違い、単にモジュールやパッケージを列挙して、Distutils が正しいファイルを見つけてくれると期待するだけでは十分ではありません; 拡張モジュールの名前、ソースコードファイル (群) 、そして何らかのコンパイル/リンクに関する必要事項 (include ディレクトリ、リンクすべきライブラリ、等) を指定しなければなりません。
こうした指定は全て、 setup() の別のキーワード引数、 ext_modules オプションを介して行えます。 ext_modules は、 Extension インスタンスからなるただのリストで、各インスタンスに一個の拡張モジュールを記述するようになっています。仮に、 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 拡張モジュールをきわめて柔軟に記述できるようなサポートを提供しています。これについては後の節で説明します。
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 にします。
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++ ファイルをコンパイルして拡張モジュールを生成します。
この警告にかかわらず、現在次のようにしてSWIGに対してオプションを渡すことができます。
setup(...,
ext_modules=[Extension('_foo', ['foo.i'],
swig_opts=['-modern', '-I../include'])],
py_modules=['foo'],
)
もしくは、次のようにコマンドラインからオプションを渡すこともできます。
> python setup.py build_ext --swig-opts="-modern -I../include"
プラットフォームによっては、コンパイラで処理され、拡張モジュールに取り込まれるような非ソースコードファイルを含められます。非ソースコードファイルとは、現状では Visual C++向けの Windows メッセージテキスト (.mc) ファイルや、リソース定義 (.rc) ファイルを指します。これらのファイルはバイナリリソース (.res) ファイルにコンパイルされ、実行ファイルにリンクされます。
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 `` になります。(マクロ `` FOO `` を `` None `` にすると、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
があるのと同じになります。
拡張モジュールをビルドする際にリンクするライブラリや、ライブラリを検索するディレクトリも指定できます。 libraries はリンクするライブラリのリストで、 library_dirs はリンク時にライブラリを検索するディレクトリのリストです。また、 runtime_library_dirs は、実行時に共有ライブラリ (動的にロードされるライブラリ) を検索するディレクトリのリストです。
例えば、ビルド対象システムの標準ライブラリ検索パスにあることが分かっているライブラリをリンクする時には、以下のようにします。
Extension(...,
libraries=['gdbm', 'readline'])
非標準のパス上にあるライブラリをリンクしたいなら、その場所を library_dirs に入れておかなければなりません:
Extension(...,
library_dirs=['/usr/X11R6/lib'],
libraries=['X11', 'Xt'])
(繰り返しになりますが、この手の可搬性のない書き方は、コードを配布するのが目的なら避けるべきです。)
他にもいくつかオプションがあり、特殊な状況を扱うために使います。
extra_objects オプションには、リンカに渡すオブジェクトファイルのリストを指定します。ファイル名には拡張子をつけてはならず、コンパイラで使われているデフォルトの拡張子が使われます。
extra_compile_args および extra_link_args には、それぞれコンパイラとリンカに渡す追加のコマンドライン引数を指定します。
export_symbols は Windows でのみ意味があります。このオプションには、公開 (export) する (関数や変数の) シンボルのリストを入れられます。コンパイルして拡張モジュールをビルドする際には、このオプションは不要です: Distutils は公開するシンボルを自動的に initmodule に渡すからです。
配布物はパッケージと3種類の方法で関係します:
これらの関係は、 distutils.core.setup() 関数のキーワード引数を利用して指定することができます。
他のPythonモジュールやパッケージに対する依存は、 setup() の requires キーワード引数で指定できます。引数の値は文字列のリストでなければなりません。各文字列は、必要とするパッケージと、オプションとしてパッケージのバージョンを指定します。
あるモジュールかパッケージの任意のバージョンが必要な場合、指定する文字列はモジュール名かパッケージ名になります。例えば、 'mymodule' や 'xml.parsers.expat' を含みます。
特定のバージョンが必要な場合、修飾子(qualifier)の列を加えることができます。各修飾子は、比較演算子とバージョン番号からなります。利用できる比較演算子は:
< > ==
<= >= !=
これらの修飾子はカンマ(空白文字を入れても良いです)で区切って複数並べることができます。その場合、全ての修飾子が適合する必要があります; 評価する時に論理ANDでつなげられます。
いくつかの例を見てみましょう:
require式 | 説明 |
---|---|
==1.0 | version 1.0 のみが適合します |
>1.0, !=1.5.1, <2.0 | 1.5.1 を除いて、 1.0 より後ろで 2.0 より前の全てのバージョンに適合します。 |
これで、依存を指定することができました。同じように、この配布物が他の配布物に必要とされる何を提供するのかを指定する必要があります。これは、 setup() の provide キーワード引数によって指定できます。この引数の値は文字列のリストで、各要素はPythonモジュールかパッケージの名前です。バージョンを指定することもできます。もしバージョンが指定されなかった場合、配布物のバージョン番号が利用されます。
いくつかの例です:
provide 式 | 説明 |
---|---|
mypkg | mypkg を提供します。バージョンは配布物のものを使います。 |
mypkg (1.1) | mypkg version 1.1 を提供します。配布物のバージョン番号は気にしません |
パッケージは obsoletes キーワードを利用することで、他のパッケージを廃止することを宣言することもできます。この値は requires キーワードと似ています: モジュールやパッケージを指定する文字列のリストです。各文字列は、モジュールかパッケージの名前と、オプションとして一つ以上のバージョン指定から構成されています。バージョン指定は、モジュールやパッケージの名前のうしろに、丸括(parentheses)でかこわれています。
指定されたバージョンは、その配布物によって廃止されるバージョンを示しています。バージョン指定が存在しない場合は、指定された名前のモジュールまたはパッケージの全てが廃止されたと解釈されます。
ここまでは、スクリプトから import され、それ自体では実行されないような pure Python モジュールおよび非 pure Python モジュールについて扱ってきました。
スクリプトとは、Python ソースコードを含むファイルで、コマンドラインから実行できるよう作られているものです。スクリプトは Distutils に複雑なことを一切させません。唯一の気の利いた機能は、スクリプトの最初の行が #! で始まっていて、 “python” という単語が入っていた場合、Distutils は最初の行を現在使っているインタプリタを参照するよう置き換えます。デフォルトでは現在使っているインタプリタと置換しますが、オプション --executable (または -e) を指定することで、明示的にインタプリタのパスを指定して上書きすることができます。
scripts オプションには、単に上で述べた方法で取り扱うべきファイルのリストを指定するだけです。PyXML の setup スクリプトを例に示します:
setup(...,
scripts=['scripts/xmlproc_parse', 'scripts/xmlproc_val']
)
しばしばパッケージに追加のファイルをインストールする必要があります。このファイルは、パッケージの実装に強く関連したデータや、そのパッケージを使うプログラマーが必要とするドキュメントなどです。これらのファイルを パッケージデータ と呼びます。
パッケージデータは関数 setup() にキーワード引数 package_data を与えることで追加できます。この値はパッケージ名から、パッケージへコピーされる相対パス名リストへのマップである必要があります。それぞれのパスは対応するパッケージが含まれるディレクトリ(もし適切なら package_dir のマッピングが利用されます)からの相対パスとして扱われます。つまり、ファイルはソースディレクトリ中にパッケージの一部として存在すると仮定されています。この値にはグロブパターンを含むことができます。
パス名にはディレクトリ部分を含むことができます。必要なディレクトリはインストール時に作成されます。
たとえば、パッケージがいくつかのデータファイルを含むサブディレクトリを含んでいる場合、ソースツリーでは以下のように配置できます:
setup.py
src/
mypkg/
__init__.py
module.py
data/
tables.dat
spoons.dat
forks.dat
対応する setup() 呼び出しは以下のようになります:
setup(...,
packages=['mypkg'],
package_dir={'mypkg': 'src/mypkg'},
package_data={'mypkg': ['data/*.dat']},
)
バージョン 2.4 で追加.
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 コマンドが警告を出力します。ターゲットディレクトリにデータファイルを直接インストールしたいなら、ディレクトリ名として空文字列を指定してください。
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 | 分類語のリスト | 文字列からなるリスト | (4) |
platforms | プラットフォームのリスト | 文字列からなるリスト | |
license | パッケージのライセンス | 文字列からなるリスト | (6) |
注記:
これらの文字列はいずれも Unicode であってはなりません。
バージョン情報のコード化は、それ自体が一つのアートです。 Python のパッケージは一般的に、 major.minor[.patch][sub] というバージョン表記に従います。メジャー (major) 番号は最初は 0 で、これはソフトウェアが実験的リリースにあることを示します。メジャー番号は、パッケージが主要な開発目標を達成したとき、それを示すために加算されてゆきます。マイナー (minor) 番号は、パッケージに重要な新機能が追加されたときに加算されてゆきます。パッチ (patch) 番号は、バグフィクス版のリリースが作成されたときに加算されます。末尾にバージョン情報が追加され、サブリリースを示すこともあります。これは “a1,a2,...,aN” (アルファリリースの場合で、機能や API が変更されているとき)、 “b1,b2,...,bN” (ベータリリースの場合で、バグフィクスのみのとき) 、そして “pr1,pr2,...,prN” (プレリリースの最終段階で、リリーステストのとき) になります。以下に例を示します:
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.py に classifiers を入れておき、なおかつ 2.2.3 よりも以前のバージョンの Python と後方互換性を保ちたいなら、 setup.py 中で setup() を呼び出す前に、以下のコードを入れます。
# patch distutils if it can't cope with the "classifiers" or
# "download_url" keywords
from sys import version
if version < '2.2.3':
from distutils.dist import DistributionMetadata
DistributionMetadata.classifiers = None
DistributionMetadata.download_url = None
setup スクリプトのどこかがまずいと、開発者の思い通りに動作してくれません。
Distutils は setup 実行時の全ての例外を捉えて、簡単なエラーメッセージを出力してからスクリプトを終了します。このような仕様にしているのは、 Python にあまり詳しくない管理者がパッケージをインストールする際に混乱しなくてすむようにするためです。もし Distutils のはらわた深くからトレースバックした長大なメッセージを見たら、管理者はきっと Python のインストール自体がおかしくなっているのだと勘違いして、トレースバックを最後まで読み進んで実はファイルパーミッションの問題だったと気づいたりはしないでしょう。
しかし逆に、この仕様は開発者にとってはうまくいかない理由を見つける役には立ちません。そこで、 DISTUTILS_DEBUG 環境変数を空文字以外の何らかの値に設定しておけば、 Distutils が何を実行しているか詳しい情報を出力し、例外が発生した場合には完全なトレースバックを出力するようにできます。