はじめに
py2exeを使って、windowsでexeファイルを作るとき、意外とdistutilsとの組み合わせで書かれているサイトが多い。しかし、Linuxなどでpythonを使っていると、パッケージ化するときに、まず間違いなくdistribute(setuptools)と組み合わせて使いたくなる。setuptoolsパッケージはdistutilsを強化するもので、setuptoolsを入れるとdistutilsのsetup()関数に与えられるパラメータが強化されたり、egg形式でのパッケージ配布が可能になったり、easy_installと呼ばれるコマンドラインツールが使えるようになったりする。
このsetuptoolsは、最近、更新が止まっているのだが、その開発を引き継ぎ、完全互換なAPIを提供しているのがdistributeだ。今から使うなら、間違いなくdistributeを使ったほうが良い。早速、py2exeの説明をしたいところだが、おさらいもかねて、distributeから説明していく。(ちなみに、それぞれの概念は分離しているため、書くまでもないということなのかもしれない。そういう方にとっては、このページは役に立たない)
親切な方のコメントで、distributeが時代遅れになったことが判明。巡り巡って、setuptoolsを使った方が良いとのこと。
Since the Setuptools 0.7 release, Setuptools and Distribute have merged and Distribute is no longer being maintained.
setuptoolsの導入
まず、一般的なsetuptoolsの導入の仕方を紹介。
$ curl -O https://bitbucket.org/pypa/setuptools/downloads/ez_setup.py
$ sudo python ./dez_setup.py
setupスクリプトをダウンロードして実行するだけ。とても簡単。このパッケージを導入すると、easy_installというツールが使えるようになり、一般的なパッケージはこのツールを使って、site_packagesにインストールすることができるようになる(末尾のリンクを参照)。
ところで、ソースを配布するときは、setuptoolsのインストールが前提にできない。ドキュメントに「インストールしてね」と書くこともできるが、依存関係も解決できるpythonを使っているのに、そういうことをするのは、ちょっとカッコ悪い。そんな場合は、配布物にdistribute_setup.pyを含め、setup.pyの冒頭に以下のように記述する。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import ez_setup
ez_setup.use_setuptools()
setup.pyの冒頭に上記のような記述をいれておくと、setup.pyのスクリプト導入時にdistributeパッケージのインストールを行う。
setuptools+py2exeを組み合わせたsetup.pyの書き方
これまでの導入で、setuptoolsのインポートはできた。ここでは、setuptoolsとpy2exeを組み合わせたsetup.pyの書き方を紹介する。まず、最初にテンプレートは以下のとおりになる。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__author__ = "<author name>"
__author_email__ = "<author's email>"
__date__ = "<date>"
__version__ = "<version number>"
import os
from os import listdir
from os.path import join
from os.path import dirname
from os.path import splitext
import ez_setup
ez_setup.use_setuptools()
from setuptools import setup
import py2exe
def find_py_modules(dir):
py_modules = []
for f in listdir(dir):
base, ext = splitext(f)
if ext == '.py' and base != '<AppName>': py_modules.append(base)
return py_modules
def read(fname):
return open(join(dirname(__file__), fname)).read()
setup(name='VideoRecorder',
version=__version__,
description='<description>',
author=__author__,
author_email=__author_email__,
url='<project homepage>',
long_description=read('README'),
include_package_data=True,
console=[
{
'script': '<main python module>',
'icon_resources': [(1, '<icon path>'),],
},
],
package_dir = {'': 'src'},
py_modules=find_py_modules('src'),
package_data={'':['*.ini', '*.gif', '*.ico']},
data_files=[("", [<necessary dlls>]),],
zipfile=None
)
テンプレート中、<>で囲まれた部分は、作成者ごとに変更する部分である。以下にそのリストを挙げる。
変数 | 概要 |
---|---|
author | 作成者名 |
author's email | 作成者のEメールアドレスです |
date | 日付 |
version number | バージョン番号 |
app name | 主要pythonモジュールのパス |
description | 概要 |
project homepage | プロジェクトのホームページ |
icon path | アイコンのパス |
necessary dlls | 必要なファイルの配列、使用するパッケージによっては、dllや、フォントなどを含める必要がある。 |
プロジェクトに合わせて上記の変数は調整する必要がある。distributeからインポートされるメソッドは、setupである。setup.pyのパラメータは以下のとおり。
パラメータ | 概要 |
---|---|
version | ソフトウェアのバージョン番号 |
description | ソフトウェアの概要説明 |
author | 作成者名 |
author_email | 作成者の連絡先 |
url | プロジェクトのurl |
license | ライセンス情報(テンプレートでは未記載) |
keywords | キーワード情報(テンプレートでは未記載) |
long_description | ソフトウェアのより詳細な説明 |
console/windows | エラーメッセージ出力を望むか、コンソールプログラムを動作させるならconsoleパラメータとして、純粋なUIアプリとして、動作させるなら、windowsパラメータとして宣言する。 |
options | 辞書のキーとして、compressed, optimize, bundle_filesを指定する。(テンプレートでは未記載) |
include_package_data | CVSやSubversion、MANIFEST.inファイルに指定されているファイルを含めるかどうかを示すbool値 |
package_dir | パッケージの基底となるディレクトリ情報 |
package_data | パッケージ名と、ファイル名のパターンのリストを対応付ける辞書 |
py_modules | パッケージ化されていないpythonモジュール群の指定 |
data_files | 純正pythonパッケージ以外で配布物に含めるファイル群の指定 |
zipfile | pythonのモジュール群をzipfile化するかどうか指定 |
※他にも様々なパラメータがある。詳しくはサイト末尾のリンクから調べると良い。
その他のメソッドについて、下記にその意味を解説していく。なお、これらの関数とテンプレートの中の<>変数に関しては、必須ではないので、プロジェクトに合わせて、各自変更すれば良い。
def find_py_modules(dir):
py_modules = []
for f in listdir(dir):
base, ext = splitext(f)
if ext == '.py' and base != '<AppName>': py_modules.append(base)
return py_modules
find_py_modulesは、find_packagesのモジュール版(も簡易実装)である。外部パッケージを組み合わせたアプリケーションの場合、コアとなるソースはパッケージにするまでもない単位である場合がある。そのようなときは、packagesパラメータと、find_packagesメソッドの代わりに、py_modulesパラメータと、find_py_modulesメソッド(中身は各自、調整すること)を組み合わせると良い。
def read(fname):
return open(join(dirname(__file__), fname)).read()
readメソッドは、long_descriptionの内容をファイルから読み込むためのメソッドである。descriptionでは説明が足りない規模のアプリケーションを作る場合に便利なメソッドである。
リンク
setuptoolsそのものに関しては、正確で包括的な情報を有するブログがあるので、こちらを参照してほしい。
このサイトを作るときもこのサイトを参考にした。setuptoolsを扱う上で、起点となるサイトだと思う。その他、easy_installとdistributeに関してのリンクは以下のとおり。両方共、英語のサイトなので、もっと簡単な解説が欲しい場合は、以下のキーワード(+python)でGoogleで検索すると良い。