WindowsでC++17をCythonでビルドしてPythonから使うために

1 minute read

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 などを見つけられなくてエラーになる

MinGWのエラー対応

  • 通常実行すると下記のようなバグが発生する
    ()
    c:\mingw\include\c++\8.2.0\cmath:1121:11: error: '::hypot' has not been declared
     using ::hypot;
             ^~~~~
    ()
    
  • エラーが発生した cmathusing ::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 というライブラリはリプレイバッファを爆速にしたもので、近日中に他の記事で(私か友人が)紹介しようと思っています。

記事の中で間違っているところ、もっと良い方法があれば是非教えてください!

参考資料