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'))
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'}
packages = ['foo']
を指定すれば、
lib/foo/__init__.py が存在すると Distutils に
確約したことになります。
もう一つの規約のあり方は foo パッケージを lib に 置き換え、foo.bar パッケージが lib/bar にある、 などとするものです。このような規約は、 setup スクリプトでは
package_dir = {'foo': 'lib'}
package: dir
のようなエントリがあると、
package の下にある全てのパッケージに対してこの規則が
暗黙のうちに適用され、その結果 foo.bar の場合が自動的に
処理されます。
この例では、 packages = ['foo', 'foo.bar']
は、
Distutils に lib/__init__.py と
lib/bar/__init__.py を探すように指示します。
(package_dir は再帰的に適用されますが、この場合
packages の下にある全てのパッケージを明示的に指定
しなければならないことを心に留めておいてください:
Distutils は __init__.py を持つディレクトリを
ソースツリーから再帰的にさがしたりは しません 。)
小さなモジュール配布物の場合、パッケージを列挙するよりも、 全てのモジュールを列挙するほうがよいと思うかもしれません -- 特に、単一のモジュールが ``ルートパッケージ'' にインストール される (すなわち、パッケージは全くない) ような場合がそうです。 この最も単純なケースは 2.1 で示しました; ここではもうちょっと入り組んだ例を示します:
py_modules = ['mod1', 'pkg.mod2']
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 拡張モジュールをきわめて
柔軟に記述できるようなサポートを提供しています。
これについては後の節で説明します。
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++
ファイルをコンパイルして拡張モジュールを生成します。
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
に
なります。(マクロ 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
に渡すからです。
スクリプトとは、Python ソースコードを含むファイルで、コマンドライン
から実行できるよう作られているものです。スクリプトは Distutils に
複雑なことを一切させません。唯一の気の利いた機能は、スクリプトの
最初の行が #!
で始まっていて、 ``python'' という単語が
入っていた場合、Distutils は最初の行を現在使っているインタプリタを
参照するよう置き換えます。
scripts オプションには、単に上で述べた方法で取り扱うべき ファイルのリストを指定するだけです。PyXML の setup スクリプトを 例に示します:
setup (... scripts = ['scripts/xmlproc_parse', 'scripts/xmlproc_val'] )
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 |
Trove 分類語 | 文字列からなるリスト | (4) |
注記:
これらの文字列はいずれも 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 if sys.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 が何を実行しているか詳しい 情報を出力し、例外が発生した場合には完全なトレースバックを出力 するようにできます。
ご意見やご指摘をお寄せになりたい方は、 このドキュメントについて... をご覧ください。