Linuxbrew×asdf構成で、Pythonの_ctypes問題を回避する

5308 ワード

Linuxbrew×asdf構成で、Pythonの_ctypes問題を回避する

手元ではMacOSを使っているが、普段の作業は開発用に立てたEC2インスタンスの中で作業をすることが多いです。
そして、なるべく覚えるコマンドを少なくしたい、関数を使いまわしたいという思いから開発用マシンでも以下の構成にしています。

  • OS: Ubuntu 20.04
  • パッケージ管理: aptlinuxbrew
  • ランタイムバージョン管理: pyenvasdf

こうすることで、手元と同じbrewコマンド経由でライブラリをインストールすることができ、
asdfだけでランタイムのバージョンも管理することができます。

しかし、linuxbrewasdfもまだ枯れていないために環境構築でめちゃくちゃハマってしまいました。。。

今後自分と同じように苦しむ人が現れないための供養記事になります。

超要約

以下で解決するはず

$ brew install bzip2 libffi libxml2 libxmlsec1 openssl readline sqlite xz zlib
$ asdf uninstall python <version>
$ CC="$(brew --prefix gcc)/bin/gcc-11" \
> asdf install python <version>

回避するために必要な知識

  • 環境が整っていないと、_ctypesモジュールのインストールはスキップされる
    • このエラーが出たときは、pythonをビルドし直す必要がある
  • asdf python pluginは実はpyenvのラッパー
    • 解決のヒントはasdfではなく、pyenvの周りに落ちている
  • pyenvはインストール方法によって、推奨されている環境構築の方法が違う
    • その辺の記事のコピペでは、解決できない場合がある

事の発端

Remote SSHプラグイン経由でEC2インスタンスにアクセス、VSCodeのJupyterUIで分析をしようとしたら、必要なipykernelがインストールできない。

ここでinstallをクリックしても、

installできていない...

推奨されているコマンドをターミナルで打つと、一見うまく言っているように見えるが、やっぱり駄目。。。
この無限ループ地獄に陥ってしまった。

詳しく

問題の直接的原因

上記のipykernelがインストールできない問題の根本原因は_ctypesモジュールがないことでした。
詳細は以下の記事が詳しいです。
【Python3】_ctypes と libffi のインストールに苦しんだ記録 – notemite.com

このエラーを解決するためには、ctypesが依存しているlibffiなどのライブラリをインストールしてPythonのビルド環境を整えてからPythonをビルド(=インストール)し直す必要があるとのことです。

自分の場合、asdf経由でPythonをインストールしていたので以下のようにPythonをインストールし直せば大丈夫かも知れないと思い、試してみました。
(どこかの記事でpythonプラグインごとインストールしなおすとうまくいったと見たのでそうしました)

$ asdf plugin remove python
$ asdf plugin add python
$ asdf install python <バージョン>

しかし、やっぱり駄目でした。。。

更に深ぼる

pythonの再インストールで駄目ということは、ビルド環境が整っていないのかも知れないと思い、ビルド環境を調べてみました。

自分の場合、cloud-initでインスタンスを立てる際にすべてインストールするようにしていたので、それを見直しました。
すると、必要な依存関係はすべてインストールされていました。
(なんなら、linuxbrewaptの両方でインストールできていました。。)

そこで、もしかしたらasdfのバグ何じゃないのかと思いasdfasdf-pythonのイシューを探りにいきました。
やはりそれっぽいものも見当たらなかったので次に、asdf-pythonコードを見てみました。

するとどうでしょう。asdfは内部的にpyenvを使っていたのです!!

https://github.com/danhper/asdf-python/blob/57a4d725e47b8624cc97cabcac2b064f0474b8b2/bin/utils.sh

pyenv周辺を探る

そこで、pyenvを検索KWに加えて改めてググり直してみました。
すると、homebrewを使っている場合は別の解決策が必要だというStackoverflowに行き着きました。

$ CC="$(brew --prefix gcc)/bin/gcc-11" \
$ pyenv install --verbose 3.10.0

python - Python3: ImportError: No module named '_ctypes' when using Value from module multiprocessing - Stack Overflow

ここで、閃きました。
もしかして、asdfは内部的にpyenvを使っているし、自分はaptではなく、linuxbrewで環境を作っている。
ということは、これと全く同じ方法で自分も問題も解決できるのではないか?

そこで、下記コマンドを試してみました。

$ asdf uninstall python <version>
$ CC="$(brew --prefix gcc)/bin/gcc-11" \
> asdf install python <version>

すると、、、、、うまくいきました!!!!!
無事解決!!

まとめ

色んな環境の違いにより、解決策は異なってくることがよく分かった経験になりました。
便利な新しいツールを使うのは便利だけど、高度なことをやっている分エラー解決が難しくなります。
そんな時にも基礎的な部分のことを知っていればなんとか対処することができます。

やはり、基礎が大事だとわかりました。

参考

python - Python3: ImportError: No module named '_ctypes' when using Value from module multiprocessing - Stack Overflow
【Python3】_ctypes と libffi のインストールに苦しんだ記録 – notemite.com
Home · pyenv/pyenv Wiki