Cygwinにpyenvをインストールした時の奮戦記


Cygwinに、pyenvをインストールしたときの記録。pythonのバージョンでインストールできたり、できなかったりした。

環境:Cygwin(Setup version 2.900(64 bit))

変更履歴:
 2020/01/17 初稿
 2020/01/19 pyenvの機能が動作しない件について追記

  • Cygwinにpyenvをインストール
    CygwinのSetupにはpyenvのパッケージが見つからなかったため、gitでインストールした。
$ git clone https://github.com/pyenv/pyenv.git ~/.pyenv
  • 環境変数の設定
$ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_bashrc
$ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_bashrc
$ echo 'eval "$(pyenv init -)"' >> ~/.bash_bashrc
$ source ~/.bash_bashrc
  • pyenvでインストールできるpythonの確認。
$ pyenv install --list
Available versions:
  2.1.3
  2.2.3
  2.3.7
 以下略
  • pythonのインストール
    初めにpython 3.7.6をインストールした。
$ pyenv install 3.7.6
Downloading Python-3.7.6.tar.xz...
-> https://www.python.org/ftp/python/3.7.6/Python-3.7.6.tar.xz
Installing Python-3.7.6...
WARNING: The Python bz2 extension was not compiled. Missing the bzip2 lib?
WARNING: The Python sqlite3 extension was not compiled. Missing the SQLite3 lib?
Installed Python-3.7.6 to /home/xxxx/.pyenv/versions/3.7.6

インストールは指定バージョンのpythonを自分のpyenv環境にインストールするため、時間がかかる。自分のPCで約10分かかった。

WARNINGが出たので次のように対応した。
WARNING: The Python bz2 extension was not compiled. Missing the bzip2 lib?の対応
CygwinのSetupで libbz2-devel というパッケージをインストールし、
pyenv uninstall -f 3.7.6
で、アンインストールしてから再度
pyenv install 3.7.6
を実行し解決。

WARNING: The Python sqlite3 extension was not compiled. Missing the SQLite3 lib?の対応
CygwinのSetupでsqlite3関係のパッケージをインストール(最終的にはsqlite3関係の全てのパッケージをインストール)したが、WARNINGは解決されなかった。
そこでCygwinのSetupでsqlite3関係のパッケージを全てアンインストール、SQLiteダウンロードサイト(※1)からソース(sqlite-autoconf-3300100.tar.gz)をダウンロード。解凍、./configure、make、make install を実行してSQLite3をインストール(インストール先はデフォルトの/usr/local)して再度 pyenv install して解決。

※1https://www.sqlite.org/download.html

  • python 3.6.10のインストール
    以下のようにエラーになった。
$ pyenv install 3.6.10
Downloading Python-3.6.10.tar.xz...
-> https://www.python.org/ftp/python/3.6.10/Python-3.6.10.tar.xz
Installing Python-3.6.10...

BUILD FAILED (CYGWIN_NT-6.1 3.1.2(0.340/5/3) using python-build 1.2.16-1-g4500a33c)

Inspect or clean up the working tree at /tmp/python-build.20200114100336.19695
Results logged to /tmp/python-build.20200114100336.19695.log

Last 10 log lines:
     PyStructSequence_SET_ITEM(result, 6, PyLong_FromLong(si->si_band));
                                                              ^
./Include/tupleobject.h:62:75: 備考: in definition of macro ‘PyTuple_SET_ITEM’
 #define PyTuple_SET_ITEM(op, i, v) (((PyTupleObject *)(op))->ob_item[i] = v)
                                                                           ^
./Modules/signalmodule.c:979:5: 備考: in expansion of macro ‘PyStructSequence_SET_ITEM’
     PyStructSequence_SET_ITEM(result, 6, PyLong_FromLong(si->si_band));
     ^~~~~~~~~~~~~~~~~~~~~~~~~
make: *** [Makefile:1782: Modules/signalmodule.o] エラー 1
make: *** 未完了のジョブを待っています....

./Modules/signalmodule.cでコンパイルエラーが発生している。そこでインストールが成功したPython-3.7.6とコンパイルエラーが発生したPython-3.6.10の./Modules/signalmodule.cソースを比べてみた。

