音楽プログラミングの超入門(仮)

Python / 音楽情報処理 初心者が、初心者にも分かるような記事を書きたい。

Python スクリプトのスタンドアロン化

Pitch shift

photo by Ryan Johnson

自分がググり倒した成果を書き連ねています。
この記事では、主にLinux環境を前提としているので注意してください。
WindowsMacでも同じような感じでいけるかも知れないです。

スタンドアロン アプリケーション

Pythonスクリプト言語であるため、インタプリタがインストールされている環境でしかプログラムを実行することができません。さらに、プログラムに外部パッケージ(Numpy、Scipyなど)を使用している場合は、それらのインストールも必要となります。

一方、C++Javaなどのコンパイル言語では、ソースコードをバイナリコードへコンパイルするため、大体どのような環境でも動かすことが可能です。

しかし、Pythonをメインで使っているプログラマとしては、Pythonのコードもどのような環境でも動くスタンドアロンアプリケーションに変換したいなあ、と思うわけです。そうすれば、相手の環境を気にすることなく、自分の書いたアルゴリズムなどを配布することができます。

今回は特に、信号処理でよく用いられるNumpy、Scipyなどの外部ライブラリを含んだコードをスタンドアロンにする方法を、備忘録的に書いておこうと思います。

cx_Freezeによるスタンドアロン

Pythonコードをスタンドアロンにするためのツールはいくつかあるようですが、今回はcx_Freezeというものを用いた方法を紹介します。(自分がうまくいったから)

cx_FreezeはPythonの外部パッケージなので、インストールは簡単にできます。面倒くさいのでググってください。

cx_Freezeがやってることは(多分)、プログラムの中で使ってるライブラリとかを全部かき集めてきてバイナリでラッピングするみたいな感じだと思います。(詳しくは知らない)

やること

cx_Freezeによるスタンドアロン化は簡単で、以下のステップで行うことができます。

  1. 好きなPythonコードを書く
  2. setup.py を書く
  3. " python setup.py build " を実行する

以上なのですが、つまるところ、setup.py の書き方が重要となってきます。

sample code

今回は SciPy などを使ったコードをスタンドアロン化することが目的なので、以下のようなコードを例にします。

from scipy import rand

print rand()

setup.py を書こう!

こんな感じで書きます。

# coding: utf-8
# Setup file for cx_Freeze

import sys
from cx_Freeze import setup, Executable

# -------
# Setup
# -------
packages = []
includes = ["scipy"]
excludes = []
binpaths = ["/usr/lib/atlas-base/", "/usr/lib/"]
binincludes = ['/usr/lib/libatlas.so.3gf', '/usr/lib/liblapack.so.3gf', '/usr/lib/libblas.so.3gf']
init_script = "ConsoleSetLibPath"

base = None

# if sys.platform == 'win32' : base = 'Win32GUI'

# exe にしたい python ファイルを指定
exe = Executable(script = './test.py',
                 base = base)

# セットアップ
setup(name = 'test',
      version = '0.2',
      description = 'converter',
      options = {"build_exe": {'copy_dependent_files':True, "includes":includes, 
                               "excludes":excludes, "packages":packages, 
                               'bin_path_includes':binpaths, 'bin_includes':binincludes, 
                               'create_shared_zip':True, "init_script": init_script}},
      executables = [exe])

上のsetupファイルで重要な部分を説明します。

  • packages: 使うパッケージを列挙
  • includes: 使うモジュールを列挙
  • binpaths: 依存するバイナリファイルのディレクト
  • binincludes: 依存するバイナリファイルのパス

scipyなどは、"packages" と "includes" のどちらに書いても動きますが、"packages" は余計なものまで色々フリーズしてしまい容量が大きくなるので、"includes" のほうがいいと思います。

"binincludes" はかなり重要で、最初一番ハマったところです。
scipyなどで使っているatlas、lapackblasといった計算ライブラリのパスを指定しています。もちろん環境によってパスが違ったりすると思うので、その辺は頑張って調べてください。(これは Ubuntu12.04 環境)
実はこれを記述しなくても、パッケージングしたマシンでは多分動きますが、他のマシンにファイルを移して実行するとエラーがでる、と言ったことが起きます。

パッケージングしよう

以下のコードを実行するだけです。

python setup.py build

これを走らすと、カレントディレクトリに build/ というディレクトリができて、その中にさらに exe.---/ みたいなディレクトリができてると思います。

これでpythonコードのスタンドアロン化が完了しました。

実行

さきほどできた、exe.--/ ディレクトリの中に実行バイナリファイルができています。元のpythonファイルと同じ名前になっていると思うので、テストファイルが test.py とすると、コマンドラインから以下のように実行できます。

./build/exe.---/test

"python test.py" の部分がバイナリに置き換わっただけだと思ってください。
これで乱数が print されれば成功です。

かなり簡単なテストコードを扱いましたが、個人的にかなり複雑なコードを試しても成功したので、多分大丈夫だと思います。