Edited at

そのインストール/ビルド失敗の悩み、sysconfigモジュールが救う(かもしれない)

More than 3 years have passed since last update.


Homebrewでpyqt5をインストールした際に発生したエラー

Homebrew経由でpyqt5をインストールしたところ、python3 configure.py実行中に以下のエラーが出た。

...

File "configure.py", line 2693, in main
target_config.from_introspection(opts.verbose, opts.debug)
File "configure.py", line 733, in from_introspection
self.py_pylib_dir = pylib_dir
UnboundLocalError: local variable 'pylib_dir' referenced before assignment
...

configure.pyの該当箇所は以下の通り。py_pylib_dirへの変数が代入されないのは、dynamic_pylibが偽の時だと分かる。

dynamic_pylibは、--enable-frameworkというキーがあるかを判別しているようだ。


configure.py

...

# Use distutils to get the additional configuration.
from distutils.sysconfig import get_config_vars
ducfg = get_config_vars()

config_args = ducfg.get('CONFIG_ARGS', '')

if sys.platform == 'darwin':
dynamic_pylib = '--enable-framework' in config_args
else:
dynamic_pylib = '--enable-shared' in config_args

if dynamic_pylib:
pyshlib = ducfg.get('LDLIBRARY', '')

exec_prefix = ducfg['exec_prefix']
multiarch = ducfg.get('MULTIARCH', '')
libdir = ducfg['LIBDIR']

if glob.glob('%s/lib/libpython%d.%d*' % (exec_prefix, py_major, py_minor)):
pylib_dir = exec_prefix + '/lib'
elif multiarch != '' and glob.glob('%s/lib/%s/libpython%d.%d*' % (exec_prefix, multiarch, py_major, py_minor)):
pylib_dir = exec_prefix + '/lib/' + multiarch
elif glob.glob('%s/libpython%d.%d*' % (libdir, py_major, py_minor)):
pylib_dir = libdir
else:
pylib_dir = ''
else:
pyshlib = ''

self.py_pylib_dir = pylib_dir
self.py_pylib_lib = pylib_lib
self.py_pyshlib = pyshlib
...



sysconfigモジュールによる構成情報の確認

ではget_config_vars関数で取得できる辞書と、そのキーのCONFIG_ARGSはどのような情報を表しているのか。

公式のリファレンスを見ると、「引数がない場合、現在のプラットフォームに関するすべての構成変数の辞書を返します。」という記述がある。「構成変数」というのは同ページで説明されているように、Pythonのビルド時(configure/make)に決定される情報が全て入っている。例えばCONFIG_ARGSには./configure実行時に指定した引数が格納されている。

get_config_varsで取得できる内容は、sysconfigモジュールを直接実行すると簡単に取得できる。実際に取得した結果、確かに--enable-frameworkは入っていない。

(ref.)

http://www.warp1337.com/content/python-32-get-compile-options-get-configargs

https://github.com/python/cpython/blob/master/Lib/sysconfig.py#L694


sysconfigモジュールの実行結果(エラーが発生した際のPython)

$ python -m sysconfig | grep CONFIG_ARGS

CONFIG_ARGS = "'--prefix=/Users/FGtatsuro/.anyenv/envs/pyenv/versions/3.4.2' '--libdir=/Users/FGtatsuro/.anyenv/envs/pyenv/versions/3.4.2/lib' 'LDFLAGS=-L/usr/local/opt/readline/lib -L/usr/local/opt/readline/lib -L/Users/FGtatsuro/.anyenv/envs/pyenv/versions/3.4.2/lib ' 'CPPFLAGS=-I/usr/local/opt/readline/include -I/usr/local/opt/readline/include -I/Users/FGtatsuro/.anyenv/envs/pyenv/versions/3.4.2/include '"

そもそも--enable-frameworkはなんなのか、というのはPythonのREADMEに記載がある。指定することにより、フレームワーク形式でPythonをビルドできる(フレームワーク形式についてはこちら参照)。この引数がデフォルトでは指定されないため、自身の環境で使用しているPython(pyenv経由でインストール)はフレームワーク形式でビルドされていなかった。

(PythonのREADMより抜粋)

* ``--enable-framework[=DIR]``

If this argument is specified the build will create a Python.framework rather
than a traditional Unix install. See the section
_`Building and using a framework-based Python on Mac OS X` for more
information on frameworks.


対処方法


HomebrewでインストールしたPythonを使う

Homebrewはデフォルトで--enable-frameworkを指定してビルドしている。

(ref.) https://github.com/Homebrew/homebrew/blob/master/Library/Formula/python3.rb#L77


sysconfigモジュールの実行結果(HomebrewでインストールしたPython)

$ /usr/local/bin/python3 -m sysconfig | grep CONFIG_ARGS

CONFIG_ARGS = "'--prefix=/usr/local/Cellar/python3/3.4.2_1' '--enable-ipv6' '--datarootdir=/usr/local/Cellar/python3/3.4.2_1/share' '--datadir=/usr/local/Cellar/python3/3.4.2_1/share' '--enable-framework=/usr/local/Cellar/python3/3.4.2_1/Frameworks' '--without-gcc' 'CFLAGS=-I/usr/local/include -I/usr/local/opt/sqlite/include' 'LDFLAGS=-L/usr/local/lib -L/usr/local/opt/sqlite/lib' 'MACOSX_DEPLOYMENT_TARGET=10.9' 'CC=clang'"


ビルド時に--enable-frameworkを指定する(pyenv)

pyenvは環境変数PYTHON_CONFIGURE_OPTSを指定することで、ビルド時の設定を変更できる。

(ref.) https://github.com/yyuu/pyenv/issues/99


bash

$ env PYTHON_CONFIGURE_OPTS="--enable-framework" pyenv install 3.3.6

$ pyenv global 3.3.6
$ ~/.anyenv/envs/pyenv/shims/python -m sysconfig | grep CONFIG_ARGS
CONFIG_ARGS = "'--prefix=/Users/tatsuro/.anyenv/envs/pyenv/versions/3.3.6' '--libdir=/Users/tatsuro/.anyenv/envs/pyenv/versions/3.3.6/lib' '--enable-framework' '--enable-framework=/Users/tatsuro/.anyenv/envs/pyenv/versions/3.3.6' 'LDFLAGS=-L/usr/local/opt/readline/lib -L/usr/local/opt/readline/lib -L/Users/tatsuro/.anyenv/envs/pyenv/versions/3.3.6/lib ' 'CPPFLAGS=-I/usr/local/opt/readline/include -I/usr/local/opt/readline/include -I/Users/tatsuro/.anyenv/envs/pyenv/versions/3.3.6/include '"


最後になるが、Virtualenv環境作成時に指定したPythonがフレームワーク形式でビルドされていない場合、作成した環境で使用するPythonも同様にフレームワーク形式でビルドされていないものであるため注意すること。