Pybind11を使ってC++の関数をPythonから呼び出せるようにする環境を構築する方法を説明します。WindowsかつVisual Studio Code(以下、VSCode)を使っている人向けの記事があまりなかったので、いろいろ調べたことをまとめておきます。
デバッグ編はこちら。
0. 環境
以下の環境で確認しています。CMake以下のインストール方法はこの記事で説明します。
- OS: Windows 10 Home 22H2
- エディター: Visual Studio Code 1.83.1
- Python: 3.11
- この記事でインストールするもの
- CMake: 3.19.4
- msvc: 2019 Release
- pybind11: 2.11.1
1. 環境構築
1.1. CMakeのインストール
CMakeとは、C++等をビルドする際の設定を様々なコンパイラーで利用できるようにするツールです。が、私自身よく分かっていないので、詳しくはこちらをみてください。
ダウンロード ページからWindows win64-x64 Installerをダウンロードし、インストールします。
また、VSCode用の拡張機能CMake ToolsもVSCodeにインストールしておきます。端末がオフラインの場合はこちらを参考にしてください。
1.2. msvcのインストール
msvcとは、Microsoft製C++コンパイラです。Visual StudioのC++コンパイラー部分です。
インストール方法は、端末がオンラインの場合はこちらを、オフラインの場合はこちらをご覧ください。
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
オフライン環境の場合は、cmake_exampleから、↓ Code ▾
(緑色) -> Download ZIP
でダウンロード、また、pybind11
フォルダーが空になっているので、pybind11からも同様にダウンロードし、中身を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)にしてください。(コンパイラーにg++を使うと日本語はダメだけど、msvcならOKみたい)
project_root
├ .vscode
│ └ settings.json
├ pybind11
├ src
│ └ main.cpp
└ CMakeLists.txt
setting.json
でPythoのバージョンを指定する。以下はPython 3.11の例。
{
"cmake.configureArgs": [
"-DPYTHON_EXECUTABLE:FILEPATH=C:/Program Files/Python311/python.exe"
]
}
コンパイル エラー(なぜかはわからない)になるため、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 3.4...3.18)
project(cmake_example)
add_subdirectory(pybind11)
pybind11_add_module(cmake_example src/main.cpp)
# EXAMPLE_VERSION_INFO is defined by setup.py and passed into the C++ code as a
# define (VERSION_INFO) here.
target_compile_definitions(cmake_example PRIVATE VERSION_INFO=${EXAMPLE_VERSION_INFO})
project_root
をVSCodeで開き、コマンド パレット(Ctrl+p
)からCMake Toolsを使ってビルドします。
-
Cmake: Select a Kit
でVisal Studio Build Tools 2019 Release - amd64
を選択 -
Cmake: Select Variant
でDebug
を選択 -
Cmake: Build
を実行
なお、上記はVSCodeのステータスバー(下部の青いバー)をクリックして設定することもできます。
成功すれば、./build/Debug
フォルダーにcmake_example.cp37-win_amd64.pyd
が作成されます。VSCodeでCtrl+@
でターミナルを開き、試してみましょう。
> python # Pythonを起動
>>> from build.Debug.cmake_example import add
>>> add(1,2)
3
>>> exit() # Powershellに戻る
add
関数を呼び出せていれば成功です。
add
関数のデバッグ方法はデバッグ編にて説明していますのでそちらもご覧ください。
3. トラブルシューティング
3.1. ConfigureとGenarate
3.1.1 Unknown CMake command "pybind11_add_module".
pybind11フォルダーが空になっていませんか?git clone
時に--recursive
オプションを付け忘れるか、zipダウンロードの場合はpybind11のダウンロード & 展開を忘れるとそのようになります。
3.1.2. cmake -G "MinGW Makefiles" ..
ができない
cmake -G "MinGW Makefiles" ..
ができないパス名に日本語が含まれるとConfigureとGenarateができません。パス名は大人しく半角英数字(スペースと記号もOK)にしましょう。日本語に対応して欲しいですね。(コンパイラーにg++を使うと日本語はダメだけど、msvcならOKみたい)
3.2. ビルド時
3.2.1. 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
この問題は公式でも議論されており、プルリクエスト後、マージされています(実際のコミット)。
3.2.2. 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]
というワーニングが大量に出ます。
4. おわりに
最後まで読んでいただき、ありがとうございます。
この記事では公式のサンプルを使っただけでしたが、他の人の記事を参考に、main.cpp
やCMakeLists.txt
を修正してみてください。
C++に疎いため、たったこれだけの事が出来るようになるまでに時間がかかりました。これからC++デビューしたいと思います。
参考
以下の記事を参考にさせていただきました。