python-3.6.10./Modules/signalmodule.cでエラーになった箇所
    PyStructSequence_SET_ITEM(result, 6, PyLong_FromLong(si->si_band));

python-3.7.6./Modules/signalmodule.cで同じ場所
#ifdef HAVE_SIGINFO_T_SI_BAND
    PyStructSequence_SET_ITEM(result, 6, PyLong_FromLong(si->si_band));
#else
    PyStructSequence_SET_ITEM(result, 6, PyLong_FromLong(0L));
#endif

上を見ると、python-3.7.6ではHAVE_SIGINFO_T_SI_BANDスイッチで処理を切り分けているのがわかる。
python-3.7.6のインストールパッケージのconfigureを見ると、Cygwinのヘッダーを調べsiginfo_t構造体にsi_bandが存在すればHAVE_SIGINFO_T_SI_BANDスイッチを1に設定し、存在していなければなにも無処理であった(Issue #21085の対応である)。従って、python-3.7.6ではコンパイルエラーにならなかった。
実際には Cygwinのsiginfo_t 構造体に si_band は存在しない。
ということで python-3.6.10では無条件にsiginfo_tのsi_bandを参照しているのでエラーになった。
調べたら環境変数 PYTHON_BUILD_CACHE_PATH を設定し、キャッシュしたソースをインストールできるという記事(※2)を見つけたので、それを利用し python-3.6.10 の ./Modules/signalmodule.c を python-3.7.6 のように変更してそれをインストールすればよいのではと考えた。

※2 https://github.com/pyenv/pyenv/tree/master/plugins/python-build

実際には以下のような手順を行ってみた。

$ pyenv install -k 3.6.10   *1
⇒ エラーになるが、$PYENV_ROOT/sources/3.6.10 にダウンロードした Python-3.6.10.tar.xz が残る。
[手操作] Python-3.6.10.tar.xz を適当な場所で、解凍・展開。
   エラーになった./Modules/signalmodule.cをpython-3.7.6のコードのように修正し、
   新たなPython-3.6.10.tar.xzを作成する。
$ mkdir $PYENV_ROOT/cache   *2
[手操作]先ほど新たに作成した Python-3.6.10.tar.xz を $PYENV_ROOT/cache にコピーする。
$ PYTHON_BUILD_CACHE_PATH=$PYENV_ROOT/cache pyenv install 3.6.10   *3

*1 -kは、ソースを保存するオプション。
*2 キャッシュ用ディレクトリを作成
*3 キャッシュにあるソースをインストールする( python-build を参照)

しかしそれでも
Downloading Python-3.6.10.tar.xz...
-> https://www.python.org/ftp/python/3.6.10/Python-3.6.10.tar.xz
と表示され、サーバーからダウンロードされる。
なお、pythonのサーバーからダウンロードしたパッケージをキャッシュに置いてキャッシュを用いる方法で install したら、Downloadはされなかった。
さらに調べたら、Join GitHub todayの記事(※3)で、インストールするパッケージは、pyenvで定義されている正しいSHA256 checksumでなければならないらしい。
もうこれ以上は、大変なのでこの方法によるPython-3.6.10のインストールは断念。

※3 https://github.com/pyenv/pyenv/issues/563

インストールのコマンドは

$ pyenv help install
Usage: pyenv install [-f] [-kvp] <version>
       pyenv install [-f] [-kvp] <definition-file>
       pyenv install -l|--list
       pyenv install --version

  -l/--list          List all available versions
  -f/--force         Install even if the version appears to be installed already
  -s/--skip-existing Skip if the version appears to be installed already

  python-build options:

  -k/--keep          Keep source tree in $PYENV_BUILD_ROOT after installation
                     (defaults to $PYENV_ROOT/sources)
  -p/--patch         Apply a patch from stdin before building
  -v/--verbose       Verbose mode: print compilation status to stdout
  --version          Show version of python-build
  -g/--debug         Build a debug version

で、他に<definition-file>を指定する方法と、--patchでパッチしてインストールする方法があるようだが、有用な情報を見つけることができずギブアップ。時間があれば pyenv のソースを見てみたいが!
本家に修正依頼をすればいいのだろうけど、英語駄目だし、やったこともないし流儀も分からないので無理。

  • 他にpython 2.7.17とpython 3.5.9のインストールしたがエラー発生。深追いはしていない。

  • python 3.8.1のインストールは成功。

$ pyenv install 3.8.1
Downloading Python-3.8.1.tar.xz...
-> https://www.python.org/ftp/python/3.8.1/Python-3.8.1.tar.xz
Installing Python-3.8.1...
Installed Python-3.8.1 to /home/xxxx/.pyenv/versions/3.8.1

$ pyenv versions
* system (set by /home/xxxx/.pyenv/version)
  3.7.6
  3.8.1
  • pyenvの動作確認

さて、python 3.7.6とpython 3.8.1はpyenvにインストールできたのだが、その動作確認でまたつまずいた。

$ pyenv global 3.8.1

$ pyenv versions
  system
  3.7.6
* 3.8.1 (set by /home/xxxx/.pyenv/version)

$ python -V
Python 2.7.16

$ pyenv which python
/usr/bin/python

と、Cygwinのパッケージでインストールしたpythonが実行されpyenvが機能していない。
そこでpyenvが動作しているubuntuのそれと比較してみた。すると、ubuntuのpyenv環境に存在するシンボリックリンクがCygwinのpyenv環境には存在していないことがわかった。
おそらく、$PYENV_ROOT/plugins/python-build\bin/python-build(bashスクリプト)を調べれば良いのかとは思うがそこまでする気にはならなかった。
対応として、手動で次のようなシンボリックリンクを作成した。

◎python 3.7.6 に対するシンボリックリンク

$ cd $PYENV_ROOT/versions/3.7.6
$ ln -s easy_install-3.7 easy_install
$ ln -s idle3.7 idle
$ ln -s pip3.7 pip
$ ln -s pydoc3.7 pydoc
$ ln -s python3.7m.exe python
$ ln -s python3.7-config python-config

◎python 3.8.1 に対するシンボリックリンク

$ cd $PYENV_ROOT/versions/3.8.1
$ ln -s easy_install-3.8 easy_install
$ ln -s idle3.8 idle
$ ln -s pip3.8 pip
$ ln -s pydoc3.8 pydoc
$ ln -s python3.8.exe python-buildpython
$ ln -s python3.8-config python-config

その後は以下のようにpyenvが機能するようになった。

$ pyenv init
$ pyenv rehash

$ pyenv global 3.7.6
$ pyenv versions
  system
* 3.7.6 (set by /home/xxxx/.pyenv/version)
  3.8.1
$ python -V
Python 3.7.6
$ pyenv which python
/home/xxxx/.pyenv/versions/3.7.6/bin/python

$ pyenv global 3.8.1
$ pyenv versions
  system
  3.7.6
* 3.8.1 (set by /home/xxxx/.pyenv/version)
$ python -V
Python 3.8.1
$ pyenv which python
/home/xxxx/.pyenv/versions/3.8.1/bin/python

$ pyenv global system
$ pyenv versions
* system (set by /home/xxxx/.pyenv/version)
  3.7.6
  3.8.1
$ python -V
Python 2.7.16
$ pyenv which python
/usr/bin/python
  • まとめ

pyenvでのpythonインストール結果は以下の通り。
 python 2.7.17 失敗
 python 3.5.9 失敗
 python 3.6.10 失敗
 python 3.7.6 成功
 python 3.8.1 成功

それでも、インストールが成功したものでも素直に機能せず、手動で個別対応(これもどこまで正しいか自信がない)が必要であった。
とりあえず、指定したバージョンのpythonは動くようにはなったが、そのpythonを使っていると新たにいろいろなトラブルが出てこないともかぎらない。
現状ではCygwinでpyenvを使用するのは避けた方が賢明ではないかと感じた。

苦労している方々の参考になればうれしい。
また、こうすればインストールできるよという情報をいただければ幸いです。

以上