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


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

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

```bash:
...
  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`というキーがあるかを判別しているようだ。


```python: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`はどのような情報を表しているのか。
[公式のリファレンス](http://docs.python.jp/3/library/sysconfig.html#sysconfig.get_config_vars)を見ると、「引数がない場合、現在のプラットフォームに関するすべての構成変数の辞書を返します。」という記述がある。「構成変数」というのは[同ページ](http://docs.python.jp/3/library/sysconfig.html#configuration-variables)で説明されているように、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


```bash: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](https://github.com/python/cpython/blob/master/Mac/README#L18)に記載がある。指定することにより、フレームワーク形式でPythonをビルドできる(フレームワーク形式については[こちら](https://developer.apple.com/library/mac/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/WhatAreFrameworks.html#//apple_ref/doc/uid/20002303-BBCEIJFI)参照)。この引数がデフォルトでは指定されないため、自身の環境で使用している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

```bash: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:bash:sysconfigモジュールの実行結果(pyenvでインストールしたPython(--enable-framework指定))
$ 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も同様にフレームワーク形式でビルドされていないものであるため注意すること。