Macでpyinstallerを使ってPythonコードから実行ファイルを生成した時の記録（OSError: Python library not found: libpython3.7m.dylib, .Python, libpython3.7.dylibの回避）

# 記事の内容

Macでpyinstallerを使ってPythonコードから実行ファイルを生成した時の記録です。

## Pythonコード

```print_sys_path.py

import sys

print(sys.path)
print(f"__name__ = {__name__}")
print(f"__file__ = {__file__}")
```

## pyinstaller実行とエラーメッセージ

pipでインストールしたpyinstallerを使用し、端末で以下を実行しました。

```bash

pyinstaller print_sys_path.py --onefile
```

以下のようにPython library not foundエラーが出ました。

```

71 INFO: PyInstaller: 3.6
71 INFO: Python: 3.7.4
83 INFO: Platform: Darwin-19.2.0-x86_64-i386-64bit

（中略）

OSError: Python library not found: libpython3.7m.dylib, .Python, libpython3.7.dylib, Python
    This would mean your Python installation doesn't come with proper library files.
    This usually happens by missing development package, or unsuitable build parameters of Python installation.

    * On Debian/Ubuntu, you would need to install Python development packages
      * apt-get install python3-dev
      * apt-get install python-dev
    * If you're building Python by yourself, please rebuild your Python with `--enable-shared` (or, `--enable-framework` on Darwin)
```

## 対処その1 （1回目の--enable-sharedで失敗）

pyenvでPythonをインストールするときのオプションに「--enable-shared」を使用。
端末で以下を実行しました。

```bash

PYTHON_CONFIGURE_OPTS="--enable-shared" pyenv install 3.7.4
```

以下のように表示されて、3.7.4が上書きインストールされました。

```

pyenv: /Users/username/.pyenv/versions/3.7.4 already exists
continue with installation? (y/N) y
python-build: use openssl@1.1 from homebrew
python-build: use readline from homebrew
Downloading Python-3.7.4.tar.xz...
-> https://www.python.org/ftp/python/3.7.4/Python-3.7.4.tar.xz
Installing Python-3.7.4...
python-build: use readline from homebrew
python-build: use zlib from xcode sdk
Installed Python-3.7.4 to /Users/username/.pyenv/versions/3.7.4
```

使用されるPythonを確認します。

```bash

$ pyenv global
3.7.4
```

pyinstallerを起動したら、以下のようにまだPython library not foundエラーが出ました。

```bash

$ pyinstaller print_sys_path.py --onefile

（中略）

OSError: Python library not found: Python, libpython3.7.dylib, .Python, libpython3.7m.dylib
    This would mean your Python installation doesn't come with proper library files.
    This usually happens by missing development package, or unsuitable build parameters of Python installation.

    * On Debian/Ubuntu, you would need to install Python development packages
      * apt-get install python3-dev
      * apt-get install python-dev
    * If you're building Python by yourself, please rebuild your Python with `--enable-shared` (or, `--enable-framework` on Darwin)
```

.dylibファイルが見つからないと叱られているので、以下のようにfindコマンドで場所を探して、

```bash

find $HOME -name 'libpython3*.dylib' 2> /dev/null
```

LD_LIBRARY_PATH環境変数にlibpython3.7m.dylibの場所を指定して実行してみましたが、以下のようにPython library not foundエラーのままでした。

```bash

$ LD_LIBRARY_PATH=/Users/username/.pyenv/versions/3.7.4/lib pyinstaller print_sys_path.py --onefile

（中略）

OSError: Python library not found: .Python, Python, libpython3.7m.dylib, libpython3.7.dylib
    This would mean your Python installation doesn't come with proper library files.
    This usually happens by missing development package, or unsuitable build parameters of Python installation.

    * On Debian/Ubuntu, you would need to install Python development packages
      * apt-get install python3-dev
      * apt-get install python-dev
    * If you're building Python by yourself, please rebuild your Python with `--enable-shared` (or, `--enable-framework` on Darwin)
```

## 対処その2 （--enable-frameworkで成功）

pyenvでPythonをインストールするときのオプションに「--enable-framework」を使用。
端末で以下を実行しました。

```
PYTHON_CONFIGURE_OPTS="--enable-framework" pyenv install 3.7.4
```

以下のように表示されて、3.7.4が上書きインストールされました。

```
pyenv: /Users/username/.pyenv/versions/3.7.4 already exists
continue with installation? (y/N) Y
python-build: use openssl@1.1 from homebrew
python-build: use readline from homebrew
Downloading Python-3.7.4.tar.xz...
-> https://www.python.org/ftp/python/3.7.4/Python-3.7.4.tar.xz
Installing Python-3.7.4...
python-build: use readline from homebrew
python-build: use zlib from xcode sdk
Installed Python-3.7.4 to /Users/username/.pyenv/versions/3.7.4
```

pyinstallerを起動したら、以下のように「pyinstallerがない」というエラーが出ました。

```bash

$ LD_LIBRARY_PATH=/Users/username/.pyenv/versions/3.7.4/lib pyinstaller print_sys_path.py --onefile
-bash: /Users/username/.pyenv/shims/pyinstaller: No such file or directory
```

