WindowsでC++17をCythonでビルドしてPythonから使うために
Published:
はじめに
背景(ポエム)
強化学習する時に地味にリプレイバッファの遅さが気になってきて、C++で実装してしまえ!と思ってC++ -> Cython -> Pythonと呼べるようにしたのですが、Windowsでのビルドでこけまくったのでその方法を残します。
[https://twitter.com/ohtake_i/status/1092373129391816704:embed]
ちなみに Unix系(Mac OS X, Ubuntu14.04, 16.04)ではGCCを入れて容易にインストールできます。
実験環境
- Windows 10 64bit
- Anaconda 4.5.4
- python 3.6.7
- numpy 1.16.1
- cython 0.29.4
手順
MinGWのインストール
- C++17をビルドできるように最新のGCCをサポートするMinGWをインストールする
- C++17の機能とサポートするGCCバージョンの一覧はここ
- numen MinGW distribution から
mingw-16.1.exe
(2019/2現在)をダウンロードする - 解凍後、ドライブのルート(例えば
C:\
,D:\
)に置く - システムの環境変数にパスを通す(
PATH=$PATH;C:\MinGW\bin
)- ユーザの環境変数に追加するとCythonがビルドするときに
gcc
などを見つけられなくてエラーになる
- ユーザの環境変数に追加するとCythonがビルドするときに
MinGWのエラー対応
- 通常実行すると下記のようなバグが発生する
(略) c:\mingw\include\c++\8.2.0\cmath:1121:11: error: '::hypot' has not been declared using ::hypot; ^~~~~ (略)
- エラーが発生した
cmath
でusing ::hypot;
をusing ::_hypot;
に置き換える
Cythonのインストール
pip install cython >= 0.29
でCythonをインストールする0.28.x
ではエラーが発生した
MSVCライブラリのインストール
- 下記のようなエラーが発生した場合に対策する
c:/mingw/bin/../lib/gcc/x86_64-w64-mingw32/8.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: cannot find -lmsvcr140
collect2.exe: error: ld returned 1 exit status
- これは、現在使われなくなった
msvcr140.dll
を参照していることが原因となっている - そこで、
\path\to\Lib\distutils\cygwincompiler.py
を下記のように書き換えることで現在使われているDLLを呼ぶようにする- 上記
\path\to
はAnacondaの場合例えばC:\Users\username\AppData\Local\Continuum\anaconda3
- 上記
elif msc_ver == '1900':
# Visual Studio 2015 / Visual C++ 14.0
+ return ['vcruntime140']
- return ['msvcr140']
- 次に、
vcruntime140.dll
をPythonから見えるディレクトリにコピーするcp \path\to\vcruntime140.dll \path\to\libs\vcruntime140.dll
MinGWでCythonをBuildする
- デフォルトでMSVC(Microsoft Visual C++)でビルドするように設定されているので、MinGWでビルドするように変更する
distutils
のディレクトリに移動する- 例えば
cd C:\Users\username\Appdata\Local\Continuum\anaconda3\Lib\distutils
- 例えば
- distutils.cfg を作成し、下記のように設定する
[build]
compiler=mingw32
ビルドできることを確認
- 簡単な例で試そうと思いましたが、
.pyx
,.hpp
,setup.py
を準備するのが大変なので、とりあえず今友人と作っているライブラリのリンクを貼ります- [https://gitlab.com/ymd_h/cpprb:title]
- ライブラリの中では、例えば構造化束縛などのC++17の機能を使っています
auto [obs,act,rew,next_obs,done] = initialize_space(indexes.size());
- リプレイバッファからサンプルを返すためバッチサイズ分のメモリを確保しています
- 早速 Build -> Install -> Test してみましょう
git clone https://gitlab.com/ymd_h/cpprb.git
cd cpprb
python setup.py build
python setup.py install
cd test
python PyReplayBuffer.py
- 動けば環境構築完了です。ありがとうMinGW!GCC!C++17!!
まとめ
本記事ではC++17をWindowsでPythonから呼ぶための環境構築をまとめました。 ちなみにMSVCでいいじゃん!という意見もあるかと思いますが、残念ながらMSVCはC++17非対応だったり、規格に準拠していなかったりで多くの問題を引き起こします。 ClangのMS Code genはまだ試していませんが、それも今後試してみようと思います。
確認する時に使った cpprb
というライブラリはリプレイバッファを爆速にしたもので、近日中に他の記事で(私か友人が)紹介しようと思っています。
記事の中で間違っているところ、もっと良い方法があれば是非教えてください!
参考資料
- MinGWのインストール
- MinGWをデフォルトコンパイラにする
- Cythonの
hypot
でエラー