(2021年1月追記)
以下の記事ではg++を使った環境構築・ビルド方法を説明していますが、msvcを使った環境構築・ビルド方法およびデバッグ方法の記事を投稿しましたのでそちらをご覧ください。g++を使ったデバッグはブレークポイントで止められなかったのであきらめましたorz
Pybind11を使ってC++の関数をPythonから呼び出せるようにする環境を構築する方法を説明します。WindowsかつVisual Studio Codeを使っている人向けの記事があまりなかったので、いろいろ調べたことをまとめておきます。ただ、エディターはVisual Studio Codeでなくても大丈夫です。
0. 環境
以下の環境で確認しています。CMake以下のインストール方法はこの記事で説明します。
- OS: Windows 10
- エディター: Visual Studio Code
- Python: 3.7 (Anaconda 3 2019.7)
- この記事でインストールするもの
- CMake: 3.17.2
- Mingw-w64: x86_64-8.1.0-posix-seh-rt_v6-rev0
- pybind11: 2.5.0
1. 環境構築
1.1. CMakeのインストール
CMakeとは、C++等をビルドする際の設定を様々なコンパイラーで利用できるようにするツールです。が、私自身よく分かっていないので、詳しくはこちらをみてください。
ダウンロード ページからWindows win64-x64 Installerをダウンロードし、インストールします。
1.2. Mingw-w64のインストール
Mingw-w64とは、フリーのC++コンパイラg++のWindwos 64bit版です。これも私自身よく分かっていないので、グーグル先生に聞いてみてください。
ダウンロードページからインストーラー等をダウンロードします。オンライン環境であれば、インストーラーMinGW-W64-install.exe
をダウンロードしインストールします。オフライン環境であれば、7z形式のファイルをダウンロードして展開します。
以下、この記事ではg++.exe
の配置が次のようになっているとします:D:\UserProgram\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin\g++.exe
次に、上記フォルダーを環境変数Pathに追加します。Powershellで追加するには、
> $envPath = [System.Environment]::GetEnvironmentVariable("Path", "User")
> $envPath += ";D:\UserProgram\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin" #←g++.exeが含まれているパス
> [System.Environment]::SetEnvironmentVariable("Path", $envPath, "User")
端末単位で設定するには1行目と3行目の"User"
を"Macine"
に置き換えます。この場合、管理者権限が必要になります。
> $envPath = [System.Environment]::GetEnvironmentVariable("Path", "Machine")
> $envPath += ";D:\UserProgram\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin" #←g++.exeが含まれているパス
> [System.Environment]::SetEnvironmentVariable("Path", $envPath, "Machine")
1.3. Pybind11のインストール
オンライン環境なら、pip
でインストールします。
> pip install pybind11
オフライン環境の場合は、
PyPIのダウンロード ページからpybind11-x.y.z-py2.py3-none-any.wh
(x, y, zは数字)をダウンロードしてから、pip
でインストールします。
> pip install ダウンロード先/pybind11-2.5.0-py2.py3-none-any.whl #2.5.0部分は適宜読み替え
後で使うので、公式のサンプルもダウンロードします。オンライン環境(かつGitをインストール済み)なら、Powershell上でダウンロードしたい場所まで移動し、
git clone --recursive https://github.com/pybind/cmake_example.git
としてダウンロードします。オフライン環境の場合は、公式のサンプルのClone or download
ボタンを押します。また、pybind11フォルダーも同様にダウンロードします。
**【重要】(2021/1修正。現時点ではワーニングが出ないため削除。)cmake_example/pybind11/include/pybind11
以下のファイルを、C:\ProgramData\Anaconda3\include\pybind11
以下のファイルで置き換えます。**置き換える前のファイルは古いみたいで、コンパイルは通りますが、warning: 'void PyThread_delete_key_value(int)' is deprecated [-Wdeprecated-declarations]
というワーニングが大量に出ます。
2. やってみるさ( ■ 一 ■)
先ほどダウンロードしたcmake_exmple
フォルダーから、pybind11
、src
、CMakeLists.txt
を適当なフォルダー(以下、project_root
とします)にコピーします。なお、パス名に日本語が含まれるとConfigureとGenarateができないため、半角英数字(スペースと記号もOK)にしてください。
project_root
├ pybind11
│ ├ docs
│ ├ include
│ │ └pybind11
│ │ └・・・
│ └・・・
├ src
│ └main.cpp
└ CMakeLists.txt
コンパイル エラー(なぜかはわからない)になるため、main.cpp
の#ifdef VERSION_INFO
~#endif
部分をコメントアウトor削除。
# include <pybind11/pybind11.h>
int add(int i, int j) {
return i + j;
}
namespace py = pybind11;
PYBIND11_MODULE(cmake_example, m) {
(略)
m.def("add", &add, R"pbdoc(
Add two numbers
Some other explanation about the add function.
)pbdoc");
(略)
//コンパイルエラー(なぜかはわからない)になるので以下をコメントアウトor削除
//#ifdef VERSION_INFO
// m.attr("__version__") = MACRO_STRINGIFY(VERSION_INFO);
//#else
// m.attr("__version__") = "dev";
//#endif
}
cmake_minimum_required(VERSION 2.8.12)
project(cmake_example)
add_subdirectory(pybind11)
pybind11_add_module(cmake_example src/main.cpp)
project_root
をVisual Studio Codeで開き、Ctrl+@
でターミナルに移動し、以下を実行します。
> mkdir build # ビルド先のフォルダーを作成
> cd build # ビルド先に移動
> cmake -G "MinGW Makefiles" .. # ConfigureとGenarate
> cmake --build . # ビルド
成功すれば、build
フォルダーにcmake_example.cp37-win_amd64.pyd
が作成されます。先ほどのターミナルで試してみましょう。
> python # Pythonを起動
>>> from cmake_example import add
>>> add(1,2)
3
>>> exit() # Powershellに戻る
add
関数を呼び出せていれば成功です。
3. トラブルシューティング
3.1. ConfigureとGenarate
3.1.1. cmake -G "MinGW Makefiles" ..
ができない
パス名に日本語が含まれるとConfigureとGenarateができません。パス名は大人しく半角英数字(スペースと記号もOK)にしましょう。日本語に対応して欲しいですね。
3.2. ビルド時
3.2.1. warning: 'void PyThread_delete_key_value(int)' is deprecated [-Wdeprecated-declarations]
上で書きましたが、(2021/1修正。現時点ではワーニングが出ないため削除。)cmake_example/pybind11/include/pybind11
以下のファイルを、C:\ProgramData\Anaconda3\include\pybind11
以下のファイルで置き換えます。置き換える前のファイルは古いみたいで、コンパイルは通りますが、warning: 'void PyThread_delete_key_value(int)' is deprecated [-Wdeprecated-declarations]
というワーニングが大量に出ます。
3.2.2. error: '::hypot' has not been declared
2018年12月以前にリリースされたPythonの各バージョンを使っていると、このエラーでビルドが失敗します。原因はpyconfig.hで、次のように修正します。
#define COMPILER "[gcc]"
- #define hypot _hypot ←この行を削除する。
#define PY_LONG_LONG long long
#define PY_LLONG_MIN LLONG_MIN
#define PY_LLONG_MAX LLONG_MAX
この問題は公式でも議論されており、プルリクエスト後、マージされています(実際のコミット)。
4. おわりに
最後まで読んでいただき、ありがとうございます。
この記事では公式のサンプルを使っただけでしたが、他の人の記事を参考に、main.cpp
やCMakeLists.txt
を修正してみてください。
C++に疎いため、たったこれだけの事が出来るようになるまでに時間がかかりました。これからC++デビューしたいと思います。あと、VSCodeの拡張機能CMake Toolsの使い方もそのうち調べて記事にしたいです。
参考
以下の記事を参考にさせていただきました。