Summary
windows10にpythonをインストールし、Jupyter NotebookでCythonの力を試そうとしたところ、DistutilsPlatformError: Unable to find vcvarsall.bat
というエラーに遭遇。
- 初回: 対処に4時間かかったorz
- 4年後: 対処に1.5日かかった..._(⌒(_´-ω-)_
でも!対処できたので記録を残しておこうと思います。
多分、この記事が参考になるという人はほとんどいないのではないかと思います....(危険な方法のため。もし、他の方法があったら是非教えて下さい)
環境1
4年前にこの問題に出くわした時の環境。
- | version |
---|---|
windows | 10 |
Visual Studio | Express Edition 2017 |
Anaconda3 | 2019.07 (Python3.7.3 64-bit) |
python | 3.7.3 |
Cython | 0.29.12 |
環境2
2023/10/01 に再び出くわした時の環境。
- | version |
---|---|
windows | 10 |
Visual Studio | Express Edition 2017 |
pyenv-win | 3.1.1 |
python |
|
Cython | 3.0.2 |
swig | 4.0.1 |
-> python 3.8.10 では解決できず、 3.7.3 に下げて4年前と同じ方法で無理やり解決させた。
症状
Cython 実行時エラー
# 参考にした記事: https://qiita.com/pashango2/items/45cb85390193d97523ca
%load_ext Cython
# --- next cell ---
%%cython
def py_fib(n):
a, b = 0.0, 1.0
for i in range(n):
a, b = a + b, a
return a
# result
...(略)
-> DistutilsPlatformError: Unable to find vcvarsall.bat
swig 実行時エラー
> python setup.py build_ext --inplace
running build_ext
building '_pafprocess' extension
swigging pafprocess.i to pafprocess_wrap.cpp
C:\swigwin-4.0.1\swig.exe -python -c++ -o pafprocess_wrap.cpp pafprocess.i
error: Unable to find vcvarsall.bat
対処
- pythonをコンパイルしたVC++のバージョンを調査
- Visual Studioをインストール
もちろん、1. で調べたバージョンをインストールする - Cythonのソースを無理やり書き換えて、
vcvarsall.bat
を見つけさせた (swig 実行時エラー発生時は不要っぽい?)
他の方法も色々試したんですが...この方法しか成功しませんでした
「なんでこんな方法にしたの?」と思われた方は、ここをご覧くださいな(;_;)
1. pythonをコンパイルしたVC++のバージョンを調査
C:\Users\PCUser>python
>>> import sys
>>> sys.version
'3.7.3 (default, Apr 24 2019, 15:29:51) [MSC v.1915 64 bit (AMD64)]'
ということで、コンパイラ VC++ のバージョンは V14.15 (Visual C++ 2017) と判明
Visual Studio のバージョン を sys.version
の出力結果からたどる場合、 wikipedia にも情報が書かれているが、
次のサイトの方が詳しい。
2. Visual Studio インストール
2017 ※以下の方法は、今は使えないようです
-
次のURLを開く
https://visualstudio.microsoft.com/ja/vs/express/ -
下にスクロールして以下の赤枠位置をクリックしてインストーラーをダウンロード
-
ダウンロードされたファイルを実行
vs_wdexpress.exe
特に設定変更などはせず -
vcvarsall.bat
ファイルを探す!
私の場合、ここにあった...↓
C:\Program Files (x86)\Microsoft Visual Studio\2017\WDExpress\VC\Auxiliary\Build
2017 ※代替策 (2023/10/01)
こちらの記事で、 Visual Studio express 2017 のインストール方法が書いてありました。
以下のサイトなどから、VIsual Studio 2022 などのインストーラを入手し、
powershell で、そのファイルがあるフォルダまで移動してから、以下のコマンドを実行します。
# VisualStudioSetup.exe の部分は、ダウンロードしたファイル名で置き換えてね
.\VisualStudioSetup.exe --channelUri https://aka.ms/vs/15/release/channel --productId Microsoft.VisualStudio.Product.WDExpress
すると、Visual Studio 2017 のインストールが開始できる状態になります。
install し終わったら、念のため windows 本体を再起動しておく。
このインストール方法、一体いつまで使えるのだろうか。。。
とりあえず、ファイルは4年前と同じここにあった。
C:\Program Files (x86)\Microsoft Visual Studio\2017\WDExpress\VC\Auxiliary\Build
昔と変わらず。
2019 ※使ってません
ここからダウンロードしたインストーラでインストールできます
※ただし、2019を使った解決策はまだ確立できておらず、この記事にも書いていません。
3. Cythonコードの書き換え
(swig 実行時エラーへの対処場合、やらなくてよさそう?)
Jupyter Notebook上のエラーログには、_msvccompiler.py
というファイルの135行目付近でエラーが発生したと書かれていたので、まずはそのファイルを探す。
ここにあった
- anaconda で環境構築してた時
C:\Users\PCUser\Anaconda3\Lib\distutils\_msvccompiler.py
- pyenv-win で環境構築した時
C:\Users\PCUser\...\.venv\Lib\site-packages\setuptools\_distutils\_msvccompiler.py
次に、_msvccompiler.py
の処理を追って行くと、次のメソッドでvcvarsall
がNone
になっているためにエラーが発生していることが判明。
# 135行目付近
def _get_vc_env(plat_spec):
if os.getenv("DISTUTILS_USE_SDK"):
return {
key.lower(): value
for key, value in os.environ.items()
}
vcvarsall, vcruntime = _find_vcvarsall(plat_spec)
if not vcvarsall:
# Jupyter Notebook上ではこのエラーが見える
raise DistutilsPlatformError("Unable to find vcvarsall.bat")
# ... 以下略
まずは error 発生直前の_find_vcvarsall
メソッドが怪しい。
このメソッドを探すと....
# 92行目付近
def _find_vcvarsall(plat_spec):
_, best_dir = _find_vc2017()
vcruntime = None
vcruntime_plat = 'x64' if 'amd64' in plat_spec else 'x86'
if best_dir:
vcredist = os.path.join(best_dir, "..", "..", "redist", "MSVC", "**",
"Microsoft.VC141.CRT", "vcruntime140.dll")
try:
import glob
vcruntime = glob.glob(vcredist, recursive=True)[-1]
except (ImportError, OSError, LookupError):
vcruntime = None
# ... 以下略
_find_vcvarsall
メソッド内に_find_vc2017()
なるメソッドを発見。
こいつの戻り値best_dir
さえ正しければ、vcvarsall.bat
ファイルも見つけられる気がするのだけれど...
print(best_dir)
したらNone
が入ってました。
ぷわー(/・ω・)/
ここで3時間以上経過していたため、完全に面倒くさくなり、best_dir
に直接pathを代入させることにしました...
# 92行目
def _find_vcvarsall(plat_spec):
# _, best_dir = _find_vc2017() # もともとあったコード
# INFO: from this line, cord is added ...
# tmp_path に正しいpathを投入
tmp_path = "C:/Program Files (x86)/Microsoft Visual Studio/2017/WDExpress".replace('/', os.sep)
best_dir = os.path.join(tmp_path, "VC", "Auxiliary", "Build")
print(best_dir)
# INFO: until this line, cord is added ...
vcruntime = None
vcruntime_plat = 'x64' if 'amd64' in plat_spec else 'x86'
if best_dir:
vcredist = os.path.join(best_dir, "..", "..", "redist", "MSVC", "**",
"Microsoft.VC141.CRT", "vcruntime140.dll")
try:
import glob
vcruntime = glob.glob(vcredist, recursive=True)[-1]
except (ImportError, OSError, LookupError):
vcruntime = None
# ... 以下略
この修正を行った後に再度実行したところ、めでたくCythonによるコンパイルが成功しました!!
補足事項
_msvccompiler.py
を書き換える度に、Jupyter Notebook の kernel を restart する必要があります。
そうしないと、たとえファイルを書き換えても実行結果が変わりませんでした。
参考にした記事
- WindowsでもCythonを使いたい!
-> Visual Studioが必要と判明
- 「Unable to find vcvarsall.bat」の対処法
-> PythonをコンパイルしたVC++
のバージョンが重要な意味を持つと判明
- Fix Python 3 on Windows error Microsoft Visual C++ 14.0 is required
-> python3.7にはVisual Studio 2017が必要と判明
- Installing Cython For Anaconda On Windows (※link切れ)
-> Cythonのソースを直接書き換えるという愚行を試すきっかけ
- VisualStudio2017 install 方法 (2023/10/01 現在有効)
もし、この記事がなかったら、2023年時点において VisualStudio2017 はインストールできなかった。。
惜しくも参考にできなかった記事
多分こっちのやり方が正統派なんだと思いますです...
CythonExtensionsOnWindows
私の力では、何をすればいいのかわかりませんでした(´・ω・`)