Qt4/Qt5およびPySide(Qt4対応,Qt5に対応していないようなので)/PyQt(Qt5対応)を両立する際、環境変数まわりで少し工夫が必要だった。
前提環境
- OS X(10.9.5)
- virtualenvwrapper
- Homebrew
Qt4/Qt5のインストール
Homebrew経由でインストールする。
$ brew install qt
$ brew install qt5
PySideのインストール
PySideはpip経由でインストール可能だったため、virtualenv下にインストールする。
$ mkvirtualenv -p python3 pyside
(pyside)$ mkvirtualenv
(pyside)$ pip install PySide
PyQtのインストール
PyQtも同様にpip経由でインストールを試みたところ、既に削除されたのかインストールできなかった。
$ mkvirtualenv -p python3 pyqt
(pyqt)$ pip install PyQt5
Downloading/unpacking PyQt5
Could not find any downloads that satisfy the requirement PyQt5
Cleaning up...
No distributions at all found for PyQt5
Storing debug log for failure in /Users/FGtatsuro/.pip/pip.log
そのため、PyQtはHomebrew経由でインストールすることとした。インストール時のトラブルはこちら。なおPyQt自体はHomebrew経由でインストールしたが、関連するライブラリをインストールすることを考えて、PySideと同様にvirtualenv環境は作っておく。
(pyqt)$ brew install pyqt5
PySideの実行
ここにあるPySideのサンプルを動かそうとしたが、動的ライブラリの読み込みに失敗し実行できない。
(pyside)$ python pyside_test.py
Traceback (most recent call last):
File "pyside_test.py", line 6, in <module>
from PySide.QtCore import *
ImportError: dlopen(/Users/FGtatsuro/.homesick/repos/dotfiles/home/.virtualenvs/pyside/lib/python3.4/site-packages/PySide/QtCore.so, 2): Library not loaded: libpyside.cpython-34m.1.2.dylib
Referenced from: /Users/FGtatsuro/.homesick/repos/dotfiles/home/.virtualenvs/pyside/lib/python3.4/site-packages/PySide/QtCore.so
Reason: image not found
読み込もうとしている動的ライブラリはvirtualenvのsite-package下にある。そのパスを環境変数DYLD_LIBRARY_PATH
に追加することで実行できる。
(pyside)$ ls /Users/FGtatsuro/.homesick/repos/dotfiles/home/.virtualenvs/pyside/lib/python3.4/site-packages/PySide/libpyside.cpython-34m.1.2.dylib
/Users/FGtatsuro/.homesick/repos/dotfiles/home/.virtualenvs/pyside/lib/python3.4/site-packages/PySide/libpyside.cpython-34m.1.2.dylib
(pyside)$ export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:/Users/FGtatsuro/.homesick/repos/dotfiles/home/.virtualenvs/pyside/lib/python3.4/site-packages/PySide
(pyside)$ python pyside_test.py
PyQtの実行
ここにあるPyQtのサンプルを動かそうとしたが、こちらはPyQtのモジュールの読み込みに失敗する。
(pyqt)$ python pyqt_test.py
Traceback (most recent call last):
File "pyqt_test.py", line 4, in <module>
from PyQt5.QtCore import *
ImportError: No module named 'PyQt5'
Homebrew経由でインストールしたPyQt(+PyQtが依存しているsip)のsite-packageが、virtualenv環境から見えていないのが原因。そのパスを環境変数PYTHONPATH
に追加することで実行できる。
(pyqt)$ export PYTHONPATH=$PYTHONPATH:/usr/local/opt/pyqt5/lib/python3.4/site-packages:/usr/local/opt/sip/lib/python3.4/site-packages
(pyqt)$ python pyqt_test.py
環境変数の切り替え
ここまででPySide/PyQtの実行はできたが、これらを共存するとなるとまだ問題がある。PySideに必要なDYLD_LIBRARY_PATH
とPyQtの実行に必要なPYTHONPATH
が両方存在した場合、PyQtの実行に失敗する。(ライブラリの読み込みトラブル?)
(pyqt)$ env | egrep 'DYLD_LIBRARY_PATH|PYTHONPATH'
DYLD_LIBRARY_PATH=/Users/FGtatsuro/.homesick/repos/dotfiles/home/.virtualenvs/pyside/lib/python3.4/site-packages/PySide
PYTHONPATH=/usr/local/opt/pyqt5/lib/python3.4/site-packages:/usr/local/opt/sip/lib/python3.4/site-packages
(pyqt)$ python pyqt_test.py
Traceback (most recent call last):
File "pyqt_test.py", line 5, in <module>
from PyQt5.QtWidgets import *
RuntimeError: the PyQt5.QtCore module failed to register with the sip module
DYLD_LIBRARY_PATH
をunsetすれば実行可能になるが、virtualenv環境を切りかえるたびにこの変数を意識しなくてはならないのは非常に面倒に感じる。
そこでPySide/PyQtのvirtualenv環境をactivate/deactivateした際に必要な環境変数をexport/unsetするようにvirtualenvwrapperの設定ファイルを変更した。.virtualenvs/postactivate
はactivate「後」に実行され、.virtualenvs/predeactivte
はdeactive「前」に実行される。PySide環境の判定が「virtualenv環境下の」pipに依存しており、判定のタイミングはvirtualenv環境に入った「後」とvirtualenv環境から出る「前」でなくてはならない。
判定の条件は次の通り。
- PySide: pipでPySideがインストールされている。
- PyQt: virtualenv環境名に文字列
pyqt
を含む。
#!/bin/bash
# This hook is run after every virtualenv is activated.
# PySideがpipでインストールされていれば、DYLD_LIBRARY_PATHに必要なパスを追加する。
if [ `pip freeze | grep PySide` ]; then
# Now, I can use PySide on only 3.4.x environment
VENV_PYSIDE_PATH=$VIRTUAL_ENV/lib/python3.4/site-packages/PySide
if [ $DYLD_LIBRARY_PATH ]; then
export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:$VENV_PYSIDE_PATH
else
export DYLD_LIBRARY_PATH=$VENV_PYSIDE_PATH
fi
fi
# virtualenv環境名が"pyqt"を含んでいれば、PYTHONPATHに必要なパスを追加する。
if [ `basename $VIRTUAL_ENV | grep pyqt` ]; then
# Now, I can use PyQt on only 3.4.x environment
BREW_PYQT_PATH=`brew --prefix pyqt5`/lib/python3.4/site-packages:`brew --prefix sip`/lib/python3.4/site-packages
if [ $PYTHONPATH ]; then
export PYTHONPATH=$PYTHONPATH:$BREW_PYQT_PATH
else
export PYTHONPATH=$BREW_PYQT_PATH
fi
fi
#!/bin/bash
# This hook is run before every virtualenv is deactivated.
# PySideがpipでインストールされていれば、DYLD_LIBRARY_PATHから関連するパスを除く。
if [ `pip freeze | grep PySide` ]; then
# Now, I can use PySide on only 3.4.x environment
VENV_PYSIDE_PATH=$VIRTUAL_ENV/lib/python3.4/site-packages/PySide
export DYLD_LIBRARY_PATH=`echo $DYLD_LIBRARY_PATH | sed -e "s|:*$VENV_PYSIDE_PATH||g"`
if [ -z $DYLD_LIBRARY_PATH ]; then
unset DYLD_LIBRARY_PATH
fi
fi
# virtualenv環境名が"pyqt"を含んでいれば、PYTHONPATHから関連するパスを除く。
if [ `basename $VIRTUAL_ENV | grep pyqt` ]; then
# Now, I can use PyQt on only 3.4.x environment
BREW_PYQT_PATH=`brew --prefix pyqt5`/lib/python3.4/site-packages:`brew --prefix sip`/lib/python3.4/site-packages
export PYTHONPATH=`echo $PYTHONPATH | sed -e "s|:*$BREW_PYQT_PATH||g"`
if [ -z $PYTHONPATH ];then
unset PYTHONPATH
fi
fi
PyQtをpip経由でインストールすることができなかったため、判定の条件をvirtualenv環境の命名規則に頼らざるを得なかった。その点が少し残念なので、いいアイデアがないか考える。