iOSでは使えないPython
MacにはPythonが標準で入っているので、Cocoaアプリケーションではlibpythonが簡単に使えますが、iOSにはPythonが入ってないので使うことができません。
いくら調べてもPythonistaのことばっかりで嫌になります。
そんなところ、libpythonを静的ライブラリにしてiOSアプリに組み込んで動かすことができたので、ここで書くのはその方法。
kivy
kivyという、Pythonでマルチタッチアプリケーションを作成するツールがあり、これはiOSに対応しています。
Pythonのソースコードからライブラリをビルドするのは難しかったので、こいつからlibpythonだけを抜き出して使います。
kivyではPython2.7とPython3.7をサポートしています。ここでは3.7を利用しますが、2.7も基本的には同じやり方でできるはずなので、適宜読み替えてください。
kivyを使えるようにする
Python3を標準に
Python2.7にしたい場合はスキップしてください
python3が入っていない場合はhomebrewなどを使ってインストールしてください
alias python=python3
alias pip=pip3
kivyをダウンロードと必要なもののインストール
git clone git://github.com/kivy/kivy-ios
cd kivy-ios
pip install -r requirements.txt
xcode-select --install
brew install autoconf automake libtool pkg-config
brew link libtool
sudo pip3 install Cython==0.28.1
ビルド
./toolchain.py build python3
./toolchain.py build python3 hostpython
これでPythonのビルドは完了です。
kivy-ios/dist/lib/
内に
- libcrypto.a
- libffi.a
- libpython3.a
- libssl.a
が生成されているはずです。
プロジェクトにライブラリをインポート
必要なライブラリを追加
"Linked Frameworks and Libraries"に以下の3つを追加してください
- libz.tbd
- libbz2.tbd
- libsqlite3.tbd
ビルドしたライブラリのインポート
Project NavigatorにFrameworksというグループがあるはずなので、kivy-ios/dist/lib/
内にある4つのファイルをFinderからドラッグしてFrameworksグループに入れてください。
ダイアログが出てきたら"Copy items if needed"にチェックを入れて"Finish"をクリック。
python3をプロジェクトにコピー
kivy-ios/dist/root/python3
がpython3の本体みたいなので、これをProject Navigatorにドラッグして、ダイアログが出てきたら"Copy items if needed"と"Create folder references"にチェックを入れて"Finish"をクリック。
Project Navigatorでpython3のフォルダが青いアイコンならOKです
Header Search Pathsを指定
このままではPythonのヘッダをコンパイラが見つけてくれないので、指定します。
Build Settings内のHeader Search Pathsにpython3
をrecursiveで追加します
最終的にこうなっているはず
Objective-Cで使用
テストしてないです。
インクルード
使いたいクラスのヘッダで#include "Python.h"
PYTHONHOMEの指定
Py_Initializeをする前にPythonの標準ライブラリが入っているパス(PYTHON_HOME)を指定しないと標準ライブラリが使えません。なので、下にあるコードをPy_Initializeの前に実行してください。
NSString *resourcePath = [NSString stringWithFormat:@"%@/python3", [[NSBundle mainBundle] resourcePath], nil];
NSString *python_home = [NSString stringWithFormat:@"PYTHONHOME=%@", resourcePath, nil];
putenv((char *)[python_home UTF8String]);
実行
他のアプリケーションへの Python の埋め込み
あとはここに書いてある通りにすればいいです。
Swiftで使用
##インクルード
Bridging-Headerが必要です。
ない場合は自分で作ってBuild Settingsで指定するか、新しい"C File"を生成すると自動で生成してくれるのでそれを使います。
Bridging-Headerさえ用意できれば、そこに#include "Python.h"
と書くだけです。
PYTHONHOMEの指定
Py_Initializeをする前にPythonの標準ライブラリが入っているパス(PYTHON_HOME)を指定しないと標準ライブラリが使えません。なので、下にあるコードをPy_Initializeの前に実行してください。
let resourcePath = Bundle.main.resourcePath! + "/python3"
let python_home = "PYTHONHOME=\(resourcePath)" as NSString
putenv(UnsafeMutablePointer(mutating: python_home.utf8String))
実行
他のアプリケーションへの Python の埋め込み
あとはここに書いてあるみたいにできます。
ただし、1つ注意点があり、Swiftでは#defineによるマクロが使えないので、#defineで定義された関数が使えません。
例えば、
PyRun_SimpleString
は
#define PyRun_SimpleString(s) PyRun_SimpleStringFlags(s, NULL)
として定義されている関数なので、使うことができません。こういうときは、直接
PyRun_SimpleStringFlags(s, NULL)
を呼び出す必要があります。
こういうのは超高水準レイヤのような場所で調べたり、ヘッダーファイル内を関数名で検索すればわかりますが、面倒ですね。もしSwiftでライブラリ内のマクロ関数を使う方法を知っている方いたら教えて欲しいです。
サンプル
標準ライブラリが使えます。
でも、これだとまだpythonを実行するだけで、Swiftとの値のやりとりができてない。
あと、kivyのrecipesを見ると、標準ライブラリ以外にもいくつかライブラリが使えそうだけど、それもまだ試してない。
とりあえず、進捗があったらまた記事を上げます。