pyinstallerの再インストールを試みたら、以下のように「既にある」と言われました。

```bash

$ pip install pyinstaller
Requirement already satisfied: pyinstaller in /Users/username/.pyenv/versions/3.7.4/lib/python3.7/site-packages (3.6)
Requirement already satisfied: altgraph in /Users/username/.pyenv/versions/3.7.4/lib/python3.7/site-packages (from pyinstaller) (0.17)
Requirement already satisfied: setuptools in /Users/username/.pyenv/versions/3.7.4/Python.framework/Versions/3.7/lib/python3.7/site-packages (from pyinstaller) (40.8.0)
Requirement already satisfied: macholib>=1.8 in /Users/username/.pyenv/versions/3.7.4/lib/python3.7/site-packages (from pyinstaller) (1.14)
```

訳がわからなくなりました！
試行錯誤の結果、以下のようにアンインストール→インストールの手順で、pyinstallerを再インストールできました。

```bash

$ pip uninstall pyinstaller
Uninstalling PyInstaller-3.6:
  Would remove:
    /Users/username/.pyenv/versions/3.7.4/lib/python3.7/site-packages/PyInstaller-3.6.dist-info/*
    /Users/username/.pyenv/versions/3.7.4/lib/python3.7/site-packages/PyInstaller/*
Proceed (y/n)? Y
  Successfully uninstalled PyInstaller-3.6
```

```bash

$ pip install pyinstaller
Processing /Users/username/Library/Caches/pip/wheels/62/fe/62/4c0f196d1e0dd689e097449bc81d7d585a7de7dd86b081b80b/PyInstaller-3.6-cp37-none-any.whl
Requirement already satisfied: setuptools in /Users/username/.pyenv/versions/3.7.4/Python.framework/Versions/3.7/lib/python3.7/site-packages (from pyinstaller) (40.8.0)
Requirement already satisfied: macholib>=1.8 in /Users/username/.pyenv/versions/3.7.4/lib/python3.7/site-packages (from pyinstaller) (1.14)
Requirement already satisfied: altgraph in /Users/username/.pyenv/versions/3.7.4/lib/python3.7/site-packages (from pyinstaller) (0.17)
Installing collected packages: pyinstaller
Successfully installed pyinstaller-3.6
```

以下のように再びpyinstallerを起動したら、distディレクトリの下に実行ファイルが生成されました。
LD_LIBRARY_PATHを指定しましたが、指定しなくても動くようです。

```bash

LD_LIBRARY_PATH=/Users/username/.pyenv/versions/3.7.4/lib pyinstaller print_sys_path.py --onefile
```

生成された実行ファイルを起動しました（成功）。

```bash

dist/print_sys_path 
['/var/folders/kc/blch89657dv8zrzlxjljz6f40000gr/T/_MEInZMCQo/base_library.zip', '/var/folders/kc/blch89657dv8zrzlxjljz6f40000gr/T/_MEInZMCQo']
__name__ = __main__
__file__ = print_sys_path.py
```

## 対処その3 （2回目の--enable-sharedで成功）

1回目の--enable-sharedは失敗しましたが、再び--enable-sharedでインストールしたら成功するようになっていたので、記録しておきます。

pyenvでPythonのインストール：

```bash

$ PYTHON_CONFIGURE_OPTS="--enable-shared" pyenv install 3.7.4
pyenv: /Users/username/.pyenv/versions/3.7.4 already exists
continue with installation? (y/N) y
python-build: use openssl@1.1 from homebrew
python-build: use readline from homebrew
Downloading Python-3.7.4.tar.xz...
-> https://www.python.org/ftp/python/3.7.4/Python-3.7.4.tar.xz
Installing Python-3.7.4...
python-build: use readline from homebrew
python-build: use zlib from xcode sdk
Installed Python-3.7.4 to /Users/username/.pyenv/versions/3.7.4
```

pyinstaller起動：

```bash

pyinstaller print_sys_path.py --onefile
```

生成された実行ファイルを起動：

```bash

$ dist/print_sys_path 
['/var/folders/kc/blch89657dv8zrzlxjljz6f40000gr/T/_MEIf6CW7m/base_library.zip', '/var/folders/kc/blch89657dv8zrzlxjljz6f40000gr/T/_MEIf6CW7m']
__name__ = __main__
__file__ = print_sys_path.py
```

pipenvでも試します。
pyinstaller起動：

```bash

pipenv run pyinstaller print_sys_path.py --onefile
```

生成された実行ファイルを起動：

```bash

$ dist/print_sys_path 
['/var/folders/kc/blch89657dv8zrzlxjljz6f40000gr/T/_MEIPYS34b/base_library.zip', '/var/folders/kc/blch89657dv8zrzlxjljz6f40000gr/T/_MEIPYS34b']
__name__ = __main__
__file__ = print_sys_path.py
```

## 対処その1でうまく動かなかった理由

たぶん、pyenvでPythonを上書きインストールしたら、pipでインストールされていたものも再インストール（uninstall → install）が必要なんだろうと思います。
対処その1でPythonを上書きインストールしたけど、pyinstallerは以前から入っていたものをそのまま使ったので、同じエラーが発生してしまったのでしょう。